Skip to content

Commit 2c8d9c8

Browse files
committed
fix: empty record size > 64 with align let va_list get out of sync
1 parent f1fdbcb commit 2c8d9c8

File tree

5 files changed

+31
-9
lines changed

5 files changed

+31
-9
lines changed

clang/lib/CodeGen/Targets/AArch64.cpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -295,8 +295,12 @@ AArch64ABIInfo::classifyArgumentType(QualType Ty, bool IsVariadic,
295295
CGCXXABI::RAA_DirectInMemory);
296296
}
297297

298-
// Empty records are always ignored on Darwin, but actually passed in C++ mode
299-
// elsewhere for GNU compatibility.
298+
// AAPCS64 does not say that empty records are ignored as arguments,
299+
// but other compilers do so in certain situations, and we copy that behavior.
300+
// Those situations are in fact language-mode-specific, which seems really
301+
// unfortunate, but it's something we just have to accept. If this doesn't
302+
// apply, just fall through to the standard argument-handling path.
303+
// Darwin overrides the psABI here to ignore all empty records in all modes.
300304
uint64_t Size = getContext().getTypeSize(Ty);
301305
bool IsEmpty = isEmptyRecord(getContext(), Ty, true);
302306
if (IsEmpty || Size == 0) {
@@ -307,7 +311,6 @@ AArch64ABIInfo::classifyArgumentType(QualType Ty, bool IsVariadic,
307311
// 0.
308312
if (IsEmpty && Size == 0)
309313
return ABIArgInfo::getIgnore();
310-
return ABIArgInfo::getDirect(llvm::Type::getInt8Ty(getVMContext()));
311314
}
312315

313316
// Homogeneous Floating-point Aggregates (HFAs) need to be expanded.

clang/test/CodeGen/aarch64-args.cpp

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ struct Empty {};
1717

1818
// CHECK: define{{.*}} i32 @empty_arg(i32 noundef %a)
1919
// CHECK-GNU-C: define{{.*}} i32 @empty_arg(i32 noundef %a)
20-
// CHECK-GNU-CXX: define{{.*}} i32 @empty_arg(i8 %e.coerce, i32 noundef %a)
20+
// CHECK-GNU-CXX: define{{.*}} i32 @empty_arg(i64 %e.coerce, i32 noundef %a)
2121
EXTERNC int empty_arg(struct Empty e, int a) {
2222
return a;
2323
}
@@ -53,7 +53,7 @@ struct SortOfEmpty {
5353

5454
// CHECK: define{{.*}} i32 @sort_of_empty_arg(i32 noundef %a)
5555
// CHECK-GNU-C: define{{.*}} i32 @sort_of_empty_arg(i32 noundef %a)
56-
// CHECK-GNU-CXX: define{{.*}} i32 @sort_of_empty_arg(i8 %e.coerce, i32 noundef %a)
56+
// CHECK-GNU-CXX: define{{.*}} i32 @sort_of_empty_arg(i64 %e.coerce, i32 noundef %a)
5757
EXTERNC int sort_of_empty_arg(struct Empty e, int a) {
5858
return a;
5959
}
@@ -65,3 +65,22 @@ EXTERNC struct SortOfEmpty sort_of_empty_ret(void) {
6565
struct SortOfEmpty e;
6666
return e;
6767
}
68+
69+
// CHECK-GNU-CXX: define{{.*}} i32 @empty_align8_arg(i64 %a.coerce, i32 noundef %b)
70+
struct EmptyAlign8 { int __attribute__((aligned(8))) : 0; };
71+
EXTERNC int empty_align8_arg(struct EmptyAlign8 a, int b) {
72+
return b;
73+
}
74+
75+
// CHECK-GNU-CXX: define{{.*}} i32 @empty_align16_arg(i128 %a.coerce, i32 noundef %b)
76+
struct EmptyAlign16 { long long int __attribute__((aligned(16))) : 0; };
77+
EXTERNC int empty_align16_arg(struct EmptyAlign16 a, int b) {
78+
return b;
79+
}
80+
81+
// CHECK-GNU-CXX: define{{.*}} i32 @empty_align32_arg(ptr noundef %a, i32 noundef %b)
82+
struct EmptyAlign32 { long long int __attribute__((aligned(32))) : 0; };
83+
EXTERNC int empty_align32_arg(struct EmptyAlign32 a, int b) {
84+
return b;
85+
}
86+

clang/test/CodeGen/arm64-microsoft-arguments.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ S4 f4() {
5757

5858
// Pass and return from instance method called from instance method.
5959
// CHECK: define {{.*}} void @{{.*}}bar@Q1{{.*}}(ptr {{[^,]*}} %this, ptr inreg noalias sret(%class.P1) align 1 %agg.result)
60-
// CHECK: call void {{.*}}foo@P1{{.*}}(ptr noundef{{[^,]*}} %ref.tmp, ptr inreg sret(%class.P1) align 1 %agg.result, i8 %0)
60+
// CHECK: call void {{.*}}foo@P1{{.*}}(ptr noundef{{[^,]*}} %ref.tmp, ptr inreg sret(%class.P1) align 1 %agg.result, i64 %coerce.val.ii)
6161

6262
class P1 {
6363
public:
@@ -76,7 +76,7 @@ P1 Q1::bar() {
7676

7777
// Pass and return from instance method called from free function.
7878
// CHECK: define {{.*}} void {{.*}}bar{{.*}}()
79-
// CHECK: call void {{.*}}foo@P2{{.*}}(ptr noundef{{[^,]*}} %ref.tmp, ptr inreg sret(%class.P2) align 1 %retval, i8 %0)
79+
// CHECK: call void {{.*}}foo@P2{{.*}}(ptr noundef{{[^,]*}} %ref.tmp, ptr inreg sret(%class.P2) align 1 %retval, i64 %coerce.val.ii)
8080
class P2 {
8181
public:
8282
P2 foo(P2 x);
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// RUN: %clang_cc1 -triple arm64-none-linux -emit-llvm -w -o - %s | FileCheck -check-prefix=PCS %s
22

3-
// PCS: define{{.*}} void @{{.*}}(i8 %a
3+
// PCS: define{{.*}} void @{{.*}}(i64 %a.coerce)
44
struct s0 {};
55
void f0(s0 a) {}

clang/test/CodeGenCXX/arm64-darwinpcs.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ void test_extensions(bool a, char b, short c) {}
77

88
struct Empty {};
99
void test_empty(Empty e) {}
10-
// CHECK: define{{.*}} void @_Z10test_empty5Empty(i8
10+
// CHECK: define{{.*}} void @_Z10test_empty5Empty(i64 %e.coerce)
1111
// CHECK-DARWIN: define{{.*}} void @_Z10test_empty5Empty()
1212

1313
struct HFA {

0 commit comments

Comments
 (0)