Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[CIR][CIRGen][TBAA][NFC] Skeleton for union, enum and bitint #1250

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
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
2 changes: 2 additions & 0 deletions clang/include/clang/CIR/MissingFeatures.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ struct MissingFeatures {
static bool tbaa() { return false; }
static bool tbaaStruct() { return false; }
static bool tbaaTagForStruct() { return false; }
static bool tbaaTagForEnum() { return false; }
static bool tbaaTagForBitInt() { return false; }
static bool tbaaVTablePtr() { return false; }
static bool tbaaIncompleteType() { return false; }
static bool tbaaMergeTBAAInfo() { return false; }
Expand Down
55 changes: 54 additions & 1 deletion clang/lib/CIR/CodeGen/CIRGenTBAA.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include "mlir/Interfaces/DataLayoutInterfaces.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/RecordLayout.h"
#include "clang/AST/Type.h"
#include "clang/CIR/Dialect/IR/CIRTypes.h"
#include "clang/CIR/MissingFeatures.h"
#include "llvm/Support/ErrorHandling.h"
Expand Down Expand Up @@ -61,6 +62,58 @@ static bool isValidBaseType(clang::QualType qty) {
return false;
}

cir::TBAAAttr CIRGenTBAA::getTypeInfoHelper(clang::QualType qty) {
const clang::Type *ty = astContext.getCanonicalType(qty).getTypePtr();
// Handle builtin types.
if (mlir::isa<BuiltinType>(ty)) {
return cir::TBAAScalarAttr::get(mlirContext, types.ConvertType(qty));
}
// C++1z [basic.lval]p10: "If a program attempts to access the stored value of
// an object through a glvalue of other than one of the following types the
// behavior is undefined: [...] a char, unsigned char, or std::byte type."
if (ty->isStdByteType())
return getChar();

// Handle pointers and references.
//
// C has a very strict rule for pointer aliasing. C23 6.7.6.1p2:
// For two pointer types to be compatible, both shall be identically
// qualified and both shall be pointers to compatible types.
//
// This rule is impractically strict; we want to at least ignore CVR
// qualifiers. Distinguishing by CVR qualifiers would make it UB to
// e.g. cast a `char **` to `const char * const *` and dereference it,
// which is too common and useful to invalidate. C++'s similar types
// rule permits qualifier differences in these nested positions; in fact,
// C++ even allows that cast as an implicit conversion.
//
// Other qualifiers could theoretically be distinguished, especially if
// 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, types.ConvertType(qty));
}
llvm_unreachable("NYI");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The same problems we discussed about llvm_unreachable before is valid for the whole implementation of TBAA, please move to missing features for here, elsewhere and any future work

}
// Accesses to arrays are accesses to objects of their element types.
if (codeGenOpts.NewStructPathTBAA && ty->isArrayType()) {
llvm_unreachable("NYI");
}
// Enum types are distinct types. In C++ they have "underlying types",
// however they aren't related for TBAA.
if (const EnumType *ety = dyn_cast<EnumType>(ty)) {
assert(!cir::MissingFeatures::tbaaTagForEnum());
return tbaa_NYI(mlirContext);
}
if (const auto *eit = dyn_cast<BitIntType>(ty)) {
assert(!cir::MissingFeatures::tbaaTagForBitInt());
return tbaa_NYI(mlirContext);
}
// For now, handle any other kind of type conservatively.
return getChar();
}

cir::TBAAAttr CIRGenTBAA::getTypeInfo(clang::QualType qty) {
// At -O0 or relaxed aliasing, TBAA is not emitted for regular types.
if (codeGenOpts.OptimizationLevel == 0 || codeGenOpts.RelaxedAliasing) {
Expand Down Expand Up @@ -93,7 +146,7 @@ cir::TBAAAttr CIRGenTBAA::getTypeInfo(clang::QualType qty) {
// cache, which invalidates all its previously obtained iterators. So we
// first generate the node for the type and then add that node to the
// cache.
auto typeNode = cir::TBAAScalarAttr::get(mlirContext, types.ConvertType(qty));
auto typeNode = getTypeInfoHelper(qty);
return metadataCache[ty] = typeNode;
}

Expand Down
4 changes: 4 additions & 0 deletions clang/lib/CIR/CodeGen/CIRGenTBAA.h
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,10 @@ class CIRGenTBAA {

cir::TBAAAttr getChar();

// An internal helper function to generate metadata used
// to describe accesses to objects of the given type.
cir::TBAAAttr getTypeInfoHelper(clang::QualType qty);

public:
CIRGenTBAA(mlir::MLIRContext *mlirContext, clang::ASTContext &astContext,
CIRGenTypes &types, mlir::ModuleOp moduleOp,
Expand Down
13 changes: 13 additions & 0 deletions clang/test/CIR/CodeGen/tbaa-bitinit.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir -O1
// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s


// CIR: #tbaa[[tbaa_NYI:.*]] = #cir.tbaa

_BitInt(33) a;
_BitInt(31) b;
void c() {
// CIR: %{{.*}} = cir.load %{{.*}} : !cir.ptr<!cir.int<s, 33>>, !cir.int<s, 33> tbaa(#tbaa[[tbaa_NYI]])
// CIR: cir.store %{{.*}}, %{{.*}} : !cir.int<s, 31>, !cir.ptr<!cir.int<s, 31>> tbaa(#tbaa[[tbaa_NYI]])
b = a;
}
49 changes: 49 additions & 0 deletions clang/test/CIR/CodeGen/tbaa-enum.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir -O1
// 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: 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: 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: FileCheck --check-prefix=NO-TBAA --input-file=%t.ll %s

// NO-TBAA-NOT: !tbaa

// CIR: #tbaa[[tbaa_NYI:.*]] = #cir.tbaa
// CIR: #tbaa[[INT:.*]] = #cir.tbaa_scalar<type = !u32i>
// CIR: #tbaa[[INT_PTR:.*]] = #cir.tbaa_scalar<type = !cir.ptr<!u32i>>

typedef unsigned int uint32_t;
typedef enum {
RED_AUTO_32,
GREEN_AUTO_32,
BLUE_AUTO_32
} EnumAuto32;

uint32_t g0(EnumAuto32 *E, uint32_t *val) {
// CIR-LABEL: cir.func @g0
// CIR: %[[C5:.*]] = cir.const #cir.int<5> : !s32i
// CIR: %[[U_C5:.*]] = cir.cast(integral, %[[C5]] : !s32i), !u32i
// CIR: %[[VAL_PTR:.*]] = cir.load deref %{{.*}} : !cir.ptr<!cir.ptr<!u32i>>, !cir.ptr<!u32i> tbaa(#tbaa[[INT_PTR]])
// CIR: cir.store %[[U_C5]], %[[VAL_PTR]] : !u32i, !cir.ptr<!u32i> tbaa(#tbaa[[INT]])
// CIR: %[[C0:.*]] = cir.const #cir.int<0> : !s32i
// CIR: %[[U_C0:.*]] = cir.cast(integral, %[[C0]] : !s32i), !u32i
// CIR: %[[E_PTR:.*]] = cir.load deref %{{.*}} : !cir.ptr<!cir.ptr<!u32i>>, !cir.ptr<!u32i> tbaa(#tbaa[[INT_PTR]])
// CIR: cir.store %[[U_C0]], %[[E_PTR]] : !u32i, !cir.ptr<!u32i> tbaa(#tbaa[[tbaa_NYI]])
// CIR: %[[RET_PTR:.*]] = cir.load deref %{{.*}} : !cir.ptr<!cir.ptr<!u32i>>, !cir.ptr<!u32i> tbaa(#tbaa[[INT_PTR]])
// CIR: %[[RET:.*]] = cir.load %[[RET_PTR]] : !cir.ptr<!u32i>, !u32i tbaa(#tbaa[[INT]])
// CIR: cir.store %[[RET]], %{{.*}} : !u32i, !cir.ptr<!u32i>

// LLVM-LABEL: define{{.*}} i32 @g0(
// LLVM: store i32 5, ptr %{{.*}}, align 4, !tbaa [[TAG_i32:!.*]]
// LLVM: store i32 0, ptr %{{.*}}, align 4
// LLVM: load i32, ptr %{{.*}}, align 4, !tbaa [[TAG_i32]]
*val = 5;
*E = RED_AUTO_32;
return *val;
}

// 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]], i64 0}
33 changes: 33 additions & 0 deletions clang/test/CIR/CodeGen/tbaa-union.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir -O1
// 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
// 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 -relaxed-aliasing
// 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
// RUN: FileCheck --check-prefix=NO-TBAA --input-file=%t.ll %s

// NO-TBAA-NOT: !tbaa
// CIR: #tbaa[[CHAR:.*]] = #cir.tbaa_scalar<type = !cir.int<s, 1>>
// CIR: #tbaa[[Struct_S_PTR:.*]] = #cir.tbaa_scalar<type = !cir.ptr<!ty_S>>
typedef struct {
union {
int a, b;
};
int c;
} S;

void foo(S *s) {
// CIR-LABEL: cir.func @foo
// CIR: %[[C1:.*]] = cir.const #cir.int<1> : !s32i loc(#loc6)
// CIR: %{{.*}} = cir.load %{{.*}} : !cir.ptr<!cir.ptr<!ty_S>>, !cir.ptr<!ty_S> tbaa(#tbaa[[Struct_S_PTR]])
// CIR: cir.store %[[C1]], %{{.*}} : !s32i, !cir.ptr<!s32i> tbaa(#tbaa[[CHAR]])

// LLVM-LABEL: void @foo
// LLVM: store i32 1, ptr %{{.*}}, align 4, !tbaa ![[TBAA_TAG:.*]]
s->a = 1;
}

// LLVM: ![[TBAA_TAG]] = !{![[CHAR:.*]], ![[CHAR]], i64 0}
// LLVM: ![[CHAR]] = !{!"omnipotent char", ![[ROOT:.*]], i64 0}
// LLVM: ![[ROOT]] = !{!"Simple C/C++ TBAA"}
Loading