diff --git a/clang/include/clang/CIR/MissingFeatures.h b/clang/include/clang/CIR/MissingFeatures.h index 070144f69c20..dda4a3b5cb2b 100644 --- a/clang/include/clang/CIR/MissingFeatures.h +++ b/clang/include/clang/CIR/MissingFeatures.h @@ -60,7 +60,6 @@ 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; } diff --git a/clang/lib/CIR/CodeGen/CIRGenTBAA.cpp b/clang/lib/CIR/CodeGen/CIRGenTBAA.cpp index f2d46a30cc53..d2a7ff946b7b 100644 --- a/clang/lib/CIR/CodeGen/CIRGenTBAA.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenTBAA.cpp @@ -174,8 +174,22 @@ cir::TBAAAttr CIRGenTBAA::getTypeInfoHelper(clang::QualType qty) { // Enum types are distinct types. In C++ they have "underlying types", // however they aren't related for TBAA. if (const EnumType *ety = dyn_cast(ty)) { - assert(!cir::MissingFeatures::tbaaTagForEnum()); - return tbaa_NYI(mlirContext); + if (!features.CPlusPlus) + return getTypeInfo(ety->getDecl()->getIntegerType()); + + // In C++ mode, types have linkage, so we can rely on the ODR and + // on their mangled names, if they're external. + // TODO: Is there a way to get a program-wide unique name for a + // decl with local linkage or no linkage? + if (!ety->getDecl()->isExternallyVisible()) + return getChar(); + + SmallString<256> outName; + llvm::raw_svector_ostream out(outName); + types.getCXXABI().getMangleContext().mangleCanonicalTypeName( + QualType(ety, 0), out); + return cir::TBAAScalarAttr::get(mlirContext, outName, + types.convertType(qty)); } if (const auto *eit = dyn_cast(ty)) { assert(!cir::MissingFeatures::tbaaTagForBitInt()); diff --git a/clang/test/CIR/CodeGen/tbaa-enum.c b/clang/test/CIR/CodeGen/tbaa-enum.c index a08b416906fc..2136ab2303f7 100644 --- a/clang/test/CIR/CodeGen/tbaa-enum.c +++ b/clang/test/CIR/CodeGen/tbaa-enum.c @@ -14,6 +14,7 @@ // CIR: #tbaa[[CHAR:.*]] = #cir.tbaa_omnipotent_char // CIR: #tbaa[[INT:.*]] = #cir.tbaa_scalar // CIR: #tbaa[[LONG_LONG:.*]] = #cir.tbaa_scalar +// CIR: #tbaa[[LONG:.*]] = #cir.tbaa_scalar // CIR: #tbaa[[SHORT:.*]] = #cir.tbaa_scalar typedef unsigned char uint8_t; @@ -54,14 +55,14 @@ uint32_t g0(EnumAuto32 *E, uint32_t *val) { // 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 - // CIR: cir.store %[[U_C0]], %[[E_PTR]] : !u32i, !cir.ptr tbaa(#tbaa[[NYI]]) + // CIR: cir.store %[[U_C0]], %[[E_PTR]] : !u32i, !cir.ptr tbaa(#tbaa[[INT]]) // CIR: %[[RET_PTR:.*]] = cir.load deref %{{.*}} : !cir.ptr>, !cir.ptr // CIR: %[[RET:.*]] = cir.load %[[RET_PTR]] : !cir.ptr, !u32i tbaa(#tbaa[[INT]]) // CIR: cir.store %[[RET]], %{{.*}} : !u32i, !cir.ptr // LLVM-LABEL: define{{.*}} i32 @g0( // LLVM: store i32 5, ptr %{{.*}}, align 4, !tbaa [[TAG_i32:!.*]] - // LLVM: store i32 0, ptr %{{.*}}, align 4 + // LLVM: store i32 0, ptr %{{.*}}, align 4, !tbaa [[TAG_i32]] // LLVM: load i32, ptr %{{.*}}, align 4, !tbaa [[TAG_i32]] *val = 5; *E = RED_AUTO_32; @@ -76,14 +77,14 @@ uint64_t g1(EnumAuto64 *E, uint64_t *val) { // CIR: cir.store %[[U_C5]], %[[VAL_PTR]] : !u64i, !cir.ptr tbaa(#tbaa[[LONG_LONG]]) // CIR: %[[C0:.*]] = cir.const #cir.int<0> : !u64i // CIR: %[[E_PTR:.*]] = cir.load deref %{{.*}} : !cir.ptr>, !cir.ptr - // CIR: cir.store %[[C0]], %[[E_PTR]] : !u64i, !cir.ptr tbaa(#tbaa[[NYI]]) + // CIR: cir.store %[[C0]], %[[E_PTR]] : !u64i, !cir.ptr tbaa(#tbaa[[LONG]]) // CIR: %[[RET_PTR:.*]] = cir.load deref %{{.*}} : !cir.ptr>, !cir.ptr // CIR: %[[RET:.*]] = cir.load %[[RET_PTR]] : !cir.ptr, !u64i tbaa(#tbaa[[LONG_LONG]]) // CIR: cir.store %[[RET]], %{{.*}} : !u64i, !cir.ptr // LLVM-LABEL: define{{.*}} i64 @g1( // LLVM: store i64 5, ptr %{{.*}}, align 8, !tbaa [[TAG_i64:!.*]] - // LLVM: store i64 0, ptr %{{.*}}, align 8 + // LLVM: store i64 0, ptr %{{.*}}, align 8, !tbaa [[TAG_long:!.*]] // LLVM: load i64, ptr %{{.*}}, align 8, !tbaa [[TAG_i64]] *val = 5; *E = RED_AUTO_64; @@ -98,14 +99,14 @@ uint16_t g2(Enum16 *E, uint16_t *val) { // CIR: cir.store %[[U_C5]], %[[VAL_PTR]] : !u16i, !cir.ptr tbaa(#tbaa[[SHORT]]) // CIR: %[[C0:.*]] = cir.const #cir.int<0> : !u16i // CIR: %[[E_PTR:.*]] = cir.load deref %{{.*}} : !cir.ptr>, !cir.ptr - // CIR: cir.store %[[C0]], %[[E_PTR]] : !u16i, !cir.ptr tbaa(#tbaa[[NYI]]) + // CIR: cir.store %[[C0]], %[[E_PTR]] : !u16i, !cir.ptr tbaa(#tbaa[[SHORT]]) // CIR: %[[RET_PTR:.*]] = cir.load deref %{{.*}} : !cir.ptr>, !cir.ptr // CIR: %[[RET:.*]] = cir.load %[[RET_PTR]] : !cir.ptr, !u16i tbaa(#tbaa[[SHORT]]) // CIR: cir.store %[[RET]], %{{.*}} : !u16i, !cir.ptr // LLVM-LABEL: define{{.*}} i16 @g2( // LLVM: store i16 5, ptr %{{.*}}, align 2, !tbaa [[TAG_i16:!.*]] - // LLVM: store i16 0, ptr %{{.*}}, align 2 + // LLVM: store i16 0, ptr %{{.*}}, align 2, !tbaa [[TAG_i16]] // LLVM: load i16, ptr %{{.*}}, align 2, !tbaa [[TAG_i16]] *val = 5; *E = RED_16; @@ -120,7 +121,7 @@ uint8_t g3(Enum8 *E, uint8_t *val) { // CIR: cir.store %[[U_C5]], %[[VAL_PTR]] : !u8i, !cir.ptr tbaa(#tbaa[[CHAR]]) // CIR: %[[C0:.*]] = cir.const #cir.int<0> : !u8i // CIR: %[[E_PTR:.*]] = cir.load deref %{{.*}} : !cir.ptr>, !cir.ptr - // CIR: cir.store %[[C0]], %[[E_PTR]] : !u8i, !cir.ptr tbaa(#tbaa[[NYI]]) + // CIR: cir.store %[[C0]], %[[E_PTR]] : !u8i, !cir.ptr tbaa(#tbaa[[CHAR]]) // CIR: %[[RET_PTR:.*]] = cir.load deref %{{.*}} : !cir.ptr>, !cir.ptr // CIR: %[[RET:.*]] = cir.load %[[RET_PTR]] : !cir.ptr, !u8i tbaa(#tbaa[[CHAR]]) // CIR: cir.store %[[RET]], %{{.*}} : !u8i, !cir.ptr @@ -128,7 +129,7 @@ uint8_t g3(Enum8 *E, uint8_t *val) { // LLVM-LABEL: define{{.*}} i8 @g3( // LLVM: store i8 5, ptr %{{.*}}, align 1, !tbaa [[TAG_i8:!.*]] - // LLVM: store i8 0, ptr %{{.*}}, align 1 + // LLVM: store i8 0, ptr %{{.*}}, align 1, !tbaa [[TAG_i8]] // LLVM: load i8, ptr %{{.*}}, align 1, !tbaa [[TAG_i8]] *val = 5; *E = RED_8; @@ -141,6 +142,8 @@ uint8_t g3(Enum8 *E, uint8_t *val) { // LLVM: [[TAG_c_tbaa]] = !{!"Simple C/C++ TBAA"} // 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} +// LLVM: [[TYPE_long]] = !{!"long", [[TYPE_char]], i64 0} // LLVM: [[TAG_i16]] = !{[[TYPE_i16:!.*]], [[TYPE_i16]], i64 0} // LLVM: [[TYPE_i16]] = !{!"short", [[TYPE_char]], -// LLVM: [[TAG_i8]] = !{[[TYPE_i8:!.*]], [[TYPE_char]], i64 0} \ No newline at end of file +// LLVM: [[TAG_i8]] = !{[[TYPE_i8:!.*]], [[TYPE_char]], i64 0} diff --git a/clang/test/CIR/CodeGen/tbaa-enum.cpp b/clang/test/CIR/CodeGen/tbaa-enum.cpp new file mode 100644 index 000000000000..6dc469a21e58 --- /dev/null +++ b/clang/test/CIR/CodeGen/tbaa-enum.cpp @@ -0,0 +1,157 @@ +// 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: 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[[NYI:.*]] = #cir.tbaa +// CIR: #tbaa[[CHAR:.*]] = #cir.tbaa_omnipotent_char +// CIR: #tbaa[[INT:.*]] = #cir.tbaa_scalar +// CIR: #tbaa[[EnumAuto32:.*]] = #cir.tbaa_scalar +// CIR: #tbaa[[LONG_LONG:.*]] = #cir.tbaa_scalar +// CIR: #tbaa[[EnumAuto64:.*]] = #cir.tbaa_scalar +// CIR: #tbaa[[SHORT:.*]] = #cir.tbaa_scalar +// CIR: #tbaa[[Enum16:.*]] = #cir.tbaa_scalar +// CIR: #tbaa[[Enum8:.*]] = #cir.tbaa_scalar + + +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned int uint32_t; +typedef unsigned long long uint64_t; + +typedef enum { + RED_AUTO_32, + GREEN_AUTO_32, + BLUE_AUTO_32 +} EnumAuto32; + +typedef enum { + RED_AUTO_64, + GREEN_AUTO_64, + BLUE_AUTO_64 = 0x100000000ull +} EnumAuto64; + +typedef enum : uint16_t { + RED_16, + GREEN_16, + BLUE_16 +} Enum16; + +typedef enum : uint8_t { + RED_8, + GREEN_8, + BLUE_8 +} Enum8; + +uint32_t g0(EnumAuto32 *E, uint32_t *val) { + // CIR-LABEL: cir.func @_Z2g0 + // 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 + // CIR: cir.store %[[U_C5]], %[[VAL_PTR]] : !u32i, !cir.ptr tbaa(#tbaa[[INT]]) + // CIR: %[[C0:.*]] = cir.const #cir.int<0> : !u32i + // CIR: %[[E_PTR:.*]] = cir.load deref %{{.*}} : !cir.ptr>, !cir.ptr + // CIR: cir.store %[[C0]], %[[E_PTR]] : !u32i, !cir.ptr tbaa(#tbaa[[EnumAuto32]]) + // CIR: %[[RET_PTR:.*]] = cir.load deref %{{.*}} : !cir.ptr>, !cir.ptr + // CIR: %[[RET:.*]] = cir.load %[[RET_PTR]] : !cir.ptr, !u32i tbaa(#tbaa[[INT]]) + // CIR: cir.store %[[RET]], %{{.*}} : !u32i, !cir.ptr + + // LLVM-LABEL: define{{.*}} i32 @_Z2g0 + // LLVM: store i32 5, ptr %{{.*}}, align 4, !tbaa [[TAG_i32:!.*]] + // LLVM: store i32 0, ptr %{{.*}}, align 4, !tbaa [[TAG_EnumAuto32:!.*]] + // LLVM: load i32, ptr %{{.*}}, align 4, !tbaa [[TAG_i32]] + *val = 5; + *E = RED_AUTO_32; + return *val; +} + +uint64_t g1(EnumAuto64 *E, uint64_t *val) { + // CIR-LABEL: cir.func @_Z2g1 + // CIR: %[[C5:.*]] = cir.const #cir.int<5> : !s32i + // CIR: %[[U_C5:.*]] = cir.cast(integral, %[[C5]] : !s32i), !u64i + // CIR: %[[VAL_PTR:.*]] = cir.load deref %{{.*}} : !cir.ptr>, !cir.ptr + // CIR: cir.store %[[U_C5]], %[[VAL_PTR]] : !u64i, !cir.ptr tbaa(#tbaa[[LONG_LONG]]) + // CIR: %[[C0:.*]] = cir.const #cir.int<0> : !u64i + // CIR: %[[E_PTR:.*]] = cir.load deref %{{.*}} : !cir.ptr>, !cir.ptr + // CIR: cir.store %[[C0]], %[[E_PTR]] : !u64i, !cir.ptr tbaa(#tbaa[[EnumAuto64]]) + // CIR: %[[RET_PTR:.*]] = cir.load deref %{{.*}} : !cir.ptr>, !cir.ptr + // CIR: %[[RET:.*]] = cir.load %[[RET_PTR]] : !cir.ptr, !u64i tbaa(#tbaa[[LONG_LONG]]) + // CIR: cir.store %[[RET]], %{{.*}} : !u64i, !cir.ptr + + // LLVM-LABEL: define{{.*}} i64 @_Z2g1 + // LLVM: store i64 5, ptr %{{.*}}, align 8, !tbaa [[TAG_i64:!.*]] + // LLVM: store i64 0, ptr %{{.*}}, align 8, !tbaa [[TAG_EnumAuto64:!.*]] + // LLVM: load i64, ptr %{{.*}}, align 8, !tbaa [[TAG_i64]] + *val = 5; + *E = RED_AUTO_64; + return *val; +} + +uint16_t g2(Enum16 *E, uint16_t *val) { + // CIR-LABEL: cir.func @_Z2g2 + // CIR: %[[C5:.*]] = cir.const #cir.int<5> : !s32i + // CIR: %[[U_C5:.*]] = cir.cast(integral, %[[C5]] : !s32i), !u16i + // CIR: %[[VAL_PTR:.*]] = cir.load deref %{{.*}} : !cir.ptr>, !cir.ptr + // CIR: cir.store %[[U_C5]], %[[VAL_PTR]] : !u16i, !cir.ptr tbaa(#tbaa[[SHORT]]) + // CIR: %[[C0:.*]] = cir.const #cir.int<0> : !u16i + // CIR: %[[E_PTR:.*]] = cir.load deref %{{.*}} : !cir.ptr>, !cir.ptr + // CIR: cir.store %[[C0]], %[[E_PTR]] : !u16i, !cir.ptr tbaa(#tbaa[[Enum16]]) + // CIR: %[[RET_PTR:.*]] = cir.load deref %{{.*}} : !cir.ptr>, !cir.ptr + // CIR: %[[RET:.*]] = cir.load %[[RET_PTR]] : !cir.ptr, !u16i tbaa(#tbaa[[SHORT]]) + // CIR: cir.store %[[RET]], %{{.*}} : !u16i, !cir.ptr + + // LLVM-LABEL: define{{.*}} i16 @_Z2g2 + // LLVM: store i16 5, ptr %{{.*}}, align 2, !tbaa [[TAG_i16:!.*]] + // LLVM: store i16 0, ptr %{{.*}}, align 2, !tbaa [[TAG_Enum16:!.*]] + // LLVM: load i16, ptr %{{.*}}, align 2, !tbaa [[TAG_i16]] + *val = 5; + *E = RED_16; + return *val; +} + +uint8_t g3(Enum8 *E, uint8_t *val) { + // CIR-LABEL: cir.func @_Z2g3 + // CIR: %[[C5:.*]] = cir.const #cir.int<5> : !s32i + // CIR: %[[U_C5:.*]] = cir.cast(integral, %[[C5]] : !s32i), !u8i + // CIR: %[[VAL_PTR:.*]] = cir.load deref %{{.*}} : !cir.ptr>, !cir.ptr + // CIR: cir.store %[[U_C5]], %[[VAL_PTR]] : !u8i, !cir.ptr tbaa(#tbaa[[CHAR]]) + // CIR: %[[C0:.*]] = cir.const #cir.int<0> : !u8i + // CIR: %[[E_PTR:.*]] = cir.load deref %{{.*}} : !cir.ptr>, !cir.ptr + // CIR: cir.store %[[C0]], %[[E_PTR]] : !u8i, !cir.ptr tbaa(#tbaa[[Enum8]]) + // CIR: %[[RET_PTR:.*]] = cir.load deref %{{.*}} : !cir.ptr>, !cir.ptr + // CIR: %[[RET:.*]] = cir.load %[[RET_PTR]] : !cir.ptr, !u8i tbaa(#tbaa[[CHAR]]) + // CIR: cir.store %[[RET]], %{{.*}} : !u8i, !cir.ptr + + + // LLVM-LABEL: define{{.*}} i8 @_Z2g3 + // LLVM: store i8 5, ptr %{{.*}}, align 1, !tbaa [[TAG_i8:!.*]] + // LLVM: store i8 0, ptr %{{.*}}, align 1, !tbaa [[TAG_Enum8:!.*]] + // LLVM: load i8, ptr %{{.*}}, align 1, !tbaa [[TAG_i8]] + *val = 5; + *E = RED_8; + 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: [[TAG_c_tbaa]] = !{!"Simple C++ TBAA"} +// LLVM: [[TAG_EnumAuto32]] = !{[[TYPE_EnumAuto32:!.*]], [[TYPE_EnumAuto32]], i64 0} +// LLVM: [[TYPE_EnumAuto32]] = !{!"_ZTS10EnumAuto32", [[TYPE_char]], +// LLVM: [[TAG_i64]] = !{[[TYPE_i64:!.*]], [[TYPE_i64]], i64 0} +// LLVM: [[TYPE_i64]] = !{!"long long", [[TYPE_char]], +// LLVM: [[TAG_EnumAuto64]] = !{[[TYPE_EnumAuto64:!.*]], [[TYPE_EnumAuto64]], i64 0} +// LLVM: [[TYPE_EnumAuto64]] = !{!"_ZTS10EnumAuto64", [[TYPE_char]], +// LLVM: [[TAG_i16]] = !{[[TYPE_i16:!.*]], [[TYPE_i16]], i64 0} +// LLVM: [[TYPE_i16]] = !{!"short", [[TYPE_char]], +// LLVM: [[TAG_Enum16]] = !{[[TYPE_Enum16:!.*]], [[TYPE_Enum16]], i64 0} +// LLVM: [[TYPE_Enum16]] = !{!"_ZTS6Enum16", [[TYPE_char]], +// LLVM: [[TAG_Enum8]] = !{[[TYPE_Enum8:!.*]], [[TYPE_Enum8]], i64 0} +// LLVM: [[TYPE_Enum8]] = !{!"_ZTS5Enum8", [[TYPE_char]],