llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang @llvm/pr-subscribers-clang-codegen Author: Mariya Podchishchaeva (Fznamznon) <details> <summary>Changes</summary> Currently for i128:128 targets correct implementation is possible either for __int128 or for _BitInt(129+) with lowering to iN, but not both. Since we have now correct implementation of __int128 in place after a21abc7, this patch attempts to fix codegen issues by lowering _BitInt(129+) types to an array of i8 for "memory", similarly how it is happening for bools now. Fixes https://github.com/llvm/llvm-project/issues/85139 Fixes https://github.com/llvm/llvm-project/issues/83419 --- Full diff: https://github.com/llvm/llvm-project/pull/91364.diff 6 Files Affected: - (modified) clang/lib/CodeGen/CGExpr.cpp (+8) - (modified) clang/lib/CodeGen/CGExprConstant.cpp (+12) - (modified) clang/lib/CodeGen/CGExprScalar.cpp (+7) - (modified) clang/lib/CodeGen/CodeGenTypes.cpp (+6) - (modified) clang/test/CodeGen/ext-int-cc.c (+1-1) - (modified) clang/test/CodeGen/ext-int.c (+93-4) ``````````diff diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index d96c7bb1e568..7e631e469a88 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -1989,6 +1989,14 @@ llvm::Value *CodeGenFunction::EmitLoadOfScalar(Address Addr, bool Volatile, return EmitAtomicLoad(AtomicLValue, Loc).getScalarVal(); } + if (const auto *BIT = Ty->getAs<BitIntType>()) { + if (BIT->getNumBits() > 128) { + // Long _BitInt has array of bytes as in-memory type. + llvm::Type *NewTy = ConvertType(Ty); + Addr = Addr.withElementType(NewTy); + } + } + llvm::LoadInst *Load = Builder.CreateLoad(Addr, Volatile); if (isNontemporal) { llvm::MDNode *Node = llvm::MDNode::get( diff --git a/clang/lib/CodeGen/CGExprConstant.cpp b/clang/lib/CodeGen/CGExprConstant.cpp index 94962091116a..98ab1e23d128 100644 --- a/clang/lib/CodeGen/CGExprConstant.cpp +++ b/clang/lib/CodeGen/CGExprConstant.cpp @@ -1774,6 +1774,18 @@ llvm::Constant *ConstantEmitter::emitForMemory(CodeGenModule &CGM, return Res; } + if (const auto *BIT = destType->getAs<BitIntType>()) { + if (BIT->getNumBits() > 128) { + // Long _BitInt has array of bytes as in-memory type. + ConstantAggregateBuilder Builder(CGM); + llvm::Type *DesiredTy = CGM.getTypes().ConvertTypeForMem(destType); + auto *CI = cast<llvm::ConstantInt>(C); + llvm::APInt Value = CI->getValue(); + Builder.addBits(Value, /*OffsetInBits=*/0, /*AllowOverwrite=*/false); + return Builder.build(DesiredTy, /*AllowOversized*/ false); + } + } + return C; } diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp index d84531959b50..717d47d20dea 100644 --- a/clang/lib/CodeGen/CGExprScalar.cpp +++ b/clang/lib/CodeGen/CGExprScalar.cpp @@ -5348,6 +5348,13 @@ Value *ScalarExprEmitter::VisitVAArgExpr(VAArgExpr *VE) { return llvm::UndefValue::get(ArgTy); } + if (const auto *BIT = Ty->getAs<BitIntType>()) { + if (BIT->getNumBits() > 128) { + // Long _BitInt has array of bytes as in-memory type. + ArgPtr = ArgPtr.withElementType(ArgTy); + } + } + // FIXME Volatility. llvm::Value *Val = Builder.CreateLoad(ArgPtr); diff --git a/clang/lib/CodeGen/CodeGenTypes.cpp b/clang/lib/CodeGen/CodeGenTypes.cpp index e8d75eda029e..55c618677ddb 100644 --- a/clang/lib/CodeGen/CodeGenTypes.cpp +++ b/clang/lib/CodeGen/CodeGenTypes.cpp @@ -114,6 +114,12 @@ llvm::Type *CodeGenTypes::ConvertTypeForMem(QualType T, bool ForBitField) { return llvm::IntegerType::get(getLLVMContext(), (unsigned)Context.getTypeSize(T)); + if (const auto *BIT = T->getAs<BitIntType>()) { + if (BIT->getNumBits() > 128) + R = llvm::ArrayType::get(CGM.Int8Ty, + (unsigned)Context.getTypeSize(T) / 8); + } + // Else, don't map it. return R; } diff --git a/clang/test/CodeGen/ext-int-cc.c b/clang/test/CodeGen/ext-int-cc.c index 001e866d34b4..83f20dcb0667 100644 --- a/clang/test/CodeGen/ext-int-cc.c +++ b/clang/test/CodeGen/ext-int-cc.c @@ -131,7 +131,7 @@ void ParamPassing3(_BitInt(15) a, _BitInt(31) b) {} // are negated. This will give an error when a target does support larger // _BitInt widths to alert us to enable the test. void ParamPassing4(_BitInt(129) a) {} -// LIN64: define{{.*}} void @ParamPassing4(ptr byval(i129) align 8 %{{.+}}) +// LIN64: define{{.*}} void @ParamPassing4(ptr byval([24 x i8]) align 8 %{{.+}}) // WIN64: define dso_local void @ParamPassing4(ptr %{{.+}}) // LIN32: define{{.*}} void @ParamPassing4(ptr %{{.+}}) // WIN32: define dso_local void @ParamPassing4(ptr %{{.+}}) diff --git a/clang/test/CodeGen/ext-int.c b/clang/test/CodeGen/ext-int.c index 4cb399d108f2..a6a632bd985d 100644 --- a/clang/test/CodeGen/ext-int.c +++ b/clang/test/CodeGen/ext-int.c @@ -1,12 +1,19 @@ -// RUN: %clang_cc1 -triple x86_64-gnu-linux -O3 -disable-llvm-passes -emit-llvm -o - %s | FileCheck %s --check-prefixes=CHECK,CHECK64 -// RUN: %clang_cc1 -triple x86_64-windows-pc -O3 -disable-llvm-passes -emit-llvm -o - %s | FileCheck %s --check-prefixes=CHECK,CHECK64 -// RUN: %clang_cc1 -triple i386-gnu-linux -O3 -disable-llvm-passes -emit-llvm -o - %s | FileCheck %s --check-prefixes=CHECK,LIN32 -// RUN: %clang_cc1 -triple i386-windows-pc -O3 -disable-llvm-passes -emit-llvm -o - %s | FileCheck %s --check-prefixes=CHECK,WIN32 +// RUN: %clang_cc1 -std=c23 -triple x86_64-gnu-linux -O3 -disable-llvm-passes -emit-llvm -o - %s | FileCheck %s --check-prefixes=CHECK,CHECK64 +// RUN: %clang_cc1 -std=c23 -triple x86_64-windows-pc -O3 -disable-llvm-passes -emit-llvm -o - %s | FileCheck %s --check-prefixes=CHECK,CHECK64 +// RUN: %clang_cc1 -std=c23 -triple i386-gnu-linux -O3 -disable-llvm-passes -emit-llvm -o - %s | FileCheck %s --check-prefixes=CHECK,LIN32 +// RUN: %clang_cc1 -std=c23 -triple i386-windows-pc -O3 -disable-llvm-passes -emit-llvm -o - %s | FileCheck %s --check-prefixes=CHECK,WIN32 + +// CHECK64: %struct.S1 = type { i17, [4 x i8], [24 x i8] } +// CHECK64: %struct.S2 = type { [40 x i8], i32, [4 x i8] } //GH62207 unsigned _BitInt(1) GlobSize1 = 0; // CHECK: @GlobSize1 = {{.*}}global i1 false +// CHECK64: @__const.foo.A = private unnamed_addr constant { i17, [4 x i8], <{ i8, [23 x i8] }> } { i17 1, [4 x i8] undef, <{ i8, [23 x i8] }> <{ i8 -86, [23 x i8] zeroinitializer }> }, align 8 +// CHECK64: @BigGlob = {{.*}}global <{ i8, i8, [38 x i8] }> <{ i8 -68, i8 2, [38 x i8] zeroinitializer }>, align 8 +// CHECK64: @f.p = internal global <{ i8, i8, [22 x i8] }> <{ i8 16, i8 39, [22 x i8] zeroinitializer }>, align 8 + void GenericTest(_BitInt(3) a, unsigned _BitInt(3) b, _BitInt(4) c) { // CHECK: define {{.*}}void @GenericTest int which = _Generic(a, _BitInt(3): 1, unsigned _BitInt(3) : 2, _BitInt(4) : 3); @@ -62,3 +69,85 @@ void Size1ExtIntParam(unsigned _BitInt(1) A) { // CHECK: store i1 %[[PARAM_LOAD]], ptr %[[IDX]] B[2] = A; } + +#if __BITINT_MAXWIDTH__ > 128 +struct S1 { + _BitInt(17) A; + _BitInt(129) B; +}; + +int foo(int a) { + // CHECK64: %A1 = getelementptr inbounds %struct.S1, ptr %B, i32 0, i32 0 + // CHECK64: store i17 1, ptr %A1, align 8 + // CHECK64: %B2 = getelementptr inbounds %struct.S1, ptr %B, i32 0, i32 2 + // CHECK64: %0 = load i32, ptr %a.addr, align 4 + // CHECK64: %conv = sext i32 %0 to i129 + // CHECK64: store i129 %conv, ptr %B2, align 8 + // CHECK64: %B3 = getelementptr inbounds %struct.S1, ptr %A, i32 0, i32 2 + // CHECK64: %1 = load i129, ptr %B3, align 8 + // CHECK64: %conv4 = trunc i129 %1 to i32 + // CHECK64: %B5 = getelementptr inbounds %struct.S1, ptr %B, i32 0, i32 2 + // CHECK64: %2 = load i129, ptr %B5, align 8 + struct S1 A = {1, 170}; + struct S1 B = {1, a}; + return (int)A.B + (int)B.B; +} + +struct S2 { + _BitInt(257) A; + int B; +}; + +_BitInt(257) bar() { + // CHECK64: define {{.*}}void @bar(ptr {{.*}} sret([40 x i8]) align 8 %[[RET:.+]]) + // CHECK64: %A = alloca %struct.S2, align 8 + // CHECK64: %0 = getelementptr inbounds { <{ i8, [39 x i8] }>, i32, [4 x i8] }, ptr %A, i32 0, i32 0 + // CHECK64: %1 = getelementptr inbounds <{ i8, [39 x i8] }>, ptr %0, i32 0, i32 0 + // CHECK64: store i8 1, ptr %1, align 8 + // CHECK64: %2 = getelementptr inbounds { <{ i8, [39 x i8] }>, i32, [4 x i8] }, ptr %A, i32 0, i32 1 + // CHECK64: store i32 10000, ptr %2, align 8 + // CHECK64: %A1 = getelementptr inbounds %struct.S2, ptr %A, i32 0, i32 0 + // CHECK64: %3 = load i257, ptr %A1, align 8 + // CHECK64: store i257 %3, ptr %[[RET]], align 8 + struct S2 A = {1, 10000}; + return A.A; +} + +void TakesVarargs(int i, ...) { + // CHECK64: define{{.*}} void @TakesVarargs(i32 +__builtin_va_list args; +__builtin_va_start(args, i); + +_BitInt(160) A = __builtin_va_arg(args, _BitInt(160)); + // CHECK64: %[[ARG:.+]] = load i160 + // CHECK64: store i160 %[[ARG]], ptr %A, align 8 +} + +_BitInt(129) *f1(_BitInt(129) *p) { + // CHECK64: getelementptr inbounds [24 x i8], {{.*}} i64 1 + return p + 1; +} + +char *f2(char *p) { + // CHECK64: getelementptr inbounds i8, {{.*}} i64 24 + return p + sizeof(_BitInt(129)); +} + +auto BigGlob = (_BitInt(257))700; +// CHECK64: define {{.*}}void @foobar(ptr {{.*}} sret([40 x i8]) align 8 %[[RET1:.+]]) +_BitInt(257) foobar() { + // CHECK64: %A = alloca [40 x i8], align 8 + // CHECK64: %0 = load i257, ptr @BigGlob, align 8 + // CHECK64: %add = add nsw i257 %0, 1 + // CHECK64: store i257 %add, ptr %A, align 8 + // CHECK64: %1 = load i257, ptr %A, align 8 + // CHECK64: store i257 %1, ptr %[[RET1]], align 8 + _BitInt(257) A = BigGlob + 1; + return A; +} + +void f() { + static _BitInt(130) p = {10000}; +} + +#endif `````````` </details> https://github.com/llvm/llvm-project/pull/91364 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits