Skip to content

Commit ca9ec7d

Browse files
authored
[ARM, AArch64] Fix passing of structures with aligned base classes (#135564)
RecordLayout::UnadjustedAlignment was documented as "Maximum of the alignments of the record members in characters", but RecordLayout::getUnadjustedAlignment(), which just returns UnadjustedAlignment, was documented as getting "the record alignment in characters, before alignment adjustement." These are not the same thing: the former excludes alignment of base classes, the latter takes it into account. ItaniumRecordLayoutBuilder::LayoutBase was setting it according to the former, but the AAPCS calling convention handling, currently the only user, relies on it being set according to the latter. Fixes #135551.
1 parent 1dbc8ef commit ca9ec7d

File tree

5 files changed

+115
-101
lines changed

5 files changed

+115
-101
lines changed

clang/include/clang/AST/RecordLayout.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -75,8 +75,9 @@ class ASTRecordLayout {
7575
// performance or backwards compatibility preserving (e.g. AIX-ABI).
7676
CharUnits PreferredAlignment;
7777

78-
// UnadjustedAlignment - Maximum of the alignments of the record members in
79-
// characters.
78+
// UnadjustedAlignment - Alignment of record in characters before alignment
79+
// adjustments. Maximum of the alignments of the record members and base
80+
// classes in characters.
8081
CharUnits UnadjustedAlignment;
8182

8283
/// RequiredAlignment - The required alignment of the object. In the MS-ABI
@@ -186,7 +187,7 @@ class ASTRecordLayout {
186187
CharUnits getPreferredAlignment() const { return PreferredAlignment; }
187188

188189
/// getUnadjustedAlignment - Get the record alignment in characters, before
189-
/// alignment adjustement.
190+
/// alignment adjustment.
190191
CharUnits getUnadjustedAlignment() const { return UnadjustedAlignment; }
191192

192193
/// getSize - Get the record size in characters.

clang/lib/AST/RecordLayoutBuilder.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1302,6 +1302,7 @@ ItaniumRecordLayoutBuilder::LayoutBase(const BaseSubobjectInfo *Base) {
13021302
setSize(std::max(getSize(), Offset + Layout.getSize()));
13031303

13041304
// Remember max struct/class alignment.
1305+
UnadjustedAlignment = std::max(UnadjustedAlignment, BaseAlign);
13051306
UpdateAlignment(BaseAlign, UnpackedAlignTo, PreferredBaseAlign);
13061307

13071308
return Offset;

clang/test/CodeGen/AArch64/args.cpp

Lines changed: 109 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// RUN: %clang_cc1 -triple arm64-apple-ios7.0 -target-abi darwinpcs -emit-llvm -o - %s | FileCheck %s --check-prefixes=CHECK,DARWIN
2-
// RUN: %clang_cc1 -triple aarch64-linux-gnu -emit-llvm -o - -x c %s | FileCheck %s --check-prefixes=CHECK,C
3-
// RUN: %clang_cc1 -triple aarch64-linux-gnu -emit-llvm -o - %s | FileCheck %s --check-prefixes=CHECK,CXX
2+
// RUN: %clang_cc1 -triple aarch64-linux-gnu -emit-llvm -o - -x c %s | FileCheck %s --check-prefixes=CHECK,C,AAPCS
3+
// RUN: %clang_cc1 -triple aarch64-linux-gnu -emit-llvm -o - %s | FileCheck %s --check-prefixes=CHECK,CXX,AAPCS
44

55
// Empty structs are ignored for PCS purposes on Darwin and in C mode elsewhere.
66
// In C++ mode on ELF they consume a register slot though. Functions are
@@ -110,3 +110,110 @@ EXTERNC struct SortOfEmpty sort_of_empty_arg_variadic(int a, ...) {
110110
return b;
111111
}
112112

113+
// Base case, nothing interesting.
114+
struct S {
115+
long x, y;
116+
};
117+
118+
// CHECK-LABEL: @g_S(
119+
// CHECK: call void @f_S(i64 noundef 1, [2 x i64] {{.*}})
120+
// CHECK: call void @fm_S(i64 noundef 1, i64 noundef 2, i64 noundef 3, i64 noundef 4, i64 noundef 5, [2 x i64] {{.*}})
121+
EXTERNC void f_S(long, struct S);
122+
EXTERNC void fm_S(long, long, long, long, long, struct S);
123+
EXTERNC void g_S() {
124+
struct S s = {6, 7};
125+
f_S(1, s);
126+
fm_S(1, 2, 3, 4, 5, s);
127+
}
128+
129+
// Aligned struct passed according to its natural alignment.
130+
struct __attribute__((aligned(16))) S16 {
131+
long x, y;
132+
};
133+
134+
// CHECK-LABEL: @g_S16(
135+
// DARWIN: call void @f_S16(i64 noundef 1, i128 {{.*}})
136+
// AAPCS: call void @f_S16(i64 noundef 1, [2 x i64] {{.*}})
137+
// DARWIN: call void @fm_S16(i64 noundef 1, i64 noundef 2, i64 noundef 3, i64 noundef 4, i64 noundef 5, i128 {{.*}})
138+
// AAPCS: call void @fm_S16(i64 noundef 1, i64 noundef 2, i64 noundef 3, i64 noundef 4, i64 noundef 5, [2 x i64] {{.*}})
139+
EXTERNC void f_S16(long, struct S16);
140+
EXTERNC void fm_S16(long, long, long, long, long, struct S16);
141+
EXTERNC void g_S16() {
142+
struct S16 s = {6, 7};
143+
f_S16(1, s);
144+
fm_S16(1, 2, 3, 4, 5, s);
145+
}
146+
147+
// Aligned struct with increased natural alignment through an aligned field.
148+
struct SF16 {
149+
__attribute__((aligned(16))) long x;
150+
long y;
151+
};
152+
153+
// CHECK-LABEL: @g_SF16(
154+
// DARWIN: call void @f_SF16(i64 noundef 1, i128 {{.*}})
155+
// AAPCS: call void @f_SF16(i64 noundef 1, i128 {{.*}})
156+
// DARWIN: call void @fm_SF16(i64 noundef 1, i64 noundef 2, i64 noundef 3, i64 noundef 4, i64 noundef 5, i128 {{.*}})
157+
// AAPCS: call void @fm_SF16(i64 noundef 1, i64 noundef 2, i64 noundef 3, i64 noundef 4, i64 noundef 5, i128 {{.*}})
158+
EXTERNC void f_SF16(long, struct SF16);
159+
EXTERNC void fm_SF16(long, long, long, long, long, struct SF16);
160+
EXTERNC void g_SF16() {
161+
struct SF16 s = {6, 7};
162+
f_SF16(1, s);
163+
fm_SF16(1, 2, 3, 4, 5, s);
164+
}
165+
166+
#ifdef __cplusplus
167+
// Aligned struct with increased natural alignment through an aligned base class.
168+
struct SB16 : S16 {};
169+
170+
// DARWIN-LABEL: @g_SB16(
171+
// CXX-LABEL: @g_SB16(
172+
// DARWIN: call void @f_SB16(i64 noundef 1, i128 {{.*}})
173+
// CXX: call void @f_SB16(i64 noundef 1, i128 {{.*}})
174+
// DARWIN: call void @fm_SB16(i64 noundef 1, i64 noundef 2, i64 noundef 3, i64 noundef 4, i64 noundef 5, i128 {{.*}})
175+
// CXX: call void @fm_SB16(i64 noundef 1, i64 noundef 2, i64 noundef 3, i64 noundef 4, i64 noundef 5, i128 {{.*}})
176+
EXTERNC void f_SB16(long, struct SB16);
177+
EXTERNC void fm_SB16(long, long, long, long, long, struct SB16);
178+
EXTERNC void g_SB16() {
179+
struct SB16 s = {6, 7};
180+
f_SB16(1, s);
181+
fm_SB16(1, 2, 3, 4, 5, s);
182+
}
183+
#endif
184+
185+
// Packed structure.
186+
struct __attribute__((packed)) SP {
187+
int x;
188+
long y;
189+
};
190+
191+
// CHECK-LABEL: @g_SP(
192+
// CHECK: call void @f_SP(i32 noundef 1, [2 x i64] {{.*}})
193+
// CHECK: call void @fm_SP(i32 noundef 1, i32 noundef 2, i32 noundef 3, i32 noundef 4, i32 noundef 5, [2 x i64] {{.*}})
194+
EXTERNC void f_SP(int, struct SP);
195+
EXTERNC void fm_SP(int, int, int, int, int, struct SP);
196+
EXTERNC void g_SP() {
197+
struct SP s = {6, 7};
198+
f_SP(1, s);
199+
fm_SP(1, 2, 3, 4, 5, s);
200+
}
201+
202+
// Packed structure, overaligned, same as above.
203+
struct __attribute__((packed, aligned(16))) SP16 {
204+
int x;
205+
long y;
206+
};
207+
208+
// CHECK-LABEL: @g_SP16(
209+
// DARWIN: call void @f_SP16(i32 noundef 1, i128 {{.*}})
210+
// AAPCS: call void @f_SP16(i32 noundef 1, [2 x i64] {{.*}})
211+
// DARWIN: call void @fm_SP16(i32 noundef 1, i32 noundef 2, i32 noundef 3, i32 noundef 4, i32 noundef 5, i128 {{.*}})
212+
// AAPCS: call void @fm_SP16(i32 noundef 1, i32 noundef 2, i32 noundef 3, i32 noundef 4, i32 noundef 5, [2 x i64] {{.*}})
213+
EXTERNC void f_SP16(int, struct SP16);
214+
EXTERNC void fm_SP16(int, int, int, int, int, struct SP16);
215+
EXTERNC void g_SP16() {
216+
struct SP16 s = {6, 7};
217+
f_SP16(1, s);
218+
fm_SP16(1, 2, 3, 4, 5, s);
219+
}

clang/test/CodeGen/aapcs64-align.cpp

Lines changed: 0 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -12,101 +12,6 @@ extern "C" {
1212
// CHECK: @sizeof_RidiculouslyOverSizedBitfield ={{.*}} global i32 32
1313
// CHECK: @alignof_RidiculouslyOverSizedBitfield ={{.*}} global i32 16
1414

15-
// Base case, nothing interesting.
16-
struct S {
17-
long x, y;
18-
};
19-
20-
void f0(long, S);
21-
void f0m(long, long, long, long, long, S);
22-
void g0() {
23-
S s = {6, 7};
24-
f0(1, s);
25-
f0m(1, 2, 3, 4, 5, s);
26-
}
27-
// CHECK: define{{.*}} void @g0
28-
// CHECK: call void @f0(i64 noundef 1, [2 x i64] [i64 6, i64 7]
29-
// CHECK: call void @f0m{{.*}}[2 x i64] [i64 6, i64 7]
30-
// CHECK: declare void @f0(i64 noundef, [2 x i64])
31-
// CHECK: declare void @f0m(i64 noundef, i64 noundef, i64 noundef, i64 noundef, i64 noundef, [2 x i64])
32-
33-
// Aligned struct, passed according to its natural alignment.
34-
struct __attribute__((aligned(16))) S16 {
35-
long x, y;
36-
} s16;
37-
38-
void f1(long, S16);
39-
void f1m(long, long, long, long, long, S16);
40-
void g1() {
41-
S16 s = {6, 7};
42-
f1(1, s);
43-
f1m(1, 2, 3, 4, 5, s);
44-
}
45-
// CHECK: define{{.*}} void @g1
46-
// CHECK: call void @f1{{.*}}[2 x i64] [i64 6, i64 7]
47-
// CHECK: call void @f1m{{.*}}[2 x i64] [i64 6, i64 7]
48-
// CHECK: declare void @f1(i64 noundef, [2 x i64])
49-
// CHECK: declare void @f1m(i64 noundef, i64 noundef, i64 noundef, i64 noundef, i64 noundef, [2 x i64])
50-
51-
// Increased natural alignment.
52-
struct SF16 {
53-
long x __attribute__((aligned(16)));
54-
long y;
55-
};
56-
57-
void f3(long, SF16);
58-
void f3m(long, long, long, long, long, SF16);
59-
void g3() {
60-
SF16 s = {6, 7};
61-
f3(1, s);
62-
f3m(1, 2, 3, 4, 5, s);
63-
}
64-
// CHECK: define{{.*}} void @g3
65-
// CHECK: call void @f3(i64 noundef 1, i128 129127208515966861318)
66-
// CHECK: call void @f3m(i64 noundef 1, i64 noundef 2, i64 noundef 3, i64 noundef 4, i64 noundef 5, i128 129127208515966861318)
67-
// CHECK: declare void @f3(i64 noundef, i128)
68-
// CHECK: declare void @f3m(i64 noundef, i64 noundef, i64 noundef, i64 noundef, i64 noundef, i128)
69-
70-
71-
// Packed structure.
72-
struct __attribute__((packed)) P {
73-
int x;
74-
long u;
75-
};
76-
77-
void f4(int, P);
78-
void f4m(int, int, int, int, int, P);
79-
void g4() {
80-
P s = {6, 7};
81-
f4(1, s);
82-
f4m(1, 2, 3, 4, 5, s);
83-
}
84-
// CHECK: define{{.*}} void @g4()
85-
// CHECK: call void @f4(i32 noundef 1, [2 x i64] [i64 30064771078, i64 0])
86-
// CHECK: void @f4m(i32 noundef 1, i32 noundef 2, i32 noundef 3, i32 noundef 4, i32 noundef 5, [2 x i64] [i64 30064771078, i64 0])
87-
// CHECK: declare void @f4(i32 noundef, [2 x i64])
88-
// CHECK: declare void @f4m(i32 noundef, i32 noundef, i32 noundef, i32 noundef, i32 noundef, [2 x i64])
89-
90-
91-
// Packed structure, overaligned, same as above.
92-
struct __attribute__((packed, aligned(16))) P16 {
93-
int x;
94-
long y;
95-
};
96-
97-
void f5(int, P16);
98-
void f5m(int, int, int, int, int, P16);
99-
void g5() {
100-
P16 s = {6, 7};
101-
f5(1, s);
102-
f5m(1, 2, 3, 4, 5, s);
103-
}
104-
// CHECK: define{{.*}} void @g5()
105-
// CHECK: call void @f5(i32 noundef 1, [2 x i64] [i64 30064771078, i64 0])
106-
// CHECK: void @f5m(i32 noundef 1, i32 noundef 2, i32 noundef 3, i32 noundef 4, i32 noundef 5, [2 x i64] [i64 30064771078, i64 0])
107-
// CHECK: declare void @f5(i32 noundef, [2 x i64])
108-
// CHECK: declare void @f5m(i32 noundef, i32 noundef, i32 noundef, i32 noundef, i32 noundef, [2 x i64])
109-
11015
//BitInt alignment
11116
struct BITINT129 {
11217
char ch;

clang/test/CodeGen/arm-vfp16-arguments2.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ struct S5 : B1 {
4242
// CHECK-FULL: define{{.*}} arm_aapcs_vfpcc %struct.S1 @_Z2f12S1(%struct.S1 returned %s1.coerce)
4343
struct S1 f1(struct S1 s1) { return s1; }
4444

45-
// CHECK-SOFT: define{{.*}} void @_Z2f22S2(ptr dead_on_unwind noalias writable writeonly sret(%struct.S2) align 8 captures(none) initializes((0, 16)) %agg.result, [4 x i32] %s2.coerce)
45+
// CHECK-SOFT: define{{.*}} void @_Z2f22S2(ptr dead_on_unwind noalias writable writeonly sret(%struct.S2) align 8 captures(none) initializes((0, 16)) %agg.result, [2 x i64] %s2.coerce)
4646
// CHECK-HARD: define{{.*}} arm_aapcs_vfpcc [2 x <2 x i32>] @_Z2f22S2([2 x <2 x i32>] returned %s2.coerce)
4747
// CHECK-FULL: define{{.*}} arm_aapcs_vfpcc %struct.S2 @_Z2f22S2(%struct.S2 %s2.coerce)
4848
struct S2 f2(struct S2 s2) { return s2; }

0 commit comments

Comments
 (0)