llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang Author: Hassnaa Hamdi (hassnaaHamdi) <details> <summary>Changes</summary> - Update clang codegen for loads/stores to read/write the legal in-memory representation for _BitInt(N <= 128) and _BitInt(N <= 64). - AArch64: for _BitInt(N <= 128) the machine type is the smallest (un)signed fundamental integral data types. - ARM: for _BitInt(N <= 64) the machine type is the smallest (un)signed fundamental integral data types. - So, Loads and Stores will be as following: N - bit-precise integer size as declared M - number of bits in the representation, M >= N ``` Loads %u = load iM, ptr %p %v = trunc iM %u to iN ``` ``` Stores %u = Xext iN %v to iM store iM %u, ptr %p where Xext is zext or sext on ARM, depending on C type, and zext for AArch64. ``` These changes are according to the ABI documentation for: ARM: https://github.com/ARM-software/abi-aa/blob/main/aapcs32/aapcs32.rst AArch64: https://github.com/ARM-software/abi-aa/blob/main/aapcs64/aapcs64.rst --- Full diff: https://github.com/llvm/llvm-project/pull/93495.diff 11 Files Affected: - (modified) clang/include/clang/Basic/TargetInfo.h (+9) - (modified) clang/lib/Basic/Targets/AArch64.cpp (+10) - (modified) clang/lib/Basic/Targets/AArch64.h (+2) - (modified) clang/lib/Basic/Targets/ARM.cpp (+16) - (modified) clang/lib/Basic/Targets/ARM.h (+4) - (modified) clang/lib/CodeGen/CGExpr.cpp (+16-1) - (modified) clang/lib/CodeGen/CodeGenTypes.cpp (+3) - (added) clang/test/CodeGen/AArch64/BitInt.c (+35) - (added) clang/test/CodeGen/Arm/BitInt.c (+36) - (modified) clang/test/CodeGen/attr-noundef.cpp (+3-3) - (modified) clang/test/CodeGen/builtins-bitint.c (+30-24) ``````````diff diff --git a/clang/include/clang/Basic/TargetInfo.h b/clang/include/clang/Basic/TargetInfo.h index 8a6511b9ced83..92b03e8d6bdbc 100644 --- a/clang/include/clang/Basic/TargetInfo.h +++ b/clang/include/clang/Basic/TargetInfo.h @@ -667,6 +667,15 @@ class TargetInfo : public TransferrableTargetInfo, return false; } + // Different targets may support different machine type width for the _BitInt + virtual unsigned getBitIntLegalWidth(unsigned Width) const { + return Width; + } + + virtual bool isBitIntSignExtended(bool IsSigned) const { + return false; + } + // Different targets may support a different maximum width for the _BitInt // type, depending on what operations are supported. virtual size_t getMaxBitIntWidth() const { diff --git a/clang/lib/Basic/Targets/AArch64.cpp b/clang/lib/Basic/Targets/AArch64.cpp index 5db1ce78c657f..a5d66cb44b566 100644 --- a/clang/lib/Basic/Targets/AArch64.cpp +++ b/clang/lib/Basic/Targets/AArch64.cpp @@ -221,6 +221,16 @@ bool AArch64TargetInfo::validateTarget(DiagnosticsEngine &Diags) const { return true; } +unsigned AArch64TargetInfo::getBitIntLegalWidth(unsigned Width) const { + unsigned IntegralSizes[] = {32, 64, 128}; + const unsigned ARR_SZ = sizeof(IntegralSizes) / sizeof(unsigned); + for (unsigned I = 0; I < ARR_SZ; I ++) { + if (IntegralSizes[I] > Width) + return IntegralSizes[I]; + } + return Width; +} + bool AArch64TargetInfo::validateBranchProtection(StringRef Spec, StringRef, BranchProtectionInfo &BPI, StringRef &Err) const { diff --git a/clang/lib/Basic/Targets/AArch64.h b/clang/lib/Basic/Targets/AArch64.h index 12fb50286f751..89c6af00e628c 100644 --- a/clang/lib/Basic/Targets/AArch64.h +++ b/clang/lib/Basic/Targets/AArch64.h @@ -202,6 +202,8 @@ class LLVM_LIBRARY_VISIBILITY AArch64TargetInfo : public TargetInfo { bool hasBitIntType() const override { return true; } bool validateTarget(DiagnosticsEngine &Diags) const override; + + unsigned getBitIntLegalWidth(unsigned Width) const override; }; class LLVM_LIBRARY_VISIBILITY AArch64leTargetInfo : public AArch64TargetInfo { diff --git a/clang/lib/Basic/Targets/ARM.cpp b/clang/lib/Basic/Targets/ARM.cpp index 7423626d7c3cb..a074bafacc25f 100644 --- a/clang/lib/Basic/Targets/ARM.cpp +++ b/clang/lib/Basic/Targets/ARM.cpp @@ -1344,6 +1344,22 @@ int ARMTargetInfo::getEHDataRegisterNumber(unsigned RegNo) const { bool ARMTargetInfo::hasSjLjLowering() const { return true; } +unsigned ARMTargetInfo::getBitIntLegalWidth(unsigned Width) const { + unsigned IntegralSizes[] = {32, 64}; + const unsigned ARR_SZ = sizeof(IntegralSizes) / sizeof(unsigned); + for (unsigned I = 0; I < ARR_SZ; I ++) { + if (IntegralSizes[I] > Width) + return IntegralSizes[I]; + } + return Width; +} + +bool ARMTargetInfo::isBitIntSignExtended(bool IsSigned) const { + if (IsSigned) + return true; + return false; +} + ARMleTargetInfo::ARMleTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) : ARMTargetInfo(Triple, Opts) {} diff --git a/clang/lib/Basic/Targets/ARM.h b/clang/lib/Basic/Targets/ARM.h index df9855a52e61c..679c29e786cc9 100644 --- a/clang/lib/Basic/Targets/ARM.h +++ b/clang/lib/Basic/Targets/ARM.h @@ -229,6 +229,10 @@ class LLVM_LIBRARY_VISIBILITY ARMTargetInfo : public TargetInfo { std::pair<unsigned, unsigned> hardwareInterferenceSizes() const override { return std::make_pair(getTriple().isArch64Bit() ? 256 : 64, 64); } + + unsigned getBitIntLegalWidth(unsigned Width) const override; + + bool isBitIntSignExtended(bool IsSigned) const override; }; class LLVM_LIBRARY_VISIBILITY ARMleTargetInfo : public ARMTargetInfo { diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index d6478cc6835d8..4030f0024df4d 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -1989,7 +1989,14 @@ llvm::Value *CodeGenFunction::EmitLoadOfScalar(Address Addr, bool Volatile, return EmitAtomicLoad(AtomicLValue, Loc).getScalarVal(); } - llvm::LoadInst *Load = Builder.CreateLoad(Addr, Volatile); + llvm::LoadInst *Load = nullptr; + if (const auto *BitintTy = Ty->getAs<BitIntType>()) { + Address TempAddr(Addr.getBasePointer(), ConvertTypeForMem(Ty), Addr.getAlignment()); + Load = Builder.CreateLoad(TempAddr, Volatile); + } + else + Load = Builder.CreateLoad(Addr, Volatile); + if (isNontemporal) { llvm::MDNode *Node = llvm::MDNode::get( Load->getContext(), llvm::ConstantAsMetadata::get(Builder.getInt32(1))); @@ -2021,6 +2028,12 @@ llvm::Value *CodeGenFunction::EmitToMemory(llvm::Value *Value, QualType Ty) { assert(Value->getType()->isIntegerTy(getContext().getTypeSize(Ty)) && "wrong value rep of bool"); } + if(auto *BitIntTy = Ty->getAs<BitIntType>()) { + if (CGM.getTarget().isBitIntSignExtended(BitIntTy->isSigned())) + return Builder.CreateSExt(Value, ConvertTypeForMem(Ty), "sext_bitint"); + else + return Builder.CreateZExt(Value, ConvertTypeForMem(Ty), "zext_bitint"); + } return Value; } @@ -2043,6 +2056,8 @@ llvm::Value *CodeGenFunction::EmitFromMemory(llvm::Value *Value, QualType Ty) { unsigned ValNumElems = cast<llvm::FixedVectorType>(ValTy)->getNumElements(); return emitBoolVecConversion(V, ValNumElems, "extractvec"); } + if(Ty->getAs<BitIntType>()) + return Builder.CreateTrunc(Value, ConvertType(Ty), "to_bitint"); return Value; } diff --git a/clang/lib/CodeGen/CodeGenTypes.cpp b/clang/lib/CodeGen/CodeGenTypes.cpp index 0a926e4ac27fe..743c95e5d2a2f 100644 --- a/clang/lib/CodeGen/CodeGenTypes.cpp +++ b/clang/lib/CodeGen/CodeGenTypes.cpp @@ -114,6 +114,9 @@ llvm::Type *CodeGenTypes::ConvertTypeForMem(QualType T, bool ForBitField) { return llvm::IntegerType::get(getLLVMContext(), (unsigned)Context.getTypeSize(T)); + if (T->isBitIntType()) + return llvm::IntegerType::get(getLLVMContext(), + CGM.getTarget().getBitIntLegalWidth(T->getAs<BitIntType>()->getNumBits())); // Else, don't map it. return R; } diff --git a/clang/test/CodeGen/AArch64/BitInt.c b/clang/test/CodeGen/AArch64/BitInt.c new file mode 100644 index 0000000000000..1784bb461ff86 --- /dev/null +++ b/clang/test/CodeGen/AArch64/BitInt.c @@ -0,0 +1,35 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 5 +// RUN: %clang_cc1 -triple aarch64 -emit-llvm -o - %s | FileCheck %s +// RUN: %clang_cc1 -triple aarch64 -S -o /dev/null %s + +_BitInt(18) signed_src; +_BitInt(18) signed_dst; + +// CHECK-LABEL: define dso_local void @test_signed( +// CHECK-SAME: ) #[[ATTR0:[0-9]+]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr @signed_dst, align 4 +// CHECK-NEXT: [[TOBITINT:%.*]] = trunc i32 [[TMP0]] to i18 +// CHECK-NEXT: [[ZEXTBITINT:%.*]] = zext i18 [[TOBITINT]] to i32 +// CHECK-NEXT: store i32 [[ZEXTBITINT]], ptr @signed_src, align 4 +// CHECK-NEXT: ret void +// +void test_signed() { + signed_src = signed_dst; +} + +unsigned _BitInt(18) src; +unsigned _BitInt(18) dst; + +// CHECK-LABEL: define dso_local void @test_unsigned( +// CHECK-SAME: ) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr @dst, align 4 +// CHECK-NEXT: [[TOBITINT:%.*]] = trunc i32 [[TMP0]] to i18 +// CHECK-NEXT: [[ZEXTBITINT:%.*]] = zext i18 [[TOBITINT]] to i32 +// CHECK-NEXT: store i32 [[ZEXTBITINT]], ptr @src, align 4 +// CHECK-NEXT: ret void +// +void test_unsigned() { + src = dst; +} diff --git a/clang/test/CodeGen/Arm/BitInt.c b/clang/test/CodeGen/Arm/BitInt.c new file mode 100644 index 0000000000000..a8fe5029383ea --- /dev/null +++ b/clang/test/CodeGen/Arm/BitInt.c @@ -0,0 +1,36 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 4 +// RUN: %clang_cc1 -triple arm -emit-llvm -o - %s | FileCheck %s +// RUN: %clang_cc1 -triple arm -S -o /dev/null %s + +_BitInt(18) signed_src; +_BitInt(18) signed_dst; + +// CHECK-LABEL: define dso_local arm_aapcscc void @test_signed( +// CHECK-SAME: ) #[[ATTR0:[0-9]+]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr @signed_dst, align 4 +// CHECK-NEXT: [[TOBITINT:%.*]] = trunc i32 [[TMP0]] to i18 +// CHECK-NEXT: [[SEXTBITINT:%.*]] = sext i18 [[TOBITINT]] to i32 +// CHECK-NEXT: store i32 [[SEXTBITINT]], ptr @signed_src, align 4 +// CHECK-NEXT: ret void +// +void test_signed() { + signed_src = signed_dst; +} + +unsigned _BitInt(18) src; +unsigned _BitInt(18) dst; + +// CHECK-LABEL: define dso_local arm_aapcscc void @test_unsigned( +// CHECK-SAME: ) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr @dst, align 4 +// CHECK-NEXT: [[TOBITINT:%.*]] = trunc i32 [[TMP0]] to i18 +// CHECK-NEXT: [[ZEXTBITINT:%.*]] = zext i18 [[TOBITINT]] to i32 +// CHECK-NEXT: store i32 [[ZEXTBITINT]], ptr @src, align 4 +// CHECK-NEXT: ret void +// +void test_unsigned() { + src = dst; +} + diff --git a/clang/test/CodeGen/attr-noundef.cpp b/clang/test/CodeGen/attr-noundef.cpp index e1cab091bfcbf..16fc03bd6d0be 100644 --- a/clang/test/CodeGen/attr-noundef.cpp +++ b/clang/test/CodeGen/attr-noundef.cpp @@ -159,9 +159,9 @@ void pass_large_BitInt(_BitInt(127) e) { // TODO: for now, ExtInt is only noundef if it is sign/zero-extended // CHECK-INTEL: [[DEF]] noundef signext i3 @{{.*}}ret_BitInt{{.*}}() -// CHECK-AARCH: [[DEF]] i3 @{{.*}}ret_BitInt{{.*}}() +// CHECK-AARCH: [[DEF]] noundef i3 @{{.*}}ret_BitInt{{.*}}() // CHECK-INTEL: [[DEF]] void @{{.*}}pass_BitInt{{.*}}(i3 noundef signext % -// CHECK-AARCH: [[DEF]] void @{{.*}}pass_BitInt{{.*}}(i3 % +// CHECK-AARCH: [[DEF]] void @{{.*}}pass_BitInt{{.*}}(i3 noundef % // CHECK-INTEL: [[DEF]] void @{{.*}}pass_large_BitInt{{.*}}(i64 %{{.*}}, i64 % -// CHECK-AARCH: [[DEF]] void @{{.*}}pass_large_BitInt{{.*}}(i127 % +// CHECK-AARCH: [[DEF]] void @{{.*}}pass_large_BitInt{{.*}}(i127 noundef % } // namespace check_exotic diff --git a/clang/test/CodeGen/builtins-bitint.c b/clang/test/CodeGen/builtins-bitint.c index 804e497128773..3d103de5542ec 100644 --- a/clang/test/CodeGen/builtins-bitint.c +++ b/clang/test/CodeGen/builtins-bitint.c @@ -8,10 +8,11 @@ // CHECK-O0-LABEL: define dso_local arm_aapcscc i32 @test_popcountg_ubi1( // CHECK-O0-SAME: ) #[[ATTR0:[0-9]+]] { // CHECK-O0-NEXT: entry: -// CHECK-O0-NEXT: [[A:%.*]] = alloca i1, align 1 -// CHECK-O0-NEXT: store i1 true, ptr [[A]], align 1 -// CHECK-O0-NEXT: [[TMP0:%.*]] = load i1, ptr [[A]], align 1 -// CHECK-O0-NEXT: [[TMP1:%.*]] = call i1 @llvm.ctpop.i1(i1 [[TMP0]]) +// CHECK-O0-NEXT: [[A:%.*]] = alloca i32, align 1 +// CHECK-O0-NEXT: store i32 1, ptr [[A]], align 1 +// CHECK-O0-NEXT: [[TMP0:%.*]] = load i32, ptr [[A]], align 1 +// CHECK-O0-NEXT: [[TO_BITINT:%.*]] = trunc i32 [[TMP0]] to i1 +// CHECK-O0-NEXT: [[TMP1:%.*]] = call i1 @llvm.ctpop.i1(i1 [[TO_BITINT]]) // CHECK-O0-NEXT: [[CAST:%.*]] = zext i1 [[TMP1]] to i32 // CHECK-O0-NEXT: ret i32 [[CAST]] // @@ -28,10 +29,11 @@ int test_popcountg_ubi1() { // CHECK-O0-LABEL: define dso_local arm_aapcscc i32 @test_popcountg_ubi2( // CHECK-O0-SAME: ) #[[ATTR0]] { // CHECK-O0-NEXT: entry: -// CHECK-O0-NEXT: [[A:%.*]] = alloca i2, align 1 -// CHECK-O0-NEXT: store i2 -1, ptr [[A]], align 1 -// CHECK-O0-NEXT: [[TMP0:%.*]] = load i2, ptr [[A]], align 1 -// CHECK-O0-NEXT: [[TMP1:%.*]] = call i2 @llvm.ctpop.i2(i2 [[TMP0]]) +// CHECK-O0-NEXT: [[A:%.*]] = alloca i32, align 1 +// CHECK-O0-NEXT: store i32 3, ptr [[A]], align 1 +// CHECK-O0-NEXT: [[TMP0:%.*]] = load i32, ptr [[A]], align 1 +// CHECK-O0-NEXT: [[TO_BITINT:%.*]] = trunc i32 [[TMP0]] to i2 +// CHECK-O0-NEXT: [[TMP1:%.*]] = call i2 @llvm.ctpop.i2(i2 [[TO_BITINT]]) // CHECK-O0-NEXT: [[CAST:%.*]] = zext i2 [[TMP1]] to i32 // CHECK-O0-NEXT: ret i32 [[CAST]] // @@ -48,10 +50,11 @@ int test_popcountg_ubi2() { // CHECK-O0-LABEL: define dso_local arm_aapcscc i32 @test_ctzg_ubi1( // CHECK-O0-SAME: ) #[[ATTR0]] { // CHECK-O0-NEXT: entry: -// CHECK-O0-NEXT: [[A:%.*]] = alloca i1, align 1 -// CHECK-O0-NEXT: store i1 false, ptr [[A]], align 1 -// CHECK-O0-NEXT: [[TMP0:%.*]] = load i1, ptr [[A]], align 1 -// CHECK-O0-NEXT: [[TMP1:%.*]] = call i1 @llvm.cttz.i1(i1 [[TMP0]], i1 false) +// CHECK-O0-NEXT: [[A:%.*]] = alloca i32, align 1 +// CHECK-O0-NEXT: store i32 0, ptr [[A]], align 1 +// CHECK-O0-NEXT: [[TMP0:%.*]] = load i32, ptr [[A]], align 1 +// CHECK-O0-NEXT: [[TO_BITINT:%.*]] = trunc i32 [[TMP0]] to i1 +// CHECK-O0-NEXT: [[TMP1:%.*]] = call i1 @llvm.cttz.i1(i1 [[TO_BITINT]], i1 false) // CHECK-O0-NEXT: [[CAST:%.*]] = zext i1 [[TMP1]] to i32 // CHECK-O0-NEXT: ret i32 [[CAST]] // @@ -68,10 +71,11 @@ int test_ctzg_ubi1() { // CHECK-O0-LABEL: define dso_local arm_aapcscc i32 @test_ctzg_ubi2( // CHECK-O0-SAME: ) #[[ATTR0]] { // CHECK-O0-NEXT: entry: -// CHECK-O0-NEXT: [[A:%.*]] = alloca i2, align 1 -// CHECK-O0-NEXT: store i2 0, ptr [[A]], align 1 -// CHECK-O0-NEXT: [[TMP0:%.*]] = load i2, ptr [[A]], align 1 -// CHECK-O0-NEXT: [[TMP1:%.*]] = call i2 @llvm.cttz.i2(i2 [[TMP0]], i1 false) +// CHECK-O0-NEXT: [[A:%.*]] = alloca i32, align 1 +// CHECK-O0-NEXT: store i32 0, ptr [[A]], align 1 +// CHECK-O0-NEXT: [[TMP0:%.*]] = load i32, ptr [[A]], align 1 +// CHECK-O0-NEXT: [[TO_BITINT:%.*]] = trunc i32 [[TMP0]] to i2 +// CHECK-O0-NEXT: [[TMP1:%.*]] = call i2 @llvm.cttz.i2(i2 [[TO_BITINT]], i1 false) // CHECK-O0-NEXT: [[CAST:%.*]] = zext i2 [[TMP1]] to i32 // CHECK-O0-NEXT: ret i32 [[CAST]] // @@ -88,10 +92,11 @@ int test_ctzg_ubi2() { // CHECK-O0-LABEL: define dso_local arm_aapcscc i32 @test_clzg_ubi1( // CHECK-O0-SAME: ) #[[ATTR0]] { // CHECK-O0-NEXT: entry: -// CHECK-O0-NEXT: [[A:%.*]] = alloca i1, align 1 -// CHECK-O0-NEXT: store i1 false, ptr [[A]], align 1 -// CHECK-O0-NEXT: [[TMP0:%.*]] = load i1, ptr [[A]], align 1 -// CHECK-O0-NEXT: [[TMP1:%.*]] = call i1 @llvm.ctlz.i1(i1 [[TMP0]], i1 false) +// CHECK-O0-NEXT: [[A:%.*]] = alloca i32, align 1 +// CHECK-O0-NEXT: store i32 0, ptr [[A]], align 1 +// CHECK-O0-NEXT: [[TMP0:%.*]] = load i32, ptr [[A]], align 1 +// CHECK-O0-NEXT: [[TO_BITINT:%.*]] = trunc i32 [[TMP0]] to i1 +// CHECK-O0-NEXT: [[TMP1:%.*]] = call i1 @llvm.ctlz.i1(i1 [[TO_BITINT]], i1 false) // CHECK-O0-NEXT: [[CAST:%.*]] = zext i1 [[TMP1]] to i32 // CHECK-O0-NEXT: ret i32 [[CAST]] // @@ -108,10 +113,11 @@ int test_clzg_ubi1() { // CHECK-O0-LABEL: define dso_local arm_aapcscc i32 @test_clzg_ubi2( // CHECK-O0-SAME: ) #[[ATTR0]] { // CHECK-O0-NEXT: entry: -// CHECK-O0-NEXT: [[A:%.*]] = alloca i2, align 1 -// CHECK-O0-NEXT: store i2 0, ptr [[A]], align 1 -// CHECK-O0-NEXT: [[TMP0:%.*]] = load i2, ptr [[A]], align 1 -// CHECK-O0-NEXT: [[TMP1:%.*]] = call i2 @llvm.ctlz.i2(i2 [[TMP0]], i1 false) +// CHECK-O0-NEXT: [[A:%.*]] = alloca i32, align 1 +// CHECK-O0-NEXT: store i32 0, ptr [[A]], align 1 +// CHECK-O0-NEXT: [[TMP0:%.*]] = load i32, ptr [[A]], align 1 +// CHECK-O0-NEXT: [[TO_BITINT:%.*]] = trunc i32 [[TMP0]] to i2 +// CHECK-O0-NEXT: [[TMP1:%.*]] = call i2 @llvm.ctlz.i2(i2 [[TO_BITINT]], i1 false) // CHECK-O0-NEXT: [[CAST:%.*]] = zext i2 [[TMP1]] to i32 // CHECK-O0-NEXT: ret i32 [[CAST]] // `````````` </details> https://github.com/llvm/llvm-project/pull/93495 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits