[clang] [Clang][CodeGen][X86] don't coerce int128 into `{i64,i64}` for SysV-like ABIs (PR #135230)
github-actions[bot] wrote: @T0b1-iOS Congratulations on having your first Pull Request (PR) merged into the LLVM Project! Your changes will be combined with recent changes from other authors, then tested by our [build bots](https://lab.llvm.org/buildbot/). If there is a problem with a build, you may receive a report in an email or a comment on this PR. Please check whether problems have been caused by your change specifically, as the builds can include changes from many authors. It is not uncommon for your change to be included in a build that fails due to someone else's changes, or infrastructure issues. How to do this, and the rest of the post-merge process, is covered in detail [here](https://llvm.org/docs/MyFirstTypoFix.html#myfirsttypofix-issues-after-landing-your-pr). If your change does cause a problem, it may be reverted, or you can revert it yourself. This is a normal part of [LLVM development](https://llvm.org/docs/DeveloperPolicy.html#patch-reversion-policy). You can fix your changes and open a new PR to merge them again. If you don't get any reports, no action is required from you. Your changes are working as expected, well done! https://github.com/llvm/llvm-project/pull/135230 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang][CodeGen][X86] don't coerce int128 into `{i64,i64}` for SysV-like ABIs (PR #135230)
https://github.com/efriedma-quic closed https://github.com/llvm/llvm-project/pull/135230 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang][CodeGen][X86] don't coerce int128 into `{i64,i64}` for SysV-like ABIs (PR #135230)
T0b1-iOS wrote: Fixed. Thanks for the review! As I don't have commit access, could you merge this for me?. And do you think this could be put onto the 21 release branch? I think it should be possible from a policy pov but I think you need to have commit access to make a backport request if I'm reading the docs correctly. https://github.com/llvm/llvm-project/pull/135230 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang][CodeGen][X86] don't coerce int128 into `{i64,i64}` for SysV-like ABIs (PR #135230)
https://github.com/T0b1-iOS updated https://github.com/llvm/llvm-project/pull/135230 >From 16068fb6bce3443b608c6007ae0b9ea4eb18825d Mon Sep 17 00:00:00 2001 From: T0b1 Date: Fri, 11 Jul 2025 01:26:51 +0200 Subject: [PATCH 1/5] [Clang][CodeGen][X86] don't coerce int128 into `{i64,i64}` for SysV-like ABIs --- clang/lib/CodeGen/Targets/X86.cpp | 18 +++ clang/test/CodeGen/X86/i128-debuginfo.c | 10 clang/test/CodeGen/X86/x86_64-arguments.c | 21 clang/test/CodeGen/alloc-align-attr.c | 58 +++ clang/test/CodeGen/builtins.c | 18 ++- clang/test/CodeGen/extend-arg-64.c| 2 +- 6 files changed, 70 insertions(+), 57 deletions(-) create mode 100644 clang/test/CodeGen/X86/i128-debuginfo.c diff --git a/clang/lib/CodeGen/Targets/X86.cpp b/clang/lib/CodeGen/Targets/X86.cpp index 0f59caac2323e..bb90e3611b533 100644 --- a/clang/lib/CodeGen/Targets/X86.cpp +++ b/clang/lib/CodeGen/Targets/X86.cpp @@ -2594,6 +2594,14 @@ GetX86_64ByValArgumentPair(llvm::Type *Lo, llvm::Type *Hi, ABIArgInfo X86_64ABIInfo:: classifyReturnType(QualType RetTy) const { + // return int128 as i128 + if (const BuiltinType *BT = RetTy->getAs()) { +BuiltinType::Kind k = BT->getKind(); +if (k == BuiltinType::Int128 || k == BuiltinType::UInt128) { + return ABIArgInfo::getDirect(); +} + } + // AMD64-ABI 3.2.3p4: Rule 1. Classify the return type with the // classification algorithm. X86_64ABIInfo::Class Lo, Hi; @@ -2726,6 +2734,16 @@ X86_64ABIInfo::classifyArgumentType(QualType Ty, unsigned freeIntRegs, bool isNamedArg, bool IsRegCall) const { Ty = useFirstFieldIfTransparentUnion(Ty); + // represent int128 as i128 + if (const BuiltinType *BT = Ty->getAs()) { +BuiltinType::Kind k = BT->getKind(); +if (k == BuiltinType::Int128 || k == BuiltinType::UInt128) { + neededInt = 2; + neededSSE = 0; + return ABIArgInfo::getDirect(); +} + } + X86_64ABIInfo::Class Lo, Hi; classify(Ty, 0, Lo, Hi, isNamedArg, IsRegCall); diff --git a/clang/test/CodeGen/X86/i128-debuginfo.c b/clang/test/CodeGen/X86/i128-debuginfo.c new file mode 100644 index 0..4b865c1bed9f0 --- /dev/null +++ b/clang/test/CodeGen/X86/i128-debuginfo.c @@ -0,0 +1,10 @@ +// no autogeneration since update_cc_test_checks does not support -g +// RUN: %clang_cc1 -triple x86_64-pc-linux -O1 -debug-info-kind=limited -emit-llvm -o - %s | FileCheck %s + +// CHECK-LABEL: define{{.*}} i128 @add(i128 noundef %a) +// CHECK: #dbg_value(i128 %a, ![[DI:.*]], !DIExpression() +__int128_t add(__int128_t a) { + return a + a; +} + +// CHECK: ![[DI]] = !DILocalVariable(name: "a", arg: 1 diff --git a/clang/test/CodeGen/X86/x86_64-arguments.c b/clang/test/CodeGen/X86/x86_64-arguments.c index 82845f0a2b31f..fd73fbaa8e54f 100644 --- a/clang/test/CodeGen/X86/x86_64-arguments.c +++ b/clang/test/CodeGen/X86/x86_64-arguments.c @@ -551,6 +551,27 @@ struct s68 { void f68(struct s68 x) { } +// CHECK-LABEL: define{{.*}} i128 @f69(i128 noundef %a) +__int128_t f69(__int128_t a) { + return a; +} + +// CHECK-LABEL: define{{.*}} i128 @f70(i128 noundef %a) +__uint128_t f70(__uint128_t a) { + return a; +} + +// check that registers are correctly counted for (u)int128_t arguments +struct s71 { + long long a, b; +}; +// CHECK-LABEL: define{{.*}} void @f71(i128 noundef %a, i128 noundef %b, i64 noundef %c, ptr noundef byval(%struct.s71) align 8 %d) +void f71(__int128_t a, __int128_t b, long long c, struct s71 d) { +} +// CHECK-LABEL: define{{.*}} void @f72(i128 noundef %a, i128 noundef %b, i64 %d.coerce0, i64 %d.coerce1) +void f72(__int128_t a, __int128_t b, struct s71 d) { +} + /// The synthesized __va_list_tag does not have file/line fields. // CHECK: = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "__va_list_tag", // CHECK-NOT: file: diff --git a/clang/test/CodeGen/alloc-align-attr.c b/clang/test/CodeGen/alloc-align-attr.c index 76e5d1041b19f..c4c4e76eaaa04 100644 --- a/clang/test/CodeGen/alloc-align-attr.c +++ b/clang/test/CodeGen/alloc-align-attr.c @@ -70,66 +70,42 @@ __INT32_TYPE__ test4(__SIZE_TYPE__ a) { struct Empty {}; struct MultiArgs { __INT64_TYPE__ a, b;}; -// Struct parameter doesn't take up an IR parameter, 'i' takes up 2. +// Struct parameter doesn't take up an IR parameter, 'i' takes up 1. // Truncation to i64 is permissible, since alignments of greater than 2^64 are insane. __INT32_TYPE__ *m3(struct Empty s, __int128_t i) __attribute__((alloc_align(2))); // CHECK-LABEL: @test5( // CHECK-NEXT: entry: -// CHECK-NEXT:[[A:%.*]] = alloca i128, align 16 // CHECK-NEXT:[[A_ADDR:%.*]] = alloca i128, align 16 // CHECK-NEXT:[[E:%.*]] = alloca [[STRUCT_EMPTY:%.*]], align 1 -// CHECK-NEXT:[[COERCE:%.*]] = alloca i128, align 16 -// CHECK-NEXT:[[TMP0:%.*]] = getelementptr inbounds nuw { i64, i64 }, ptr [[A]], i32 0, i32 0 -// CHECK-NEXT:store i64 [[A_COERCE0:%.*
[clang] [Clang][CodeGen][X86] don't coerce int128 into `{i64,i64}` for SysV-like ABIs (PR #135230)
@@ -2595,6 +2595,14 @@ GetX86_64ByValArgumentPair(llvm::Type *Lo, llvm::Type *Hi, ABIArgInfo X86_64ABIInfo:: classifyReturnType(QualType RetTy) const { + // return int128 as i128 + if (const BuiltinType *BT = RetTy->getAs()) { +BuiltinType::Kind k = BT->getKind(); +if (k == BuiltinType::Int128 || k == BuiltinType::UInt128) { + return ABIArgInfo::getDirect(); +} + } + // AMD64-ABI 3.2.3p4: Rule 1. Classify the return type with the // classification algorithm. X86_64ABIInfo::Class Lo, Hi; T0b1-iOS wrote: @efriedma-quic Okay, the CI problems are fixed now. It seems there was some external problem with libcxx that made its tests fail before. Maybe you could take a look now https://github.com/llvm/llvm-project/pull/135230 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang][CodeGen][X86] don't coerce int128 into `{i64,i64}` for SysV-like ABIs (PR #135230)
@@ -2595,6 +2595,14 @@ GetX86_64ByValArgumentPair(llvm::Type *Lo, llvm::Type *Hi, ABIArgInfo X86_64ABIInfo:: classifyReturnType(QualType RetTy) const { + // return int128 as i128 + if (const BuiltinType *BT = RetTy->getAs()) { +BuiltinType::Kind k = BT->getKind(); +if (k == BuiltinType::Int128 || k == BuiltinType::UInt128) { + return ABIArgInfo::getDirect(); +} + } + // AMD64-ABI 3.2.3p4: Rule 1. Classify the return type with the // classification algorithm. X86_64ABIInfo::Class Lo, Hi; T0b1-iOS wrote: No problem. I changed it to now do an early return. Is that better? I don't think the CI ran again so maybe you need to approve it running or something? https://github.com/llvm/llvm-project/pull/135230 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang][CodeGen][X86] don't coerce int128 into `{i64,i64}` for SysV-like ABIs (PR #135230)
https://github.com/T0b1-iOS updated https://github.com/llvm/llvm-project/pull/135230 >From 36ee902227e66c24cd7de42ed6a26637f440b4a3 Mon Sep 17 00:00:00 2001 From: T0b1 Date: Thu, 10 Apr 2025 19:16:00 +0200 Subject: [PATCH 1/4] [Clang][CodeGen][X86] don't coerce int128 into `{i64,i64}` for SysV-like ABIs --- clang/lib/CodeGen/Targets/X86.cpp | 18 +++ clang/test/CodeGen/X86/i128-debuginfo.c | 10 clang/test/CodeGen/X86/x86_64-arguments.c | 21 clang/test/CodeGen/alloc-align-attr.c | 58 +++ clang/test/CodeGen/builtins.c | 18 ++- clang/test/CodeGen/extend-arg-64.c| 2 +- 6 files changed, 70 insertions(+), 57 deletions(-) create mode 100644 clang/test/CodeGen/X86/i128-debuginfo.c diff --git a/clang/lib/CodeGen/Targets/X86.cpp b/clang/lib/CodeGen/Targets/X86.cpp index 0f59caac2323e..bb90e3611b533 100644 --- a/clang/lib/CodeGen/Targets/X86.cpp +++ b/clang/lib/CodeGen/Targets/X86.cpp @@ -2594,6 +2594,14 @@ GetX86_64ByValArgumentPair(llvm::Type *Lo, llvm::Type *Hi, ABIArgInfo X86_64ABIInfo:: classifyReturnType(QualType RetTy) const { + // return int128 as i128 + if (const BuiltinType *BT = RetTy->getAs()) { +BuiltinType::Kind k = BT->getKind(); +if (k == BuiltinType::Int128 || k == BuiltinType::UInt128) { + return ABIArgInfo::getDirect(); +} + } + // AMD64-ABI 3.2.3p4: Rule 1. Classify the return type with the // classification algorithm. X86_64ABIInfo::Class Lo, Hi; @@ -2726,6 +2734,16 @@ X86_64ABIInfo::classifyArgumentType(QualType Ty, unsigned freeIntRegs, bool isNamedArg, bool IsRegCall) const { Ty = useFirstFieldIfTransparentUnion(Ty); + // represent int128 as i128 + if (const BuiltinType *BT = Ty->getAs()) { +BuiltinType::Kind k = BT->getKind(); +if (k == BuiltinType::Int128 || k == BuiltinType::UInt128) { + neededInt = 2; + neededSSE = 0; + return ABIArgInfo::getDirect(); +} + } + X86_64ABIInfo::Class Lo, Hi; classify(Ty, 0, Lo, Hi, isNamedArg, IsRegCall); diff --git a/clang/test/CodeGen/X86/i128-debuginfo.c b/clang/test/CodeGen/X86/i128-debuginfo.c new file mode 100644 index 0..4b865c1bed9f0 --- /dev/null +++ b/clang/test/CodeGen/X86/i128-debuginfo.c @@ -0,0 +1,10 @@ +// no autogeneration since update_cc_test_checks does not support -g +// RUN: %clang_cc1 -triple x86_64-pc-linux -O1 -debug-info-kind=limited -emit-llvm -o - %s | FileCheck %s + +// CHECK-LABEL: define{{.*}} i128 @add(i128 noundef %a) +// CHECK: #dbg_value(i128 %a, ![[DI:.*]], !DIExpression() +__int128_t add(__int128_t a) { + return a + a; +} + +// CHECK: ![[DI]] = !DILocalVariable(name: "a", arg: 1 diff --git a/clang/test/CodeGen/X86/x86_64-arguments.c b/clang/test/CodeGen/X86/x86_64-arguments.c index 82845f0a2b31f..fd73fbaa8e54f 100644 --- a/clang/test/CodeGen/X86/x86_64-arguments.c +++ b/clang/test/CodeGen/X86/x86_64-arguments.c @@ -551,6 +551,27 @@ struct s68 { void f68(struct s68 x) { } +// CHECK-LABEL: define{{.*}} i128 @f69(i128 noundef %a) +__int128_t f69(__int128_t a) { + return a; +} + +// CHECK-LABEL: define{{.*}} i128 @f70(i128 noundef %a) +__uint128_t f70(__uint128_t a) { + return a; +} + +// check that registers are correctly counted for (u)int128_t arguments +struct s71 { + long long a, b; +}; +// CHECK-LABEL: define{{.*}} void @f71(i128 noundef %a, i128 noundef %b, i64 noundef %c, ptr noundef byval(%struct.s71) align 8 %d) +void f71(__int128_t a, __int128_t b, long long c, struct s71 d) { +} +// CHECK-LABEL: define{{.*}} void @f72(i128 noundef %a, i128 noundef %b, i64 %d.coerce0, i64 %d.coerce1) +void f72(__int128_t a, __int128_t b, struct s71 d) { +} + /// The synthesized __va_list_tag does not have file/line fields. // CHECK: = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "__va_list_tag", // CHECK-NOT: file: diff --git a/clang/test/CodeGen/alloc-align-attr.c b/clang/test/CodeGen/alloc-align-attr.c index 76e5d1041b19f..c4c4e76eaaa04 100644 --- a/clang/test/CodeGen/alloc-align-attr.c +++ b/clang/test/CodeGen/alloc-align-attr.c @@ -70,66 +70,42 @@ __INT32_TYPE__ test4(__SIZE_TYPE__ a) { struct Empty {}; struct MultiArgs { __INT64_TYPE__ a, b;}; -// Struct parameter doesn't take up an IR parameter, 'i' takes up 2. +// Struct parameter doesn't take up an IR parameter, 'i' takes up 1. // Truncation to i64 is permissible, since alignments of greater than 2^64 are insane. __INT32_TYPE__ *m3(struct Empty s, __int128_t i) __attribute__((alloc_align(2))); // CHECK-LABEL: @test5( // CHECK-NEXT: entry: -// CHECK-NEXT:[[A:%.*]] = alloca i128, align 16 // CHECK-NEXT:[[A_ADDR:%.*]] = alloca i128, align 16 // CHECK-NEXT:[[E:%.*]] = alloca [[STRUCT_EMPTY:%.*]], align 1 -// CHECK-NEXT:[[COERCE:%.*]] = alloca i128, align 16 -// CHECK-NEXT:[[TMP0:%.*]] = getelementptr inbounds nuw { i64, i64 }, ptr [[A]], i32 0, i32 0 -// CHECK-NEXT:store i64 [[A_COERCE0:%.*
[clang] [Clang][CodeGen][X86] don't coerce int128 into `{i64,i64}` for SysV-like ABIs (PR #135230)
@@ -2595,6 +2595,14 @@ GetX86_64ByValArgumentPair(llvm::Type *Lo, llvm::Type *Hi, ABIArgInfo X86_64ABIInfo:: classifyReturnType(QualType RetTy) const { + // return int128 as i128 + if (const BuiltinType *BT = RetTy->getAs()) { +BuiltinType::Kind k = BT->getKind(); +if (k == BuiltinType::Int128 || k == BuiltinType::UInt128) { + return ABIArgInfo::getDirect(); +} + } + // AMD64-ABI 3.2.3p4: Rule 1. Classify the return type with the // classification algorithm. X86_64ABIInfo::Class Lo, Hi; efriedma-quic wrote: Sorry about the delay here. I think this does the right thing, but in a pretty unintuitive way; I had to read through the code multiple times to convince myself this actually works the way it's supposed to. I'd rather not have GetINTEGERTypeAtOffset return nullptr; instead, the callers of GetINTEGERTypeAtOffset should explicitly check for an i128 return type, and return early. And assert `Hi == Integer`. https://github.com/llvm/llvm-project/pull/135230 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang][CodeGen][X86] don't coerce int128 into `{i64,i64}` for SysV-like ABIs (PR #135230)
@@ -2595,6 +2595,14 @@ GetX86_64ByValArgumentPair(llvm::Type *Lo, llvm::Type *Hi, ABIArgInfo X86_64ABIInfo:: classifyReturnType(QualType RetTy) const { + // return int128 as i128 + if (const BuiltinType *BT = RetTy->getAs()) { +BuiltinType::Kind k = BT->getKind(); +if (k == BuiltinType::Int128 || k == BuiltinType::UInt128) { + return ABIArgInfo::getDirect(); +} + } + // AMD64-ABI 3.2.3p4: Rule 1. Classify the return type with the // classification algorithm. X86_64ABIInfo::Class Lo, Hi; T0b1-iOS wrote: @efriedma-quic ping https://github.com/llvm/llvm-project/pull/135230 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang][CodeGen][X86] don't coerce int128 into `{i64,i64}` for SysV-like ABIs (PR #135230)
https://github.com/T0b1-iOS edited https://github.com/llvm/llvm-project/pull/135230 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang][CodeGen][X86] don't coerce int128 into `{i64,i64}` for SysV-like ABIs (PR #135230)
@@ -2595,6 +2595,14 @@ GetX86_64ByValArgumentPair(llvm::Type *Lo, llvm::Type *Hi, ABIArgInfo X86_64ABIInfo:: classifyReturnType(QualType RetTy) const { + // return int128 as i128 + if (const BuiltinType *BT = RetTy->getAs()) { +BuiltinType::Kind k = BT->getKind(); +if (k == BuiltinType::Int128 || k == BuiltinType::UInt128) { + return ABIArgInfo::getDirect(); +} + } + // AMD64-ABI 3.2.3p4: Rule 1. Classify the return type with the // classification algorithm. X86_64ABIInfo::Class Lo, Hi; T0b1-iOS wrote: @efriedma-quic ping. Would this be okay now? https://github.com/llvm/llvm-project/pull/135230 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang][CodeGen][X86] don't coerce int128 into `{i64,i64}` for SysV-like ABIs (PR #135230)
https://github.com/T0b1-iOS updated https://github.com/llvm/llvm-project/pull/135230 >From f0bb89e5cfe2739dc51faef64215251cfe1516d4 Mon Sep 17 00:00:00 2001 From: T0b1 Date: Thu, 10 Apr 2025 19:16:00 +0200 Subject: [PATCH 1/3] [Clang][CodeGen][X86] don't coerce int128 into `{i64,i64}` for SysV-like ABIs --- clang/lib/CodeGen/Targets/X86.cpp | 18 +++ clang/test/CodeGen/X86/i128-debuginfo.c | 10 clang/test/CodeGen/X86/x86_64-arguments.c | 21 clang/test/CodeGen/alloc-align-attr.c | 58 +++ clang/test/CodeGen/builtins.c | 18 ++- clang/test/CodeGen/extend-arg-64.c| 2 +- 6 files changed, 70 insertions(+), 57 deletions(-) create mode 100644 clang/test/CodeGen/X86/i128-debuginfo.c diff --git a/clang/lib/CodeGen/Targets/X86.cpp b/clang/lib/CodeGen/Targets/X86.cpp index b36a6e1396653..aa4ab1c2e5490 100644 --- a/clang/lib/CodeGen/Targets/X86.cpp +++ b/clang/lib/CodeGen/Targets/X86.cpp @@ -2595,6 +2595,14 @@ GetX86_64ByValArgumentPair(llvm::Type *Lo, llvm::Type *Hi, ABIArgInfo X86_64ABIInfo:: classifyReturnType(QualType RetTy) const { + // return int128 as i128 + if (const BuiltinType *BT = RetTy->getAs()) { +BuiltinType::Kind k = BT->getKind(); +if (k == BuiltinType::Int128 || k == BuiltinType::UInt128) { + return ABIArgInfo::getDirect(); +} + } + // AMD64-ABI 3.2.3p4: Rule 1. Classify the return type with the // classification algorithm. X86_64ABIInfo::Class Lo, Hi; @@ -2727,6 +2735,16 @@ X86_64ABIInfo::classifyArgumentType(QualType Ty, unsigned freeIntRegs, bool isNamedArg, bool IsRegCall) const { Ty = useFirstFieldIfTransparentUnion(Ty); + // represent int128 as i128 + if (const BuiltinType *BT = Ty->getAs()) { +BuiltinType::Kind k = BT->getKind(); +if (k == BuiltinType::Int128 || k == BuiltinType::UInt128) { + neededInt = 2; + neededSSE = 0; + return ABIArgInfo::getDirect(); +} + } + X86_64ABIInfo::Class Lo, Hi; classify(Ty, 0, Lo, Hi, isNamedArg, IsRegCall); diff --git a/clang/test/CodeGen/X86/i128-debuginfo.c b/clang/test/CodeGen/X86/i128-debuginfo.c new file mode 100644 index 0..4b865c1bed9f0 --- /dev/null +++ b/clang/test/CodeGen/X86/i128-debuginfo.c @@ -0,0 +1,10 @@ +// no autogeneration since update_cc_test_checks does not support -g +// RUN: %clang_cc1 -triple x86_64-pc-linux -O1 -debug-info-kind=limited -emit-llvm -o - %s | FileCheck %s + +// CHECK-LABEL: define{{.*}} i128 @add(i128 noundef %a) +// CHECK: #dbg_value(i128 %a, ![[DI:.*]], !DIExpression() +__int128_t add(__int128_t a) { + return a + a; +} + +// CHECK: ![[DI]] = !DILocalVariable(name: "a", arg: 1 diff --git a/clang/test/CodeGen/X86/x86_64-arguments.c b/clang/test/CodeGen/X86/x86_64-arguments.c index 82845f0a2b31f..fd73fbaa8e54f 100644 --- a/clang/test/CodeGen/X86/x86_64-arguments.c +++ b/clang/test/CodeGen/X86/x86_64-arguments.c @@ -551,6 +551,27 @@ struct s68 { void f68(struct s68 x) { } +// CHECK-LABEL: define{{.*}} i128 @f69(i128 noundef %a) +__int128_t f69(__int128_t a) { + return a; +} + +// CHECK-LABEL: define{{.*}} i128 @f70(i128 noundef %a) +__uint128_t f70(__uint128_t a) { + return a; +} + +// check that registers are correctly counted for (u)int128_t arguments +struct s71 { + long long a, b; +}; +// CHECK-LABEL: define{{.*}} void @f71(i128 noundef %a, i128 noundef %b, i64 noundef %c, ptr noundef byval(%struct.s71) align 8 %d) +void f71(__int128_t a, __int128_t b, long long c, struct s71 d) { +} +// CHECK-LABEL: define{{.*}} void @f72(i128 noundef %a, i128 noundef %b, i64 %d.coerce0, i64 %d.coerce1) +void f72(__int128_t a, __int128_t b, struct s71 d) { +} + /// The synthesized __va_list_tag does not have file/line fields. // CHECK: = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "__va_list_tag", // CHECK-NOT: file: diff --git a/clang/test/CodeGen/alloc-align-attr.c b/clang/test/CodeGen/alloc-align-attr.c index 76e5d1041b19f..c4c4e76eaaa04 100644 --- a/clang/test/CodeGen/alloc-align-attr.c +++ b/clang/test/CodeGen/alloc-align-attr.c @@ -70,66 +70,42 @@ __INT32_TYPE__ test4(__SIZE_TYPE__ a) { struct Empty {}; struct MultiArgs { __INT64_TYPE__ a, b;}; -// Struct parameter doesn't take up an IR parameter, 'i' takes up 2. +// Struct parameter doesn't take up an IR parameter, 'i' takes up 1. // Truncation to i64 is permissible, since alignments of greater than 2^64 are insane. __INT32_TYPE__ *m3(struct Empty s, __int128_t i) __attribute__((alloc_align(2))); // CHECK-LABEL: @test5( // CHECK-NEXT: entry: -// CHECK-NEXT:[[A:%.*]] = alloca i128, align 16 // CHECK-NEXT:[[A_ADDR:%.*]] = alloca i128, align 16 // CHECK-NEXT:[[E:%.*]] = alloca [[STRUCT_EMPTY:%.*]], align 1 -// CHECK-NEXT:[[COERCE:%.*]] = alloca i128, align 16 -// CHECK-NEXT:[[TMP0:%.*]] = getelementptr inbounds nuw { i64, i64 }, ptr [[A]], i32 0, i32 0 -// CHECK-NEXT:store i64 [[A_COERCE0:%.*
[clang] [Clang][CodeGen][X86] don't coerce int128 into `{i64,i64}` for SysV-like ABIs (PR #135230)
@@ -2595,6 +2595,14 @@ GetX86_64ByValArgumentPair(llvm::Type *Lo, llvm::Type *Hi, ABIArgInfo X86_64ABIInfo:: classifyReturnType(QualType RetTy) const { + // return int128 as i128 + if (const BuiltinType *BT = RetTy->getAs()) { +BuiltinType::Kind k = BT->getKind(); +if (k == BuiltinType::Int128 || k == BuiltinType::UInt128) { + return ABIArgInfo::getDirect(); +} + } + // AMD64-ABI 3.2.3p4: Rule 1. Classify the return type with the // classification algorithm. X86_64ABIInfo::Class Lo, Hi; T0b1-iOS wrote: I changed GetINTEGERTypeAtOffset to return an i128 when appropriate. That also causes _BitInt(128) to be passed as an i128 but that should be fine as long as it doesn't change how it is passed on the stack. https://github.com/llvm/llvm-project/pull/135230 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang][CodeGen][X86] don't coerce int128 into `{i64,i64}` for SysV-like ABIs (PR #135230)
https://github.com/T0b1-iOS updated https://github.com/llvm/llvm-project/pull/135230 >From f0bb89e5cfe2739dc51faef64215251cfe1516d4 Mon Sep 17 00:00:00 2001 From: T0b1 Date: Thu, 10 Apr 2025 19:16:00 +0200 Subject: [PATCH 1/2] [Clang][CodeGen][X86] don't coerce int128 into `{i64,i64}` for SysV-like ABIs --- clang/lib/CodeGen/Targets/X86.cpp | 18 +++ clang/test/CodeGen/X86/i128-debuginfo.c | 10 clang/test/CodeGen/X86/x86_64-arguments.c | 21 clang/test/CodeGen/alloc-align-attr.c | 58 +++ clang/test/CodeGen/builtins.c | 18 ++- clang/test/CodeGen/extend-arg-64.c| 2 +- 6 files changed, 70 insertions(+), 57 deletions(-) create mode 100644 clang/test/CodeGen/X86/i128-debuginfo.c diff --git a/clang/lib/CodeGen/Targets/X86.cpp b/clang/lib/CodeGen/Targets/X86.cpp index b36a6e1396653..aa4ab1c2e5490 100644 --- a/clang/lib/CodeGen/Targets/X86.cpp +++ b/clang/lib/CodeGen/Targets/X86.cpp @@ -2595,6 +2595,14 @@ GetX86_64ByValArgumentPair(llvm::Type *Lo, llvm::Type *Hi, ABIArgInfo X86_64ABIInfo:: classifyReturnType(QualType RetTy) const { + // return int128 as i128 + if (const BuiltinType *BT = RetTy->getAs()) { +BuiltinType::Kind k = BT->getKind(); +if (k == BuiltinType::Int128 || k == BuiltinType::UInt128) { + return ABIArgInfo::getDirect(); +} + } + // AMD64-ABI 3.2.3p4: Rule 1. Classify the return type with the // classification algorithm. X86_64ABIInfo::Class Lo, Hi; @@ -2727,6 +2735,16 @@ X86_64ABIInfo::classifyArgumentType(QualType Ty, unsigned freeIntRegs, bool isNamedArg, bool IsRegCall) const { Ty = useFirstFieldIfTransparentUnion(Ty); + // represent int128 as i128 + if (const BuiltinType *BT = Ty->getAs()) { +BuiltinType::Kind k = BT->getKind(); +if (k == BuiltinType::Int128 || k == BuiltinType::UInt128) { + neededInt = 2; + neededSSE = 0; + return ABIArgInfo::getDirect(); +} + } + X86_64ABIInfo::Class Lo, Hi; classify(Ty, 0, Lo, Hi, isNamedArg, IsRegCall); diff --git a/clang/test/CodeGen/X86/i128-debuginfo.c b/clang/test/CodeGen/X86/i128-debuginfo.c new file mode 100644 index 0..4b865c1bed9f0 --- /dev/null +++ b/clang/test/CodeGen/X86/i128-debuginfo.c @@ -0,0 +1,10 @@ +// no autogeneration since update_cc_test_checks does not support -g +// RUN: %clang_cc1 -triple x86_64-pc-linux -O1 -debug-info-kind=limited -emit-llvm -o - %s | FileCheck %s + +// CHECK-LABEL: define{{.*}} i128 @add(i128 noundef %a) +// CHECK: #dbg_value(i128 %a, ![[DI:.*]], !DIExpression() +__int128_t add(__int128_t a) { + return a + a; +} + +// CHECK: ![[DI]] = !DILocalVariable(name: "a", arg: 1 diff --git a/clang/test/CodeGen/X86/x86_64-arguments.c b/clang/test/CodeGen/X86/x86_64-arguments.c index 82845f0a2b31f..fd73fbaa8e54f 100644 --- a/clang/test/CodeGen/X86/x86_64-arguments.c +++ b/clang/test/CodeGen/X86/x86_64-arguments.c @@ -551,6 +551,27 @@ struct s68 { void f68(struct s68 x) { } +// CHECK-LABEL: define{{.*}} i128 @f69(i128 noundef %a) +__int128_t f69(__int128_t a) { + return a; +} + +// CHECK-LABEL: define{{.*}} i128 @f70(i128 noundef %a) +__uint128_t f70(__uint128_t a) { + return a; +} + +// check that registers are correctly counted for (u)int128_t arguments +struct s71 { + long long a, b; +}; +// CHECK-LABEL: define{{.*}} void @f71(i128 noundef %a, i128 noundef %b, i64 noundef %c, ptr noundef byval(%struct.s71) align 8 %d) +void f71(__int128_t a, __int128_t b, long long c, struct s71 d) { +} +// CHECK-LABEL: define{{.*}} void @f72(i128 noundef %a, i128 noundef %b, i64 %d.coerce0, i64 %d.coerce1) +void f72(__int128_t a, __int128_t b, struct s71 d) { +} + /// The synthesized __va_list_tag does not have file/line fields. // CHECK: = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "__va_list_tag", // CHECK-NOT: file: diff --git a/clang/test/CodeGen/alloc-align-attr.c b/clang/test/CodeGen/alloc-align-attr.c index 76e5d1041b19f..c4c4e76eaaa04 100644 --- a/clang/test/CodeGen/alloc-align-attr.c +++ b/clang/test/CodeGen/alloc-align-attr.c @@ -70,66 +70,42 @@ __INT32_TYPE__ test4(__SIZE_TYPE__ a) { struct Empty {}; struct MultiArgs { __INT64_TYPE__ a, b;}; -// Struct parameter doesn't take up an IR parameter, 'i' takes up 2. +// Struct parameter doesn't take up an IR parameter, 'i' takes up 1. // Truncation to i64 is permissible, since alignments of greater than 2^64 are insane. __INT32_TYPE__ *m3(struct Empty s, __int128_t i) __attribute__((alloc_align(2))); // CHECK-LABEL: @test5( // CHECK-NEXT: entry: -// CHECK-NEXT:[[A:%.*]] = alloca i128, align 16 // CHECK-NEXT:[[A_ADDR:%.*]] = alloca i128, align 16 // CHECK-NEXT:[[E:%.*]] = alloca [[STRUCT_EMPTY:%.*]], align 1 -// CHECK-NEXT:[[COERCE:%.*]] = alloca i128, align 16 -// CHECK-NEXT:[[TMP0:%.*]] = getelementptr inbounds nuw { i64, i64 }, ptr [[A]], i32 0, i32 0 -// CHECK-NEXT:store i64 [[A_COERCE0:%.*
[clang] [Clang][CodeGen][X86] don't coerce int128 into `{i64,i64}` for SysV-like ABIs (PR #135230)
jmorse wrote: > To solve this problem in general, it would probably(?) be best to make SROA > create fragment #dbg_value records if it decomposes an alloca into multiple > IR values but I have no idea how difficult that would be to accomplish. An example of this happening today with C++ structured bindings is here: https://godbolt.org/z/rn3os13M7 . Specifically, the i64 return value from "f", a squashed-together pair of i32s, is decomposed into two `#dbg_value`s corresponding to the two variables that the structured-binding assigns to. Each `#dbg_value` refers to different IR Values, which seems similar to what's desired here. The major difference is that structured bindings have independent source variables contained within one alloca; wheras the situation here is one source variable being split into fragments. https://github.com/llvm/llvm-project/pull/135230 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang][CodeGen][X86] don't coerce int128 into `{i64,i64}` for SysV-like ABIs (PR #135230)
@@ -2595,6 +2595,14 @@ GetX86_64ByValArgumentPair(llvm::Type *Lo, llvm::Type *Hi, ABIArgInfo X86_64ABIInfo:: classifyReturnType(QualType RetTy) const { + // return int128 as i128 + if (const BuiltinType *BT = RetTy->getAs()) { +BuiltinType::Kind k = BT->getKind(); +if (k == BuiltinType::Int128 || k == BuiltinType::UInt128) { + return ABIArgInfo::getDirect(); +} + } + // AMD64-ABI 3.2.3p4: Rule 1. Classify the return type with the // classification algorithm. X86_64ABIInfo::Class Lo, Hi; efriedma-quic wrote: Something like that, yes. Or maybe it's simpler to do it in a separate function; whatever's more readable. https://github.com/llvm/llvm-project/pull/135230 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang][CodeGen][X86] don't coerce int128 into `{i64,i64}` for SysV-like ABIs (PR #135230)
T0b1-iOS wrote: > Maybe a bad suggestion, I have not looked into the implementation, but at the > point where the i128 gets split into two i64s, could we already update the > #dbg_value there to use fragments? At that point we have all the required > information, and it sounds like it would avoid the problem since there is > then no longer any larger-than-i64 debug info to cause poison? I think would be possible but currently the code that inserts the `#dbg_declare` records (`CodeGenFunction::EmitParmDecl`) is oblivious to the splitting. It only gets handed the `i128` value that is loaded from the temporary `{i64, i64}` alloca (created in `CodeGenFunction::EmitFunctionProlog`) where both `i64` arguments are stored into. Thus you would need to add debug handling code into the part that creates the temporary alloca which would require a refactoring of the way debug info metadata is created because the code responsible for that currently creates the `#dbg_declare` records together with the metadata (c.f. `CGDebugInfo::EmitDeclare`). Passing as i128 seems like the better choice in that case. To solve this problem in general, it would probably(?) be best to make SROA create fragment `#dbg_value` records if it decomposes an alloca into multiple IR values but I have no idea how difficult that would be to accomplish. > Presumably the desire here is to improve the variable availability of > parameters rather than fully supporting i128's through LLVM debug-info Yes, at least my primary motivation is for me to be able to retrieve the registers the parameter is passed in without having to rely on any crude heuristics. https://github.com/llvm/llvm-project/pull/135230 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang][CodeGen][X86] don't coerce int128 into `{i64,i64}` for SysV-like ABIs (PR #135230)
@@ -2595,6 +2595,14 @@ GetX86_64ByValArgumentPair(llvm::Type *Lo, llvm::Type *Hi, ABIArgInfo X86_64ABIInfo:: classifyReturnType(QualType RetTy) const { + // return int128 as i128 + if (const BuiltinType *BT = RetTy->getAs()) { +BuiltinType::Kind k = BT->getKind(); +if (k == BuiltinType::Int128 || k == BuiltinType::UInt128) { + return ABIArgInfo::getDirect(); +} + } + // AMD64-ABI 3.2.3p4: Rule 1. Classify the return type with the // classification algorithm. X86_64ABIInfo::Class Lo, Hi; T0b1-iOS wrote: I suppose you could make GetINTEGERTypeAtOffset return an i128 if it sees an i128 as the IRType and IROffset is 0 but then you need to check if it did that in classifyArgumentType and return immediately or make GetINTEGERTypeAtOffset return nullptr if the IROffset is >0 to prevent it from creating an aggregate argument? The latter seems like something one could easily trip over though https://github.com/llvm/llvm-project/pull/135230 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang][CodeGen][X86] don't coerce int128 into `{i64,i64}` for SysV-like ABIs (PR #135230)
@@ -2595,6 +2595,14 @@ GetX86_64ByValArgumentPair(llvm::Type *Lo, llvm::Type *Hi, ABIArgInfo X86_64ABIInfo:: classifyReturnType(QualType RetTy) const { + // return int128 as i128 + if (const BuiltinType *BT = RetTy->getAs()) { +BuiltinType::Kind k = BT->getKind(); +if (k == BuiltinType::Int128 || k == BuiltinType::UInt128) { + return ABIArgInfo::getDirect(); +} + } + // AMD64-ABI 3.2.3p4: Rule 1. Classify the return type with the // classification algorithm. X86_64ABIInfo::Class Lo, Hi; efriedma-quic wrote: We still need to handle i128 in structs. We could maybe extend GetINTEGERTypeAtOffset to allow it to return i128 when appropriate. (That code is pretty fragile, though; see #76017.) https://github.com/llvm/llvm-project/pull/135230 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang][CodeGen][X86] don't coerce int128 into `{i64,i64}` for SysV-like ABIs (PR #135230)
jmorse wrote: There's precedent for splitting the debug-info into fragments early, we do something similar for C++ structured-bindings in SROA and a very similar process happens when the i128 argument is split up in instruction-selection. Split-up locations become brittle to optimisations though: any source-expression that gets salvaged into a DIExpression can't be decomposed into two fragments, and we have to mark them optimised out. Any salvaging into DIExpression for an i128 will almost certainly fail when the value gets split up in isel. Plus I believe DWARF doesn't support values on the expression stack larger than the machine-address-size, but that's an assumption that can be bent. Presumably the desire here is to improve the variable availability of parameters rather than fully supporting i128's through LLVM debug-info? If so, the least invasive approach may be to teach SROA to decompose into fragments similar to structured-bindings for the first variable location in the function. Or, passing an i128 instead works alright, I have no opinion on ABI matters. (Paging @OCHyams as he worked on structured bindings; and @slinder1 as this is another scenario that might be easier with a typed expression stack) https://github.com/llvm/llvm-project/pull/135230 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang][CodeGen][X86] don't coerce int128 into `{i64,i64}` for SysV-like ABIs (PR #135230)
hvdijk wrote: Both agreed with @nikic that this PR is a good idea and with @efriedma-quic that this does not solve the problem in general. I don't think the latter should stop this from being merged but it would be nice to find something that addresses all cases. > Another fix may be to generate `DW_OP_LLVM_fragment` expressions when > removing the `or` Maybe a bad suggestion, I have not looked into the implementation, but at the point where the `i128` gets split into two `i64`s, could we already update the `#dbg_value` there to use fragments? At that point we have all the required information, and it sounds like it would avoid the problem since there is then no longer any larger-than-`i64` debug info to cause `poison`? https://github.com/llvm/llvm-project/pull/135230 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang][CodeGen][X86] don't coerce int128 into `{i64,i64}` for SysV-like ABIs (PR #135230)
efriedma-quic wrote: There isn't any reason we can't do this... but it doesn't really solve the issue in general. And there are a lot of other ways to trip over this. CC @dblaike @hvdijk @jmorse Do we want to try to handle _BitInt, or a struct containing an i128? https://github.com/llvm/llvm-project/pull/135230 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang][CodeGen][X86] don't coerce int128 into `{i64,i64}` for SysV-like ABIs (PR #135230)
https://github.com/nikic edited https://github.com/llvm/llvm-project/pull/135230 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang][CodeGen][X86] don't coerce int128 into `{i64,i64}` for SysV-like ABIs (PR #135230)
https://github.com/nikic commented: I haven't checked the implementation, but conceptually this looks fine. Passing as i128 instead of {i64, i64} is better for optimization purposes. Rust already passes these as i128, so we know that works, and change will improve x-lang LTO. (Clang also passes as i128 already, but only for ones that are known to be passed in memory -- go figure.) https://github.com/llvm/llvm-project/pull/135230 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang][CodeGen][X86] don't coerce int128 into `{i64,i64}` for SysV-like ABIs (PR #135230)
llvmbot wrote: @llvm/pr-subscribers-clang Author: None (T0b1-iOS) Changes Currently, clang coerces (u)int128_t to two i64 IR parameters when they are passed in registers. This leads to broken debug info for them after applying SROA+InstCombine. SROA generates IR like this ([godbolt](https://godbolt.org/z/YrTa4chfc)): ```llvm define dso_local { i64, i64 } @add(i64 noundef %a.coerce0, i64 noundef %a.coerce1) { entry: %a.sroa.2.0.insert.ext = zext i64 %a.coerce1 to i128 %a.sroa.2.0.insert.shift = shl nuw i128 %a.sroa.2.0.insert.ext, 64 %a.sroa.0.0.insert.ext = zext i64 %a.coerce0 to i128 %a.sroa.0.0.insert.insert = or i128 %a.sroa.2.0.insert.shift, %a.sroa.0.0.insert.ext #dbg_value(i128 %a.sroa.0.0.insert.insert, !17, !DIExpression(), !18) // ... !17 = !DILocalVariable(name: "a", arg: 1, scope: !10, file: !11, line: 1, type: !14) // ... ``` and InstCombine then removes the `or`, moving it into the `DIExpression`, and the `shl` at which point the debug info salvaging in `Transforms/Local` replaces the arguments with `poison` as it does not allow constants larger than 64 bit in `DIExpression`s. I'm working under the assumption that there is interest in fixing this. If not, please tell me. By not coercing `int128_t`s into `{i64, i64}` but keeping them as `i128`, the debug info stays intact and SelectionDAG then generates two `DW_OP_LLVM_fragment` expressions for the two corresponding argument registers. Given that the ABI code for x64 seems to not coerce the argument when it is passed on the stack, it should not lead to any problems keeping it as an `i128` when it is passed in registers. Alternatively, this could be fixed by checking if a constant value fits in 64 bits in the debug info salvaging code and then extending the value on the expression stack to the necessary width. This fixes InstCombine breaking the debug info but then SelectionDAG removes the expression and that seems significantly more complex to debug. Another fix may be to generate `DW_OP_LLVM_fragment` expressions when removing the `or` as it gets marked as disjoint by InstCombine. However, I don't know if the KnownBits information is still available at the time the `or` gets removed and it would probably require refactoring of the debug info salvaging code as that currently only seems to replace single expressions and is not designed to support generating new debug records. Converting `(u)int128_t` arguments to `i128` in the IR seems like the simpler solution, if it doesn't cause any ABI issues. tagging potential reviewers: @nikic @phoebewang @rnk --- Full diff: https://github.com/llvm/llvm-project/pull/135230.diff 6 Files Affected: - (modified) clang/lib/CodeGen/Targets/X86.cpp (+18) - (added) clang/test/CodeGen/X86/i128-debuginfo.c (+10) - (modified) clang/test/CodeGen/X86/x86_64-arguments.c (+21) - (modified) clang/test/CodeGen/alloc-align-attr.c (+17-41) - (modified) clang/test/CodeGen/builtins.c (+3-15) - (modified) clang/test/CodeGen/extend-arg-64.c (+1-1) ``diff diff --git a/clang/lib/CodeGen/Targets/X86.cpp b/clang/lib/CodeGen/Targets/X86.cpp index b36a6e1396653..aa4ab1c2e5490 100644 --- a/clang/lib/CodeGen/Targets/X86.cpp +++ b/clang/lib/CodeGen/Targets/X86.cpp @@ -2595,6 +2595,14 @@ GetX86_64ByValArgumentPair(llvm::Type *Lo, llvm::Type *Hi, ABIArgInfo X86_64ABIInfo:: classifyReturnType(QualType RetTy) const { + // return int128 as i128 + if (const BuiltinType *BT = RetTy->getAs()) { +BuiltinType::Kind k = BT->getKind(); +if (k == BuiltinType::Int128 || k == BuiltinType::UInt128) { + return ABIArgInfo::getDirect(); +} + } + // AMD64-ABI 3.2.3p4: Rule 1. Classify the return type with the // classification algorithm. X86_64ABIInfo::Class Lo, Hi; @@ -2727,6 +2735,16 @@ X86_64ABIInfo::classifyArgumentType(QualType Ty, unsigned freeIntRegs, bool isNamedArg, bool IsRegCall) const { Ty = useFirstFieldIfTransparentUnion(Ty); + // represent int128 as i128 + if (const BuiltinType *BT = Ty->getAs()) { +BuiltinType::Kind k = BT->getKind(); +if (k == BuiltinType::Int128 || k == BuiltinType::UInt128) { + neededInt = 2; + neededSSE = 0; + return ABIArgInfo::getDirect(); +} + } + X86_64ABIInfo::Class Lo, Hi; classify(Ty, 0, Lo, Hi, isNamedArg, IsRegCall); diff --git a/clang/test/CodeGen/X86/i128-debuginfo.c b/clang/test/CodeGen/X86/i128-debuginfo.c new file mode 100644 index 0..4b865c1bed9f0 --- /dev/null +++ b/clang/test/CodeGen/X86/i128-debuginfo.c @@ -0,0 +1,10 @@ +// no autogeneration since update_cc_test_checks does not support -g +// RUN: %clang_cc1 -triple x86_64-pc-linux -O1 -debug-info-kind=limited -emit-llvm -o - %s | FileCheck %s + +// CHECK-LABEL: define{{.*}} i128 @add(i128 noundef %a) +// CHECK: #dbg_value(i128 %a, ![[DI:.*]], !DIExpression() +__int128_t add(__int128_t a) { + return a + a; +} + +// CHECK: ![[DI]] = !DILocalVa
[clang] [Clang][CodeGen][X86] don't coerce int128 into `{i64,i64}` for SysV-like ABIs (PR #135230)
https://github.com/T0b1-iOS created https://github.com/llvm/llvm-project/pull/135230 Currently, clang coerces (u)int128_t to two i64 IR parameters when they are passed in registers. This leads to broken debug info for them after applying SROA+InstCombine. SROA generates IR like this ([godbolt](https://godbolt.org/z/YrTa4chfc)): ```llvm define dso_local { i64, i64 } @add(i64 noundef %a.coerce0, i64 noundef %a.coerce1) { entry: %a.sroa.2.0.insert.ext = zext i64 %a.coerce1 to i128 %a.sroa.2.0.insert.shift = shl nuw i128 %a.sroa.2.0.insert.ext, 64 %a.sroa.0.0.insert.ext = zext i64 %a.coerce0 to i128 %a.sroa.0.0.insert.insert = or i128 %a.sroa.2.0.insert.shift, %a.sroa.0.0.insert.ext #dbg_value(i128 %a.sroa.0.0.insert.insert, !17, !DIExpression(), !18) // ... !17 = !DILocalVariable(name: "a", arg: 1, scope: !10, file: !11, line: 1, type: !14) // ... ``` and InstCombine then removes the `or`, moving it into the `DIExpression`, and the `shl` at which point the debug info salvaging in `Transforms/Local` replaces the arguments with `poison` as it does not allow constants larger than 64 bit in `DIExpression`s. I'm working under the assumption that there is interest in fixing this. If not, please tell me. By not coercing `int128_t`s into `{i64, i64}` but keeping them as `i128`, the debug info stays intact and SelectionDAG then generates two `DW_OP_LLVM_fragment` expressions for the two corresponding argument registers. Given that the ABI code for x64 seems to not coerce the argument when it is passed on the stack, it should not lead to any problems keeping it as an `i128` when it is passed in registers. Alternatively, this could be fixed by checking if a constant value fits in 64 bits in the debug info salvaging code and then extending the value on the expression stack to the necessary width. This fixes InstCombine breaking the debug info but then SelectionDAG removes the expression and that seems significantly more complex to debug. Another fix may be to generate `DW_OP_LLVM_fragment` expressions when removing the `or` as it gets marked as disjoint by InstCombine. However, I don't know if the KnownBits information is still available at the time the `or` gets removed and it would probably require refactoring of the debug info salvaging code as that currently only seems to replace single expressions and is not designed to support generating new debug records. Converting `(u)int128_t` arguments to `i128` in the IR seems like the simpler solution, if it doesn't cause any ABI issues. tagging potential reviewers: @nikic @phoebewang @rnk >From f0bb89e5cfe2739dc51faef64215251cfe1516d4 Mon Sep 17 00:00:00 2001 From: T0b1 Date: Thu, 10 Apr 2025 19:16:00 +0200 Subject: [PATCH] [Clang][CodeGen][X86] don't coerce int128 into `{i64,i64}` for SysV-like ABIs --- clang/lib/CodeGen/Targets/X86.cpp | 18 +++ clang/test/CodeGen/X86/i128-debuginfo.c | 10 clang/test/CodeGen/X86/x86_64-arguments.c | 21 clang/test/CodeGen/alloc-align-attr.c | 58 +++ clang/test/CodeGen/builtins.c | 18 ++- clang/test/CodeGen/extend-arg-64.c| 2 +- 6 files changed, 70 insertions(+), 57 deletions(-) create mode 100644 clang/test/CodeGen/X86/i128-debuginfo.c diff --git a/clang/lib/CodeGen/Targets/X86.cpp b/clang/lib/CodeGen/Targets/X86.cpp index b36a6e1396653..aa4ab1c2e5490 100644 --- a/clang/lib/CodeGen/Targets/X86.cpp +++ b/clang/lib/CodeGen/Targets/X86.cpp @@ -2595,6 +2595,14 @@ GetX86_64ByValArgumentPair(llvm::Type *Lo, llvm::Type *Hi, ABIArgInfo X86_64ABIInfo:: classifyReturnType(QualType RetTy) const { + // return int128 as i128 + if (const BuiltinType *BT = RetTy->getAs()) { +BuiltinType::Kind k = BT->getKind(); +if (k == BuiltinType::Int128 || k == BuiltinType::UInt128) { + return ABIArgInfo::getDirect(); +} + } + // AMD64-ABI 3.2.3p4: Rule 1. Classify the return type with the // classification algorithm. X86_64ABIInfo::Class Lo, Hi; @@ -2727,6 +2735,16 @@ X86_64ABIInfo::classifyArgumentType(QualType Ty, unsigned freeIntRegs, bool isNamedArg, bool IsRegCall) const { Ty = useFirstFieldIfTransparentUnion(Ty); + // represent int128 as i128 + if (const BuiltinType *BT = Ty->getAs()) { +BuiltinType::Kind k = BT->getKind(); +if (k == BuiltinType::Int128 || k == BuiltinType::UInt128) { + neededInt = 2; + neededSSE = 0; + return ABIArgInfo::getDirect(); +} + } + X86_64ABIInfo::Class Lo, Hi; classify(Ty, 0, Lo, Hi, isNamedArg, IsRegCall); diff --git a/clang/test/CodeGen/X86/i128-debuginfo.c b/clang/test/CodeGen/X86/i128-debuginfo.c new file mode 100644 index 0..4b865c1bed9f0 --- /dev/null +++ b/clang/test/CodeGen/X86/i128-debuginfo.c @@ -0,0 +1,10 @@ +// no autogeneration since update_cc_test_checks does not support -g +// RUN: %clang_cc1 -triple x86_64-pc-linux -O1 -debug-info-kind=limited
[clang] [Clang][CodeGen][X86] don't coerce int128 into `{i64,i64}` for SysV-like ABIs (PR #135230)
github-actions[bot] wrote: Thank you for submitting a Pull Request (PR) to the LLVM Project! This PR will be automatically labeled and the relevant teams will be notified. If you wish to, you can add reviewers by using the "Reviewers" section on this page. If this is not working for you, it is probably because you do not have write permissions for the repository. In which case you can instead tag reviewers by name in a comment by using `@` followed by their GitHub username. If you have received no comments on your PR for a week, you can request a review by "ping"ing the PR by adding a comment “Ping”. The common courtesy "ping" rate is once a week. Please remember that you are asking for valuable time from other developers. If you have further questions, they may be answered by the [LLVM GitHub User Guide](https://llvm.org/docs/GitHub.html). You can also ask questions in a comment on this PR, on the [LLVM Discord](https://discord.com/invite/xS7Z362) or on the [forums](https://discourse.llvm.org/). https://github.com/llvm/llvm-project/pull/135230 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits