Skip to content

Commit ef48930

Browse files
committed
[Clang][CodeGen][X86] handle (u)int128_t in structs.
As a side-effect, this will also pass _BitInt(128) as a i128 if it is passed in registers
1 parent 16068fb commit ef48930

File tree

3 files changed

+34
-23
lines changed

3 files changed

+34
-23
lines changed

clang/lib/CodeGen/Targets/X86.cpp

Lines changed: 14 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2472,10 +2472,10 @@ GetSSETypeAtOffset(llvm::Type *IRType, unsigned IROffset,
24722472

24732473

24742474
/// GetINTEGERTypeAtOffset - The ABI specifies that a value should be passed in
2475-
/// an 8-byte GPR. This means that we either have a scalar or we are talking
2476-
/// about the high or low part of an up-to-16-byte struct. This routine picks
2475+
/// one or more 8-byte GPRs. This means that we either have a scalar or we are talking
2476+
/// about the high and/or low part of an up-to-16-byte struct. This routine picks
24772477
/// the best LLVM IR type to represent this, which may be i64 or may be anything
2478-
/// else that the backend will pass in a GPR that works better (e.g. i8, %foo*,
2478+
/// else that the backend will pass in GPRs that works better (e.g. i8, %foo*,
24792479
/// etc).
24802480
///
24812481
/// PrefType is an LLVM IR type that corresponds to (part of) the IR type for
@@ -2534,6 +2534,17 @@ GetINTEGERTypeAtOffset(llvm::Type *IRType, unsigned IROffset,
25342534
SourceOffset);
25352535
}
25362536

2537+
// if we have a 128-bit integer, we can pass it safely using an i128
2538+
// so we return that if the IROffset is 0 and no type otherwise
2539+
if (IRType->isIntegerTy(128)) {
2540+
if (IROffset == 0) {
2541+
return IRType;
2542+
} else {
2543+
assert(IROffset == 8);
2544+
return nullptr;
2545+
}
2546+
}
2547+
25372548
// Okay, we don't have any better idea of what to pass, so we pass this in an
25382549
// integer register that isn't too big to fit the rest of the struct.
25392550
unsigned TySizeInBytes =
@@ -2594,14 +2605,6 @@ GetX86_64ByValArgumentPair(llvm::Type *Lo, llvm::Type *Hi,
25942605

25952606
ABIArgInfo X86_64ABIInfo::
25962607
classifyReturnType(QualType RetTy) const {
2597-
// return int128 as i128
2598-
if (const BuiltinType *BT = RetTy->getAs<BuiltinType>()) {
2599-
BuiltinType::Kind k = BT->getKind();
2600-
if (k == BuiltinType::Int128 || k == BuiltinType::UInt128) {
2601-
return ABIArgInfo::getDirect();
2602-
}
2603-
}
2604-
26052608
// AMD64-ABI 3.2.3p4: Rule 1. Classify the return type with the
26062609
// classification algorithm.
26072610
X86_64ABIInfo::Class Lo, Hi;
@@ -2734,16 +2737,6 @@ X86_64ABIInfo::classifyArgumentType(QualType Ty, unsigned freeIntRegs,
27342737
bool isNamedArg, bool IsRegCall) const {
27352738
Ty = useFirstFieldIfTransparentUnion(Ty);
27362739

2737-
// represent int128 as i128
2738-
if (const BuiltinType *BT = Ty->getAs<BuiltinType>()) {
2739-
BuiltinType::Kind k = BT->getKind();
2740-
if (k == BuiltinType::Int128 || k == BuiltinType::UInt128) {
2741-
neededInt = 2;
2742-
neededSSE = 0;
2743-
return ABIArgInfo::getDirect();
2744-
}
2745-
}
2746-
27472740
X86_64ABIInfo::Class Lo, Hi;
27482741
classify(Ty, 0, Lo, Hi, isNamedArg, IsRegCall);
27492742

clang/test/CodeGen/X86/x86_64-arguments.c

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -572,6 +572,24 @@ void f71(__int128_t a, __int128_t b, long long c, struct s71 d) {
572572
void f72(__int128_t a, __int128_t b, struct s71 d) {
573573
}
574574

575+
// check that structs containing (u)int128_t are passed correctly
576+
struct s73 {
577+
struct inner {
578+
__uint128_t a;
579+
};
580+
struct inner in;
581+
};
582+
// CHECK-LABEL: define{{.*}} i128 @f73(i128 %a.coerce)
583+
struct s73 f73(struct s73 a) {
584+
return a;
585+
}
586+
587+
// check that _BitInt(128) is still passed correctly on the stack
588+
// CHECK-LABEL: define{{.*}} i128 @f74(i128 noundef %b, i128 noundef %c, i128 noundef %d, i64 noundef %e, ptr noundef byval(i128) align 8 %0)
589+
_BitInt(128) f74(__uint128_t b, __uint128_t c, __uint128_t d, long e, _BitInt(128) a) {
590+
return a;
591+
}
592+
575593
/// The synthesized __va_list_tag does not have file/line fields.
576594
// CHECK: = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "__va_list_tag",
577595
// CHECK-NOT: file:

clang/test/CodeGen/ext-int-cc.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232

3333
// Make sure 128 and 64 bit versions are passed like integers.
3434
void ParamPassing(_BitInt(128) b, _BitInt(64) c) {}
35-
// LIN64: define{{.*}} void @ParamPassing(i64 %{{.+}}, i64 %{{.+}}, i64 %{{.+}})
35+
// LIN64: define{{.*}} void @ParamPassing(i128 %{{.+}}, i64 %{{.+}})
3636
// WIN64: define dso_local void @ParamPassing(ptr %{{.+}}, i64 %{{.+}})
3737
// LIN32: define{{.*}} void @ParamPassing(ptr %{{.+}}, i64 %{{.+}})
3838
// WIN32: define dso_local void @ParamPassing(ptr %{{.+}}, i64 %{{.+}})
@@ -258,7 +258,7 @@ _BitInt(127) ReturnPassing3(void) { return 0; }
258258
// LA32: define{{.*}} void @ReturnPassing3(ptr dead_on_unwind noalias writable sret
259259

260260
_BitInt(128) ReturnPassing4(void) { return 0; }
261-
// LIN64: define{{.*}} { i64, i64 } @ReturnPassing4(
261+
// LIN64: define{{.*}} i128 @ReturnPassing4(
262262
// WIN64: define dso_local void @ReturnPassing4(ptr dead_on_unwind noalias writable sret
263263
// LIN32: define{{.*}} void @ReturnPassing4(ptr dead_on_unwind noalias writable sret
264264
// WIN32: define dso_local void @ReturnPassing4(ptr dead_on_unwind noalias writable sret

0 commit comments

Comments
 (0)