Skip to content

Commit

Permalink
Merged main:202de4a5c6ed into amd-gfx:63f08b5fd01a
Browse files Browse the repository at this point in the history
Local branch amd-gfx 63f08b5 Merged main:d40413013425 into amd-gfx:85fdb0385e9e
Remote branch main 202de4a Fix __builtin_vectorelements tests with REQUIRES (llvm#69582)
  • Loading branch information
SC llvm team authored and SC llvm team committed Oct 19, 2023
2 parents 63f08b5 + 202de4a commit 3573343
Show file tree
Hide file tree
Showing 25 changed files with 726 additions and 124 deletions.
10 changes: 5 additions & 5 deletions clang/include/clang/Analysis/FlowSensitive/Arena.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@ namespace clang::dataflow {
/// For example, `Value`, `StorageLocation`, `Atom`, and `Formula`.
class Arena {
public:
Arena() : True(makeAtom()), False(makeAtom()) {}
Arena()
: True(Formula::create(Alloc, Formula::Literal, {}, 1)),
False(Formula::create(Alloc, Formula::Literal, {}, 0)) {}
Arena(const Arena &) = delete;
Arena &operator=(const Arena &) = delete;

Expand Down Expand Up @@ -106,9 +108,7 @@ class Arena {
const Formula &makeAtomRef(Atom A);

/// Returns a formula for a literal true/false.
const Formula &makeLiteral(bool Value) {
return makeAtomRef(Value ? True : False);
}
const Formula &makeLiteral(bool Value) { return Value ? True : False; }

// Parses a formula from its textual representation.
// This may refer to atoms that were not produced by makeAtom() yet!
Expand Down Expand Up @@ -144,7 +144,7 @@ class Arena {
llvm::DenseMap<const Formula *, BoolValue *> FormulaValues;
unsigned NextAtom = 0;

Atom True, False;
const Formula &True, &False;
};

} // namespace clang::dataflow
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -473,9 +473,8 @@ class Environment {

/// Returns a symbolic boolean value that models a boolean literal equal to
/// `Value`
AtomicBoolValue &getBoolLiteralValue(bool Value) const {
return cast<AtomicBoolValue>(
arena().makeBoolValue(arena().makeLiteral(Value)));
BoolValue &getBoolLiteralValue(bool Value) const {
return arena().makeBoolValue(arena().makeLiteral(Value));
}

/// Returns an atomic boolean value.
Expand Down
15 changes: 11 additions & 4 deletions clang/include/clang/Analysis/FlowSensitive/Formula.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,8 @@ class alignas(const Formula *) Formula {
/// A reference to an atomic boolean variable.
/// We name these e.g. "V3", where 3 == atom identity == Value.
AtomRef,
// FIXME: add const true/false rather than modeling them as variables
/// Constant true or false.
Literal,

Not, /// True if its only operand is false

Expand All @@ -69,6 +70,11 @@ class alignas(const Formula *) Formula {
return static_cast<Atom>(Value);
}

bool literal() const {
assert(kind() == Literal);
return static_cast<bool>(Value);
}

ArrayRef<const Formula *> operands() const {
return ArrayRef(reinterpret_cast<Formula *const *>(this + 1),
numOperands(kind()));
Expand All @@ -81,9 +87,9 @@ class alignas(const Formula *) Formula {
void print(llvm::raw_ostream &OS, const AtomNames * = nullptr) const;

// Allocate Formulas using Arena rather than calling this function directly.
static Formula &create(llvm::BumpPtrAllocator &Alloc, Kind K,
ArrayRef<const Formula *> Operands,
unsigned Value = 0);
static const Formula &create(llvm::BumpPtrAllocator &Alloc, Kind K,
ArrayRef<const Formula *> Operands,
unsigned Value = 0);

private:
Formula() = default;
Expand All @@ -93,6 +99,7 @@ class alignas(const Formula *) Formula {
static unsigned numOperands(Kind K) {
switch (K) {
case AtomRef:
case Literal:
return 0;
case Not:
return 1;
Expand Down
100 changes: 60 additions & 40 deletions clang/lib/Analysis/FlowSensitive/Arena.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,63 +22,83 @@ canonicalFormulaPair(const Formula &LHS, const Formula &RHS) {
return Res;
}

const Formula &Arena::makeAtomRef(Atom A) {
auto [It, Inserted] = AtomRefs.try_emplace(A);
template <class Key, class ComputeFunc>
const Formula &cached(llvm::DenseMap<Key, const Formula *> &Cache, Key K,
ComputeFunc &&Compute) {
auto [It, Inserted] = Cache.try_emplace(std::forward<Key>(K));
if (Inserted)
It->second =
&Formula::create(Alloc, Formula::AtomRef, {}, static_cast<unsigned>(A));
It->second = Compute();
return *It->second;
}

const Formula &Arena::makeAnd(const Formula &LHS, const Formula &RHS) {
if (&LHS == &RHS)
return LHS;
const Formula &Arena::makeAtomRef(Atom A) {
return cached(AtomRefs, A, [&] {
return &Formula::create(Alloc, Formula::AtomRef, {},
static_cast<unsigned>(A));
});
}

auto [It, Inserted] =
Ands.try_emplace(canonicalFormulaPair(LHS, RHS), nullptr);
if (Inserted)
It->second = &Formula::create(Alloc, Formula::And, {&LHS, &RHS});
return *It->second;
const Formula &Arena::makeAnd(const Formula &LHS, const Formula &RHS) {
return cached(Ands, canonicalFormulaPair(LHS, RHS), [&] {
if (&LHS == &RHS)
return &LHS;
if (LHS.kind() == Formula::Literal)
return LHS.literal() ? &RHS : &LHS;
if (RHS.kind() == Formula::Literal)
return RHS.literal() ? &LHS : &RHS;

return &Formula::create(Alloc, Formula::And, {&LHS, &RHS});
});
}

const Formula &Arena::makeOr(const Formula &LHS, const Formula &RHS) {
if (&LHS == &RHS)
return LHS;

auto [It, Inserted] =
Ors.try_emplace(canonicalFormulaPair(LHS, RHS), nullptr);
if (Inserted)
It->second = &Formula::create(Alloc, Formula::Or, {&LHS, &RHS});
return *It->second;
return cached(Ors, canonicalFormulaPair(LHS, RHS), [&] {
if (&LHS == &RHS)
return &LHS;
if (LHS.kind() == Formula::Literal)
return LHS.literal() ? &LHS : &RHS;
if (RHS.kind() == Formula::Literal)
return RHS.literal() ? &RHS : &LHS;

return &Formula::create(Alloc, Formula::Or, {&LHS, &RHS});
});
}

const Formula &Arena::makeNot(const Formula &Val) {
auto [It, Inserted] = Nots.try_emplace(&Val, nullptr);
if (Inserted)
It->second = &Formula::create(Alloc, Formula::Not, {&Val});
return *It->second;
return cached(Nots, &Val, [&] {
if (Val.kind() == Formula::Not)
return Val.operands()[0];
if (Val.kind() == Formula::Literal)
return &makeLiteral(!Val.literal());

return &Formula::create(Alloc, Formula::Not, {&Val});
});
}

const Formula &Arena::makeImplies(const Formula &LHS, const Formula &RHS) {
if (&LHS == &RHS)
return makeLiteral(true);

auto [It, Inserted] =
Implies.try_emplace(std::make_pair(&LHS, &RHS), nullptr);
if (Inserted)
It->second = &Formula::create(Alloc, Formula::Implies, {&LHS, &RHS});
return *It->second;
return cached(Implies, std::make_pair(&LHS, &RHS), [&] {
if (&LHS == &RHS)
return &makeLiteral(true);
if (LHS.kind() == Formula::Literal)
return LHS.literal() ? &RHS : &makeLiteral(true);
if (RHS.kind() == Formula::Literal)
return RHS.literal() ? &RHS : &makeNot(LHS);

return &Formula::create(Alloc, Formula::Implies, {&LHS, &RHS});
});
}

const Formula &Arena::makeEquals(const Formula &LHS, const Formula &RHS) {
if (&LHS == &RHS)
return makeLiteral(true);

auto [It, Inserted] =
Equals.try_emplace(canonicalFormulaPair(LHS, RHS), nullptr);
if (Inserted)
It->second = &Formula::create(Alloc, Formula::Equal, {&LHS, &RHS});
return *It->second;
return cached(Equals, canonicalFormulaPair(LHS, RHS), [&] {
if (&LHS == &RHS)
return &makeLiteral(true);
if (LHS.kind() == Formula::Literal)
return LHS.literal() ? &RHS : &makeNot(RHS);
if (RHS.kind() == Formula::Literal)
return RHS.literal() ? &LHS : &makeNot(LHS);

return &Formula::create(Alloc, Formula::Equal, {&LHS, &RHS});
});
}

IntegerValue &Arena::makeIntLiteral(llvm::APInt Value) {
Expand Down
9 changes: 1 addition & 8 deletions clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -141,8 +141,6 @@ DataflowAnalysisContext::joinFlowConditions(Atom FirstToken,

Solver::Result DataflowAnalysisContext::querySolver(
llvm::SetVector<const Formula *> Constraints) {
Constraints.insert(&arena().makeLiteral(true));
Constraints.insert(&arena().makeNot(arena().makeLiteral(false)));
return S->solve(Constraints.getArrayRef());
}

Expand Down Expand Up @@ -213,13 +211,8 @@ void DataflowAnalysisContext::dumpFlowCondition(Atom Token,
Constraints.insert(&arena().makeAtomRef(Token));
addTransitiveFlowConditionConstraints(Token, Constraints);

// TODO: have formulas know about true/false directly instead
Atom True = arena().makeLiteral(true).getAtom();
Atom False = arena().makeLiteral(false).getAtom();
Formula::AtomNames Names = {{False, "false"}, {True, "true"}};

for (const auto *Constraint : Constraints) {
Constraint->print(OS, &Names);
Constraint->print(OS);
OS << "\n";
}
}
Expand Down
17 changes: 14 additions & 3 deletions clang/lib/Analysis/FlowSensitive/Formula.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,9 @@

namespace clang::dataflow {

Formula &Formula::create(llvm::BumpPtrAllocator &Alloc, Kind K,
ArrayRef<const Formula *> Operands, unsigned Value) {
const Formula &Formula::create(llvm::BumpPtrAllocator &Alloc, Kind K,
ArrayRef<const Formula *> Operands,
unsigned Value) {
assert(Operands.size() == numOperands(K));
if (Value != 0) // Currently, formulas have values or operands, not both.
assert(numOperands(K) == 0);
Expand All @@ -38,6 +39,7 @@ Formula &Formula::create(llvm::BumpPtrAllocator &Alloc, Kind K,
static llvm::StringLiteral sigil(Formula::Kind K) {
switch (K) {
case Formula::AtomRef:
case Formula::Literal:
return "";
case Formula::Not:
return "!";
Expand All @@ -62,7 +64,16 @@ void Formula::print(llvm::raw_ostream &OS, const AtomNames *Names) const {

switch (numOperands(kind())) {
case 0:
OS << getAtom();
switch (kind()) {
case AtomRef:
OS << getAtom();
break;
case Literal:
OS << (literal() ? "true" : "false");
break;
default:
llvm_unreachable("unhandled formula kind");
}
break;
case 1:
OS << sigil(kind());
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/Analysis/FlowSensitive/WatchedLiteralsSolver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,9 @@ CNFFormula buildCNF(const llvm::ArrayRef<const Formula *> &Vals) {
switch (Val->kind()) {
case Formula::AtomRef:
break;
case Formula::Literal:
CNF.addClause(Val->literal() ? posLit(Var) : negLit(Var));
break;
case Formula::And: {
const Variable LHS = GetVar(Val->operands()[0]);
const Variable RHS = GetVar(Val->operands()[1]);
Expand Down
23 changes: 23 additions & 0 deletions clang/test/AST/Interp/bitfields.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -Wno-bitfield-constant-conversion -verify %s
// RUN: %clang_cc1 -verify=ref -Wno-bitfield-constant-conversion %s
// RUN: %clang_cc1 -std=c++20 -fexperimental-new-constant-interpreter -Wno-bitfield-constant-conversion -verify %s
// RUN: %clang_cc1 -std=c++20 -verify=ref -Wno-bitfield-constant-conversion %s

// expected-no-diagnostics
// ref-no-diagnostics
Expand Down Expand Up @@ -31,6 +33,27 @@ namespace Basic {
return a.a = 10;
}
static_assert(storeA2() == 2, "");

#if __cplusplus >= 202002
struct Init1 {
unsigned a : 2 = 1;
};
constexpr Init1 I1{};
static_assert(I1.a == 1, "");

struct Init2 {
unsigned a : 2 = 100;
};
constexpr Init2 I2{};
static_assert(I2.a == 0, "");
#endif

struct Init3 {
unsigned a : 2;
constexpr Init3() : a(100) {}
};
constexpr Init3 I3{};
static_assert(I3.a == 0, "");
}

namespace Overflow {
Expand Down
20 changes: 13 additions & 7 deletions clang/test/CodeGen/builtin_vectorelements.c
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
// RUN: %clang_cc1 -O1 -triple aarch64 -target-feature +neon %s -emit-llvm -disable-llvm-passes -o - | FileCheck --check-prefixes=CHECK,NEON %s
// RUN: %clang_cc1 -O1 -triple aarch64 -target-feature +sve %s -emit-llvm -disable-llvm-passes -o - | FileCheck --check-prefixes=CHECK,SVE %s
// RUN: %clang_cc1 -O1 -triple riscv64 -target-feature +v %s -emit-llvm -disable-llvm-passes -o - | FileCheck --check-prefixes=CHECK,RISCV %s
// RUN: %clang_cc1 -O1 -triple x86_64 %s -emit-llvm -disable-llvm-passes -o - | FileCheck --check-prefixes=CHECK %s

// Note that this does not make sense to check for x86 SIMD types, because
// __m128i, __m256i, and __m512i do not specify the element type. There are no
// "logical" number of elements in them.
// REQUIRES: target=aarch64-{{.*}}
// RUN: %clang_cc1 -O1 -triple aarch64 -target-feature +neon %s -emit-llvm -disable-llvm-passes -o - | FileCheck --check-prefixes=CHECK,NEON %s

// REQUIRES: target=aarch64-{{.*}}
// RUN: %clang_cc1 -O1 -triple aarch64 -target-feature +sve %s -emit-llvm -disable-llvm-passes -o - | FileCheck --check-prefixes=CHECK,SVE %s

// REQUIRES: target=riscv64{{.*}}
// RUN: %clang_cc1 -O1 -triple riscv64 -target-feature +v %s -emit-llvm -disable-llvm-passes -o - | FileCheck --check-prefixes=CHECK,RISCV %s

/// Note that this does not make sense to check for x86 SIMD types, because
/// __m128i, __m256i, and __m512i do not specify the element type. There are no
/// "logical" number of elements in them.

typedef int int1 __attribute__((vector_size(4)));
typedef int int4 __attribute__((vector_size(16)));
Expand Down Expand Up @@ -56,7 +63,6 @@ int test_builtin_vectorelements_multiply_constant() {
return __builtin_vectorelements(int16) * 2;
}


#if defined(__ARM_NEON)
#include <arm_neon.h>

Expand Down
3 changes: 3 additions & 0 deletions clang/test/SemaCXX/builtin_vectorelements.cpp
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
// RUN: %clang_cc1 -triple x86_64 -std=c++20 -fsyntax-only -verify -disable-llvm-passes %s

// REQUIRES: target=aarch64-{{.*}}
// RUN: %clang_cc1 -triple aarch64 -target-feature +sve -std=c++20 -fsyntax-only -verify -disable-llvm-passes %s

template <typename T>
Expand Down
Loading

0 comments on commit 3573343

Please sign in to comment.