Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,9 @@ C++ Specific Potentially Breaking Changes
ABI Changes in This Version
---------------------------

- Let C++ empty record fall through to the standard argument-handling path instead of
always pass a single ``i8`` according to aarch64 AAPCS rules.

AST Dumping Potentially Breaking Changes
----------------------------------------
- How nested name specifiers are dumped and printed changes, keeping track of clang AST changes.
Expand Down
9 changes: 6 additions & 3 deletions clang/lib/CodeGen/Targets/AArch64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -422,6 +422,12 @@ ABIArgInfo AArch64ABIInfo::classifyArgumentType(QualType Ty, bool IsVariadicFn,
}

// Empty records:
// AAPCS64 does not say that empty records are ignored as arguments,
// but other compilers do so in certain situations, and we copy that behavior.
// Those situations are in fact language-mode-specific, which seems really
// unfortunate, but it's something we just have to accept. If this doesn't
// apply, just fall through to the standard argument-handling path.
// Darwin overrides the psABI here to ignore all empty records in all modes.
uint64_t Size = getContext().getTypeSize(Ty);
bool IsEmpty = isEmptyRecord(getContext(), Ty, true);
if (!Ty->isSVESizelessBuiltinType() && (IsEmpty || Size == 0)) {
Expand All @@ -434,9 +440,6 @@ ABIArgInfo AArch64ABIInfo::classifyArgumentType(QualType Ty, bool IsVariadicFn,
// behaviour here.
if (Size == 0)
return ABIArgInfo::getIgnore();

// Otherwise, they are passed as if they have a size of 1 byte.
return ABIArgInfo::getDirect(llvm::Type::getInt8Ty(getVMContext()));
}

// Homogeneous Floating-point Aggregates (HFAs) need to be expanded.
Expand Down
20 changes: 19 additions & 1 deletion clang/test/CodeGen/AArch64/args.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,29 @@ struct Empty {};

// DARWIN: define{{.*}} i32 @empty_arg(i32 noundef %a)
// C: define{{.*}} i32 @empty_arg(i32 noundef %a)
// CXX: define{{.*}} i32 @empty_arg(i8 %e.coerce, i32 noundef %a)
// CXX: define{{.*}} i32 @empty_arg(i64 %e.coerce, i32 noundef %a)
EXTERNC int empty_arg(struct Empty e, int a) {
return a;
}

// CXX: define{{.*}} i32 @empty_align8_arg(i64 %a.coerce, i32 noundef %b)
struct EmptyAlign8 { int __attribute__((aligned(8))) : 0; };
EXTERNC int empty_align8_arg(struct EmptyAlign8 a, int b) {
return b;
}

// CXX: define{{.*}} i32 @empty_align16_arg(i128 %a.coerce, i32 noundef %b)
struct EmptyAlign16 { long long int __attribute__((aligned(16))) : 0; };
EXTERNC int empty_align16_arg(struct EmptyAlign16 a, int b) {
return b;
}

// CXX: define{{.*}} i32 @empty_align32_arg(ptr dead_on_return noundef %a, i32 noundef %b)
struct EmptyAlign32 { long long int __attribute__((aligned(32))) : 0; };
EXTERNC int empty_align32_arg(struct EmptyAlign32 a, int b) {
return b;
}

// DARWIN: define{{.*}} void @empty_ret()
// C: define{{.*}} void @empty_ret()
// CXX: define{{.*}} void @empty_ret()
Expand Down
10 changes: 6 additions & 4 deletions clang/test/CodeGen/AArch64/struct-coerce-using-ptr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -575,19 +575,21 @@ void TSpp_align16(SSpp_align16 s) { *s.a.x = 1; }
struct Sempty {
};
// CHECK-A64-LABEL: define dso_local void @_Z6Tempty6Sempty(
// CHECK-A64-SAME: i8 [[S_COERCE:%.*]]) #[[ATTR0]] {
// CHECK-A64-SAME: i64 [[S_COERCE:%.*]]) #[[ATTR0]] {
// CHECK-A64-NEXT: [[ENTRY:.*:]]
// CHECK-A64-NEXT: [[S:%.*]] = alloca [[STRUCT_SEMPTY:%.*]], align 1
// CHECK-A64-NEXT: [[COERCE_DIVE:%.*]] = getelementptr inbounds nuw [[STRUCT_SEMPTY]], ptr [[S]], i32 0, i32 0
// CHECK-A64-NEXT: store i8 [[S_COERCE]], ptr [[COERCE_DIVE]], align 1
// CHECK-A64-NEXT: [[COERCE_VAL_II:%.*]] = trunc i64 [[S_COERCE]] to i8
// CHECK-A64-NEXT: store i8 [[COERCE_VAL_II]], ptr [[COERCE_DIVE]], align 1
// CHECK-A64-NEXT: ret void
//
// CHECK-A64_32-LABEL: define void @_Z6Tempty6Sempty(
// CHECK-A64_32-SAME: i8 [[S_COERCE:%.*]]) #[[ATTR0]] {
// CHECK-A64_32-SAME: i64 [[S_COERCE:%.*]]) #[[ATTR0]] {
// CHECK-A64_32-NEXT: [[ENTRY:.*:]]
// CHECK-A64_32-NEXT: [[S:%.*]] = alloca [[STRUCT_SEMPTY:%.*]], align 1
// CHECK-A64_32-NEXT: [[COERCE_DIVE:%.*]] = getelementptr inbounds nuw [[STRUCT_SEMPTY]], ptr [[S]], i32 0, i32 0
// CHECK-A64_32-NEXT: store i8 [[S_COERCE]], ptr [[COERCE_DIVE]], align 1
// CHECK-A64_32-NEXT: [[COERCE_VAL_II:%.*]] = trunc i64 [[S_COERCE]] to i8
// CHECK-A64_32-NEXT: store i8 [[COERCE_VAL_II]], ptr [[COERCE_DIVE]], align 1
// CHECK-A64_32-NEXT: ret void
//
void Tempty(Sempty s) { }
Expand Down
4 changes: 2 additions & 2 deletions clang/test/CodeGen/arm64-microsoft-arguments.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ S4 f4() {

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

class P1 {
public:
Expand All @@ -76,7 +76,7 @@ P1 Q1::bar() {

// Pass and return from instance method called from free function.
// CHECK: define {{.*}} void {{.*}}bar{{.*}}()
// CHECK: call void {{.*}}foo@P2{{.*}}(ptr noundef{{[^,]*}} %ref.tmp, ptr dead_on_unwind inreg writable sret(%class.P2) align 1 %retval, i8 %0)
// CHECK: call void {{.*}}foo@P2{{.*}}(ptr noundef{{[^,]*}} %ref.tmp, ptr dead_on_unwind inreg writable sret(%class.P2) align 1 %retval, i64 %coerce.val.ii)
class P2 {
public:
P2 foo(P2 x);
Expand Down
2 changes: 1 addition & 1 deletion clang/test/CodeGenCXX/aarch64-arguments.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -triple arm64-none-linux -emit-llvm -w -o - %s | FileCheck -check-prefix=PCS %s

// PCS: define{{.*}} void @{{.*}}(i8 %a
// PCS: define{{.*}} void @{{.*}}(i64 %a.coerce)
struct s0 {};
void f0(s0 a) {}
2 changes: 1 addition & 1 deletion clang/test/CodeGenCXX/arm64-darwinpcs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ void test_extensions(bool a, char b, short c) {}

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

struct HFA {
Expand Down