https://github.com/hvdijk updated 
https://github.com/llvm/llvm-project/pull/135564

>From 6e4491f58b96f4bff2cfcac774e1b15785f0e57c Mon Sep 17 00:00:00 2001
From: Harald van Dijk <harald.vand...@codeplay.com>
Date: Wed, 16 Apr 2025 03:08:42 +0100
Subject: [PATCH] [ARM, AArch64] Fix passing of structures with aligned base
 classes

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.

Alignment tests in aapcs64-align.cpp are moved to AArch64/args.cpp so
that we can test that this change is not applied to Apple.

Fixes #135551.
---
 clang/include/clang/AST/RecordLayout.h      |   7 +-
 clang/lib/AST/RecordLayoutBuilder.cpp       |   1 +
 clang/test/CodeGen/AArch64/args.cpp         | 111 +++++++++++++++++++-
 clang/test/CodeGen/aapcs64-align.cpp        |  95 -----------------
 clang/test/CodeGen/arm-vfp16-arguments2.cpp |   2 +-
 5 files changed, 115 insertions(+), 101 deletions(-)

diff --git a/clang/include/clang/AST/RecordLayout.h 
b/clang/include/clang/AST/RecordLayout.h
index dd18f9c49f84f..6cf08e76396e2 100644
--- a/clang/include/clang/AST/RecordLayout.h
+++ b/clang/include/clang/AST/RecordLayout.h
@@ -75,8 +75,9 @@ class ASTRecordLayout {
   // performance or backwards compatibility preserving (e.g. AIX-ABI).
   CharUnits PreferredAlignment;
 
-  // UnadjustedAlignment - Maximum of the alignments of the record members in
-  // characters.
+  // UnadjustedAlignment - Alignment of record in characters before alignment
+  // adjustments. Maximum of the alignments of the record members and base
+  // classes in characters.
   CharUnits UnadjustedAlignment;
 
   /// RequiredAlignment - The required alignment of the object.  In the MS-ABI
@@ -186,7 +187,7 @@ class ASTRecordLayout {
   CharUnits getPreferredAlignment() const { return PreferredAlignment; }
 
   /// getUnadjustedAlignment - Get the record alignment in characters, before
-  /// alignment adjustement.
+  /// alignment adjustment.
   CharUnits getUnadjustedAlignment() const { return UnadjustedAlignment; }
 
   /// getSize - Get the record size in characters.
diff --git a/clang/lib/AST/RecordLayoutBuilder.cpp 
b/clang/lib/AST/RecordLayoutBuilder.cpp
index ea353f88a8aec..dd932f6179f88 100644
--- a/clang/lib/AST/RecordLayoutBuilder.cpp
+++ b/clang/lib/AST/RecordLayoutBuilder.cpp
@@ -1302,6 +1302,7 @@ ItaniumRecordLayoutBuilder::LayoutBase(const 
BaseSubobjectInfo *Base) {
     setSize(std::max(getSize(), Offset + Layout.getSize()));
 
   // Remember max struct/class alignment.
+  UnadjustedAlignment = std::max(UnadjustedAlignment, BaseAlign);
   UpdateAlignment(BaseAlign, UnpackedAlignTo, PreferredBaseAlign);
 
   return Offset;
diff --git a/clang/test/CodeGen/AArch64/args.cpp 
b/clang/test/CodeGen/AArch64/args.cpp
index 6f1f3d5e2a062..3cb62d3119ecf 100644
--- a/clang/test/CodeGen/AArch64/args.cpp
+++ b/clang/test/CodeGen/AArch64/args.cpp
@@ -1,6 +1,6 @@
 // RUN: %clang_cc1 -triple arm64-apple-ios7.0 -target-abi darwinpcs -emit-llvm 
-o - %s | FileCheck %s --check-prefixes=CHECK,DARWIN
-// RUN: %clang_cc1 -triple aarch64-linux-gnu -emit-llvm -o - -x c %s | 
FileCheck %s --check-prefixes=CHECK,C
-// RUN: %clang_cc1 -triple aarch64-linux-gnu -emit-llvm -o - %s | FileCheck %s 
--check-prefixes=CHECK,CXX
+// RUN: %clang_cc1 -triple aarch64-linux-gnu -emit-llvm -o - -x c %s | 
FileCheck %s --check-prefixes=CHECK,C,AAPCS
+// RUN: %clang_cc1 -triple aarch64-linux-gnu -emit-llvm -o - %s | FileCheck %s 
--check-prefixes=CHECK,CXX,AAPCS
 
 // Empty structs are ignored for PCS purposes on Darwin and in C mode 
elsewhere.
 // 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, ...) {
   return b;
 }
 
+// Base case, nothing interesting.
+struct S {
+  long x, y;
+};
+
+// CHECK-LABEL: @g_S(
+// CHECK: call void @f_S(i64 noundef 1, [2 x i64] {{.*}})
+// CHECK: call void @fm_S(i64 noundef 1, i64 noundef 2, i64 noundef 3, i64 
noundef 4, i64 noundef 5, [2 x i64] {{.*}})
+EXTERNC void f_S(long, struct S);
+EXTERNC void fm_S(long, long, long, long, long, struct S);
+EXTERNC void g_S() {
+  struct S s = {6, 7};
+  f_S(1, s);
+  fm_S(1, 2, 3, 4, 5, s);
+}
+
+// Aligned struct passed according to its natural alignment.
+struct __attribute__((aligned(16))) S16 {
+  long x, y;
+};
+
+// CHECK-LABEL: @g_S16(
+// DARWIN: call void @f_S16(i64 noundef 1, i128 {{.*}})
+// AAPCS: call void @f_S16(i64 noundef 1, [2 x i64] {{.*}})
+// DARWIN: call void @fm_S16(i64 noundef 1, i64 noundef 2, i64 noundef 3, i64 
noundef 4, i64 noundef 5, i128 {{.*}})
+// AAPCS: call void @fm_S16(i64 noundef 1, i64 noundef 2, i64 noundef 3, i64 
noundef 4, i64 noundef 5, [2 x i64] {{.*}})
+EXTERNC void f_S16(long, struct S16);
+EXTERNC void fm_S16(long, long, long, long, long, struct S16);
+EXTERNC void g_S16() {
+  struct S16 s = {6, 7};
+  f_S16(1, s);
+  fm_S16(1, 2, 3, 4, 5, s);
+}
+
+// Aligned struct with increased natural alignment through an aligned field.
+struct SF16 {
+  __attribute__((aligned(16))) long x;
+  long y;
+};
+
+// CHECK-LABEL: @g_SF16(
+// DARWIN: call void @f_SF16(i64 noundef 1, i128 {{.*}})
+// AAPCS: call void @f_SF16(i64 noundef 1, i128 {{.*}})
+// DARWIN: call void @fm_SF16(i64 noundef 1, i64 noundef 2, i64 noundef 3, i64 
noundef 4, i64 noundef 5, i128 {{.*}})
+// AAPCS: call void @fm_SF16(i64 noundef 1, i64 noundef 2, i64 noundef 3, i64 
noundef 4, i64 noundef 5, i128 {{.*}})
+EXTERNC void f_SF16(long, struct SF16);
+EXTERNC void fm_SF16(long, long, long, long, long, struct SF16);
+EXTERNC void g_SF16() {
+  struct SF16 s = {6, 7};
+  f_SF16(1, s);
+  fm_SF16(1, 2, 3, 4, 5, s);
+}
+
+#ifdef __cplusplus
+// Aligned struct with increased natural alignment through an aligned base 
class.
+struct SB16 : S16 {};
+
+// DARWIN-LABEL: @g_SB16(
+// CXX-LABEL: @g_SB16(
+// DARWIN: call void @f_SB16(i64 noundef 1, i128 {{.*}})
+// CXX: call void @f_SB16(i64 noundef 1, i128 {{.*}})
+// DARWIN: call void @fm_SB16(i64 noundef 1, i64 noundef 2, i64 noundef 3, i64 
noundef 4, i64 noundef 5, i128 {{.*}})
+// CXX: call void @fm_SB16(i64 noundef 1, i64 noundef 2, i64 noundef 3, i64 
noundef 4, i64 noundef 5, i128 {{.*}})
+EXTERNC void f_SB16(long, struct SB16);
+EXTERNC void fm_SB16(long, long, long, long, long, struct SB16);
+EXTERNC void g_SB16() {
+  struct SB16 s = {6, 7};
+  f_SB16(1, s);
+  fm_SB16(1, 2, 3, 4, 5, s);
+}
+#endif
+
+// Packed structure.
+struct  __attribute__((packed)) SP {
+  int x;
+  long y;
+};
+
+// CHECK-LABEL: @g_SP(
+// CHECK: call void @f_SP(i32 noundef 1, [2 x i64] {{.*}})
+// CHECK: call void @fm_SP(i32 noundef 1, i32 noundef 2, i32 noundef 3, i32 
noundef 4, i32 noundef 5, [2 x i64] {{.*}})
+EXTERNC void f_SP(int, struct SP);
+EXTERNC void fm_SP(int, int, int, int, int, struct SP);
+EXTERNC void g_SP() {
+  struct SP s = {6, 7};
+  f_SP(1, s);
+  fm_SP(1, 2, 3, 4, 5, s);
+}
+
+// Packed structure, overaligned, same as above.
+struct  __attribute__((packed, aligned(16))) SP16 {
+  int x;
+  long y;
+};
+
+// CHECK-LABEL: @g_SP16(
+// DARWIN: call void @f_SP16(i32 noundef 1, i128 {{.*}})
+// AAPCS: call void @f_SP16(i32 noundef 1, [2 x i64] {{.*}})
+// DARWIN: call void @fm_SP16(i32 noundef 1, i32 noundef 2, i32 noundef 3, i32 
noundef 4, i32 noundef 5, i128 {{.*}})
+// AAPCS: call void @fm_SP16(i32 noundef 1, i32 noundef 2, i32 noundef 3, i32 
noundef 4, i32 noundef 5, [2 x i64] {{.*}})
+EXTERNC void f_SP16(int, struct SP16);
+EXTERNC void fm_SP16(int, int, int, int, int, struct SP16);
+EXTERNC void g_SP16() {
+  struct SP16 s = {6, 7};
+  f_SP16(1, s);
+  fm_SP16(1, 2, 3, 4, 5, s);
+}
diff --git a/clang/test/CodeGen/aapcs64-align.cpp 
b/clang/test/CodeGen/aapcs64-align.cpp
index e69faf231936c..1c26d68e434f4 100644
--- a/clang/test/CodeGen/aapcs64-align.cpp
+++ b/clang/test/CodeGen/aapcs64-align.cpp
@@ -12,101 +12,6 @@ extern "C" {
 // CHECK: @sizeof_RidiculouslyOverSizedBitfield ={{.*}} global i32 32
 // CHECK: @alignof_RidiculouslyOverSizedBitfield ={{.*}} global i32 16
 
-// Base case, nothing interesting.
-struct S {
-  long x, y;
-};
-
-void f0(long, S);
-void f0m(long, long, long, long, long, S);
-void g0() {
-  S s = {6, 7};
-  f0(1, s);
-  f0m(1, 2, 3, 4, 5, s);
-}
-// CHECK: define{{.*}} void @g0
-// CHECK: call void @f0(i64 noundef 1, [2 x i64] [i64 6, i64 7]
-// CHECK: call void @f0m{{.*}}[2 x i64] [i64 6, i64 7]
-// CHECK: declare void @f0(i64 noundef, [2 x i64])
-// CHECK: declare void @f0m(i64 noundef, i64 noundef, i64 noundef, i64 
noundef, i64 noundef, [2 x i64])
-
-// Aligned struct, passed according to its natural alignment.
-struct __attribute__((aligned(16))) S16 {
-  long x, y;
-} s16;
-
-void f1(long, S16);
-void f1m(long, long, long, long, long, S16);
-void g1() {
-  S16 s = {6, 7};
-  f1(1, s);
-  f1m(1, 2, 3, 4, 5, s);
-}
-// CHECK: define{{.*}} void @g1
-// CHECK: call void @f1{{.*}}[2 x i64] [i64 6, i64 7]
-// CHECK: call void @f1m{{.*}}[2 x i64] [i64 6, i64 7]
-// CHECK: declare void @f1(i64 noundef, [2 x i64])
-// CHECK: declare void @f1m(i64 noundef, i64 noundef, i64 noundef, i64 
noundef, i64 noundef, [2 x i64])
-
-// Increased natural alignment.
-struct SF16 {
-  long x __attribute__((aligned(16)));
-  long y;
-};
-
-void f3(long, SF16);
-void f3m(long, long, long, long, long, SF16);
-void g3() {
-  SF16 s = {6, 7};
-  f3(1, s);
-  f3m(1, 2, 3, 4, 5, s);
-}
-// CHECK: define{{.*}} void @g3
-// CHECK: call void @f3(i64 noundef 1, i128 129127208515966861318)
-// CHECK: call void @f3m(i64 noundef 1, i64 noundef 2, i64 noundef 3, i64 
noundef 4, i64 noundef 5, i128 129127208515966861318)
-// CHECK: declare void @f3(i64 noundef, i128)
-// CHECK: declare void @f3m(i64 noundef, i64 noundef, i64 noundef, i64 
noundef, i64 noundef, i128)
-
-
-// Packed structure.
-struct  __attribute__((packed)) P {
-  int x;
-  long u;
-};
-
-void f4(int, P);
-void f4m(int, int, int, int, int, P);
-void g4() {
-  P s = {6, 7};
-  f4(1, s);
-  f4m(1, 2, 3, 4, 5, s);
-}
-// CHECK: define{{.*}} void @g4()
-// CHECK: call void @f4(i32 noundef 1, [2 x i64] [i64 30064771078, i64 0])
-// 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])
-// CHECK: declare void @f4(i32 noundef, [2 x i64])
-// CHECK: declare void @f4m(i32 noundef, i32 noundef, i32 noundef, i32 
noundef, i32 noundef, [2 x i64])
-
-
-// Packed structure, overaligned, same as above.
-struct  __attribute__((packed, aligned(16))) P16 {
-  int x;
-  long y;
-};
-
-void f5(int, P16);
-void f5m(int, int, int, int, int, P16);
-  void g5() {
-    P16 s = {6, 7};
-    f5(1, s);
-    f5m(1, 2, 3, 4, 5, s);
-}
-// CHECK: define{{.*}} void @g5()
-// CHECK: call void @f5(i32 noundef 1, [2 x i64] [i64 30064771078, i64 0])
-// 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])
-// CHECK: declare void @f5(i32 noundef, [2 x i64])
-// CHECK: declare void @f5m(i32 noundef, i32 noundef, i32 noundef, i32 
noundef, i32 noundef, [2 x i64])
-
 //BitInt alignment
 struct BITINT129 {
     char ch;
diff --git a/clang/test/CodeGen/arm-vfp16-arguments2.cpp 
b/clang/test/CodeGen/arm-vfp16-arguments2.cpp
index 6e9a24e70c141..7273f64effa92 100644
--- a/clang/test/CodeGen/arm-vfp16-arguments2.cpp
+++ b/clang/test/CodeGen/arm-vfp16-arguments2.cpp
@@ -42,7 +42,7 @@ struct S5 : B1 {
 // CHECK-FULL: define{{.*}} arm_aapcs_vfpcc %struct.S1 @_Z2f12S1(%struct.S1 
returned %s1.coerce)
 struct S1 f1(struct S1 s1) { return s1; }
 
-// 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)
+// 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)
 // CHECK-HARD: define{{.*}} arm_aapcs_vfpcc [2 x <2 x i32>] @_Z2f22S2([2 x <2 
x i32>] returned %s2.coerce)
 // CHECK-FULL: define{{.*}} arm_aapcs_vfpcc %struct.S2 @_Z2f22S2(%struct.S2 
%s2.coerce)
 struct S2 f2(struct S2 s2) { return s2; }

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to