Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 17 additions & 1 deletion clang/include/clang/CIR/Dialect/IR/CIRTBAAAttrs.td
Original file line number Diff line number Diff line change
Expand Up @@ -22,22 +22,38 @@ def CIR_TBAAOmnipotentChar
def CIR_TBAAScalarAttr : CIR_Attr<"TBAAScalar", "tbaa_scalar", [], "TBAAAttr"> {
let summary = "Describes a scalar type in TBAA with an identifier.";

let parameters = (ins StringRefParameter<> : $id, CIR_AnyType : $type);
let parameters = (ins StringRefParameter<>:$id,
CIR_AnyType:$type,
OptionalParameter<"cir::TBAAScalarAttr">:$parent);

let description = [{
Define a TBAA scalar attribute.
The optional `parent` attribute is used to describe the parent type of the
scalar type. If the `parent` is null or omitted, the parent type is the
`omnipotent char` type.

Example:
```mlir
// CIR_TBAAScalarAttr
#tbaa_scalar = #cir.tbaa_scalar<id = "int", type = !s32i>
#tbaa_scalar1 = #cir.tbaa_scalar<id = "long long", type = !s64i>

#tbaa_scalar2 = #cir.tbaa_scalar<id = "any pointer", type = !cir.ptr<!s32i>>
#tbaa_scalar3 = #cir.tbaa_scalar<id = "p1 int", type = !cir.ptr<!s32i>,
parent = #tbaa_scalar2>
```

See the following link for more details:
https://llvm.org/docs/LangRef.html#tbaa-metadata
}];

let builders = [
AttrBuilder<(ins "llvm::StringRef":$id,
"mlir::Type":$type), [{
return $_get($_ctxt, id, type, /*parent =*/ nullptr);
}]>
];

let assemblyFormat = "`<` struct(params) `>`";
}

Expand Down
1 change: 0 additions & 1 deletion clang/include/clang/CIR/MissingFeatures.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,6 @@ struct MissingFeatures {
static bool tbaaMergeTBAAInfo() { return false; }
static bool tbaaMayAlias() { return false; }
static bool tbaaNewStructPath() { return false; }
static bool tbaaPointer() { return false; }
static bool emitNullabilityCheck() { return false; }
static bool ptrAuth() { return false; }
static bool memberFuncPtrAuthInfo() { return false; }
Expand Down
78 changes: 72 additions & 6 deletions clang/lib/CIR/CodeGen/CIRGenTBAA.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ static bool isValidBaseType(clang::QualType qty) {
return false;
}

cir::TBAAAttr CIRGenTBAA::getScalarTypeInfo(clang::QualType qty) {
cir::TBAAScalarAttr CIRGenTBAA::getScalarTypeInfo(clang::QualType qty) {
const clang::Type *ty = astContext.getCanonicalType(qty).getTypePtr();
assert(mlir::isa<clang::BuiltinType>(ty));
const clang::BuiltinType *bty = mlir::dyn_cast<BuiltinType>(ty);
Expand Down Expand Up @@ -159,12 +159,78 @@ cir::TBAAAttr CIRGenTBAA::getTypeInfoHelper(clang::QualType qty) {
// they involve a significant representation difference. We don't
// currently do so, however.
if (ty->isPointerType() || ty->isReferenceType()) {
if (!codeGenOpts.PointerTBAA) {
return cir::TBAAScalarAttr::get(mlirContext, "any pointer",
types.convertType(qty));
auto anyPtr = cir::TBAAScalarAttr::get(mlirContext, "any pointer",
types.convertType(qty));
if (!codeGenOpts.PointerTBAA)
return anyPtr;
// C++ [basic.lval]p11 permits objects to accessed through an l-value of
// similar type. Two types are similar under C++ [conv.qual]p2 if the
// decomposition of the types into pointers, member pointers, and arrays has
// the same structure when ignoring cv-qualifiers at each level of the
// decomposition. Meanwhile, C makes T(*)[] and T(*)[N] compatible, which
// would really complicate any attempt to distinguish pointers to arrays by
// their bounds. It's simpler, and much easier to explain to users, to
// simply treat all pointers to arrays as pointers to their element type for
// aliasing purposes. So when creating a TBAA tag for a pointer type, we
// recursively ignore both qualifiers and array types when decomposing the
// pointee type. The only meaningful remaining structure is the number of
// pointer types we encountered along the way, so we just produce the tag
// "p<depth> <base type tag>". If we do find a member pointer type, for now
// we just conservatively bail out with AnyPtr (below) rather than trying to
// create a tag that honors the similar-type rules while still
// distinguishing different kinds of member pointer.
unsigned ptrDepth = 0;
do {
ptrDepth++;
ty = ty->getPointeeType()->getBaseElementTypeUnsafe();
} while (ty->isPointerType());
assert(!isa<VariableArrayType>(ty));
// When the underlying type is a builtin type, we compute the pointee type
// string recursively, which is implicitly more forgiving than the standards
// require. Effectively, we are turning the question "are these types
// compatible/similar" into "are accesses to these types allowed to alias".
// In both C and C++, the latter question has special carve-outs for
// signedness mismatches that only apply at the top level. As a result, we
// are allowing e.g. `int *` l-values to access `unsigned *` objects.
SmallString<256> tyName;

if (isa<BuiltinType>(ty)) {
auto scalarAttr = getScalarTypeInfo(ty->getCanonicalTypeInternal());
tyName = scalarAttr.getId();
} else {
// Be conservative if the type isn't a RecordType. We are specifically
// required to do this for member pointers until we implement the
// similar-types rule.
const auto *rt = ty->getAs<RecordType>();
if (!rt)
return anyPtr;

// For unnamed structs or unions C's compatible types rule applies. Two
// compatible types in different compilation units can have different
// mangled names, meaning the metadata emitted below would incorrectly
// mark them as no-alias. Use AnyPtr for such types in both C and C++, as
// C and C++ types may be visible when doing LTO.
//
// Note that using AnyPtr is overly conservative. We could summarize the
// members of the type, as per the C compatibility rule in the future.
// This also covers anonymous structs and unions, which have a different
// compatibility rule, but it doesn't matter because you can never have a
// pointer to an anonymous struct or union.
if (!rt->getDecl()->getDeclName())
return anyPtr;

// For non-builtin types use the mangled name of the canonical type.
llvm::raw_svector_ostream tyOut(tyName);
types.getCXXABI().getMangleContext().mangleCanonicalTypeName(
QualType(ty, 0), tyOut);
}
assert(!cir::MissingFeatures::tbaaPointer());
return tbaa_NYI(mlirContext);

SmallString<256> outName("p");
outName += std::to_string(ptrDepth);
outName += " ";
outName += tyName;
return cir::TBAAScalarAttr::get(mlirContext, outName,
types.convertType(qty), anyPtr);
}
// Accesses to arrays are accesses to objects of their element types.
if (codeGenOpts.NewStructPathTBAA && ty->isArrayType()) {
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/CIR/CodeGen/CIRGenTBAA.h
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ class CIRGenTBAA {
// An internal helper function to generate metadata used
// to describe accesses to objects of the given type.
cir::TBAAAttr getTypeInfoHelper(clang::QualType qty);
cir::TBAAAttr getScalarTypeInfo(clang::QualType qty);
cir::TBAAScalarAttr getScalarTypeInfo(clang::QualType qty);

cir::TBAAAttr getValidBaseTypeInfo(clang::QualType qty);
cir::TBAAAttr getBaseTypeInfoHelper(const clang::Type *ty);
Expand Down
6 changes: 5 additions & 1 deletion clang/lib/CIR/Lowering/DirectToLLVM/LowerTBAAToLLVM.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,11 @@ class CIRToLLVMTBAAAttrLowering {
if (auto scalarAttr = mlir::dyn_cast<cir::TBAAScalarAttr>(tbaa)) {
mlir::DataLayout layout;
auto size = layout.getTypeSize(scalarAttr.getType());
return createScalarTypeNode(scalarAttr.getId(), getChar(), size);
mlir::LLVM::TBAANodeAttr parent =
scalarAttr.getParent()
? lowerCIRTBAAAttrToLLVMTBAAAttr(scalarAttr.getParent())
: getChar();
return createScalarTypeNode(scalarAttr.getId(), parent, size);
}
if (auto structAttr = mlir::dyn_cast<cir::TBAAStructAttr>(tbaa)) {
llvm::SmallVector<mlir::LLVM::TBAAMemberAttr, 4> members;
Expand Down
15 changes: 7 additions & 8 deletions clang/test/CIR/CodeGen/tbaa-enum.c
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
// This is inspired from clang/test/CodeGen/tbaa.c, with both CIR and LLVM checks.
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir -O1
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir -O1 -no-pointer-tbaa
// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t.ll -O1 -disable-llvm-passes
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t.ll -O1 -disable-llvm-passes -no-pointer-tbaa
// RUN: FileCheck --check-prefix=LLVM --input-file=%t.ll %s
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t.ll -O1 -disable-llvm-passes -relaxed-aliasing
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t.ll -O1 -disable-llvm-passes -relaxed-aliasing -no-pointer-tbaa
// RUN: FileCheck --check-prefix=NO-TBAA --input-file=%t.ll %s
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t.ll -O0 -disable-llvm-passes
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t.ll -O0 -disable-llvm-passes -no-pointer-tbaa
// RUN: FileCheck --check-prefix=NO-TBAA --input-file=%t.ll %s

// NO-TBAA-NOT: !tbaa

// CIR: #tbaa[[NYI:.*]] = #cir.tbaa
// CIR: #tbaa[[CHAR:.*]] = #cir.tbaa_omnipotent_char
// CIR: #tbaa[[INT:.*]] = #cir.tbaa_scalar<id = "int", type = !s32i>
// CIR: #tbaa[[LONG_LONG:.*]] = #cir.tbaa_scalar<id = "long long", type = !s64i>
Expand Down Expand Up @@ -136,10 +135,10 @@ uint8_t g3(Enum8 *E, uint8_t *val) {
return *val;
}

// LLVM: [[TAG_i32]] = !{[[TYPE_i32:!.*]], [[TYPE_i32]], i64 0}
// LLVM: [[TYPE_i32]] = !{!"int", [[TYPE_char:!.*]],
// LLVM: [[TYPE_char]] = !{!"omnipotent char", [[TAG_c_tbaa:!.*]],
// LLVM: [[TYPE_char:!.*]] = !{!"omnipotent char", [[TAG_c_tbaa:!.*]],
// LLVM: [[TAG_c_tbaa]] = !{!"Simple C/C++ TBAA"}
// LLVM: [[TAG_i32]] = !{[[TYPE_i32:!.*]], [[TYPE_i32]], i64 0}
// LLVM: [[TYPE_i32]] = !{!"int", [[TYPE_char]],
// LLVM: [[TAG_i64]] = !{[[TYPE_i64:!.*]], [[TYPE_i64]], i64 0}
// LLVM: [[TYPE_i64]] = !{!"long long", [[TYPE_char]],
// LLVM: [[TAG_long]] = !{[[TYPE_long:!.*]], [[TYPE_long]], i64 0}
Expand Down
15 changes: 7 additions & 8 deletions clang/test/CIR/CodeGen/tbaa-enum.cpp
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
// This is inspired from clang/test/CodeGen/tbaa.c, with both CIR and LLVM checks.
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir -O1
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir -O1 -no-pointer-tbaa
// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t.ll -O1 -disable-llvm-passes
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t.ll -O1 -disable-llvm-passes -no-pointer-tbaa
// RUN: FileCheck --check-prefix=LLVM --input-file=%t.ll %s
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t.ll -O1 -disable-llvm-passes -relaxed-aliasing
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t.ll -O1 -disable-llvm-passes -relaxed-aliasing -no-pointer-tbaa
// RUN: FileCheck --check-prefix=NO-TBAA --input-file=%t.ll %s
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t.ll -O0 -disable-llvm-passes
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t.ll -O0 -disable-llvm-passes -no-pointer-tbaa
// RUN: FileCheck --check-prefix=NO-TBAA --input-file=%t.ll %s

// NO-TBAA-NOT: !tbaa

// CIR: #tbaa[[NYI:.*]] = #cir.tbaa
// CIR: #tbaa[[CHAR:.*]] = #cir.tbaa_omnipotent_char
// CIR: #tbaa[[INT:.*]] = #cir.tbaa_scalar<id = "int", type = !s32i>
// CIR: #tbaa[[EnumAuto32:.*]] = #cir.tbaa_scalar<id = "_ZTS10EnumAuto32", type = !u32i>
Expand Down Expand Up @@ -139,10 +138,10 @@ uint8_t g3(Enum8 *E, uint8_t *val) {
return *val;
}

// LLVM: [[TAG_i32]] = !{[[TYPE_i32:!.*]], [[TYPE_i32]], i64 0}
// LLVM: [[TYPE_i32]] = !{!"int", [[TYPE_char:!.*]],
// LLVM: [[TYPE_char]] = !{!"omnipotent char", [[TAG_c_tbaa:!.*]],
// LLVM: [[TYPE_char:!.*]] = !{!"omnipotent char", [[TAG_c_tbaa:!.*]],
// LLVM: [[TAG_c_tbaa]] = !{!"Simple C++ TBAA"}
// LLVM: [[TAG_i32]] = !{[[TYPE_i32:!.*]], [[TYPE_i32]], i64 0}
// LLVM: [[TYPE_i32]] = !{!"int", [[TYPE_char]],
// LLVM: [[TAG_EnumAuto32]] = !{[[TYPE_EnumAuto32:!.*]], [[TYPE_EnumAuto32]], i64 0}
// LLVM: [[TYPE_EnumAuto32]] = !{!"_ZTS10EnumAuto32", [[TYPE_char]],
// LLVM: [[TAG_i64]] = !{[[TYPE_i64:!.*]], [[TYPE_i64]], i64 0}
Expand Down
Loading
Loading