Skip to content

Commit 9af3628

Browse files
committed
[SystemZ] Fix transparent_union calling convention
The SystemZ ABI code was missing code to handle the transparent_union extension. Arguments of such types are specified to be passed like the first member of the union, instead of according to the usual ABI calling convention for aggregates. This did not make much difference in practice as the SystemZ ABI already specifies that 1-, 2-, 4- or 8-byte aggregates are passed in registers. However, there *is* a difference if the first member of the transparent union is a scalar integer type smaller than word size - if passed as a scalar, it needs to be zero- or sign-extended to word size, while if passed as aggregate, it is not. Fixed by adding code to handle transparent_union similar to what is done on other targets.
1 parent a2d3099 commit 9af3628

File tree

2 files changed

+27
-1
lines changed

2 files changed

+27
-1
lines changed

clang/lib/CodeGen/Targets/SystemZ.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -412,13 +412,16 @@ ABIArgInfo SystemZABIInfo::classifyReturnType(QualType RetTy) const {
412412
}
413413

414414
ABIArgInfo SystemZABIInfo::classifyArgumentType(QualType Ty) const {
415+
// Handle transparent union types.
416+
Ty = useFirstFieldIfTransparentUnion(Ty);
417+
415418
// Handle the generic C++ ABI.
416419
if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, getCXXABI()))
417420
return getNaturalAlignIndirect(Ty, RAA == CGCXXABI::RAA_DirectInMemory);
418421

419422
// Integers and enums are extended to full register width.
420423
if (isPromotableIntegerTypeForABI(Ty))
421-
return ABIArgInfo::getExtend(Ty);
424+
return ABIArgInfo::getExtend(Ty, CGT.ConvertType(Ty));
422425

423426
// Handle vector types and vector-like structure types. Note that
424427
// as opposed to float-like structure types, we do not allow any

clang/test/CodeGen/SystemZ/systemz-abi.c

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,29 @@ union union_double pass_union_double(union union_double arg) { return arg; }
173173
// CHECK-LABEL: define{{.*}} void @pass_union_double(ptr dead_on_unwind noalias writable sret(%union.union_double) align 8 %{{.*}}, i64 %{{.*}})
174174

175175

176+
// Verify that transparent unions are passed like their first member (but returned like a union)
177+
178+
union tu_char { char a; } __attribute__((transparent_union));
179+
union tu_char pass_tu_char(union tu_char arg) { return arg; }
180+
// CHECK-LABEL: define{{.*}} void @pass_tu_char(ptr dead_on_unwind noalias writable sret(%union.tu_char) align 1 %{{.*}}, i8 signext %{{.*}})
181+
182+
union tu_short { short a; } __attribute__((transparent_union));
183+
union tu_short pass_tu_short(union tu_short arg) { return arg; }
184+
// CHECK-LABEL: define{{.*}} void @pass_tu_short(ptr dead_on_unwind noalias writable sret(%union.tu_short) align 2 %{{.*}}, i16 signext %{{.*}})
185+
186+
union tu_int { int a; } __attribute__((transparent_union));
187+
union tu_int pass_tu_int(union tu_int arg) { return arg; }
188+
// CHECK-LABEL: define{{.*}} void @pass_tu_int(ptr dead_on_unwind noalias writable sret(%union.tu_int) align 4 %{{.*}}, i32 signext %{{.*}})
189+
190+
union tu_long { long a; } __attribute__((transparent_union));
191+
union tu_long pass_tu_long(union tu_long arg) { return arg; }
192+
// CHECK-LABEL: define{{.*}} void @pass_tu_long(ptr dead_on_unwind noalias writable sret(%union.tu_long) align 8 %{{.*}}, i64 %{{.*}})
193+
194+
union tu_ptr { void *a; } __attribute__((transparent_union));
195+
union tu_ptr pass_tu_ptr(union tu_ptr arg) { return arg; }
196+
// CHECK-LABEL: define{{.*}} void @pass_tu_ptr(ptr dead_on_unwind noalias writable sret(%union.tu_ptr) align 8 %{{.*}}, ptr %{{.*}})
197+
198+
176199
// Accessing variable argument lists
177200

178201
int va_int(__builtin_va_list l) { return __builtin_va_arg(l, int); }

0 commit comments

Comments
 (0)