Skip to content

[clang][SPARC] Treat empty structs as if it's a one-bit type in the CC #90338

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
May 15, 2024
Merged
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
5 changes: 4 additions & 1 deletion clang/lib/CodeGen/Targets/Sparc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,10 @@ SparcV9ABIInfo::classifyType(QualType Ty, unsigned SizeLimit) const {

CoerceBuilder CB(getVMContext(), getDataLayout());
CB.addStruct(0, StrTy);
CB.pad(llvm::alignTo(CB.DL.getTypeSizeInBits(StrTy), 64));
// All structs, even empty ones, should take up a register argument slot,
// so pin the minimum struct size to one bit.
CB.pad(llvm::alignTo(
std::max(CB.DL.getTypeSizeInBits(StrTy).getKnownMinValue(), 1UL), 64));

// Try to use the original type for coercion.
llvm::Type *CoerceTy = CB.isUsableType(StrTy) ? StrTy : CB.getType();
Expand Down
41 changes: 41 additions & 0 deletions clang/test/CodeGen/sparcv9-abi.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,47 @@ char f_int_4(char x) { return x; }
// CHECK-LABEL: define{{.*}} fp128 @f_ld(fp128 noundef %x)
long double f_ld(long double x) { return x; }

// Zero-sized structs reserves an argument register slot if passed directly.
struct empty {};
struct emptyarr { struct empty a[10]; };

// CHECK-LABEL: define{{.*}} i64 @f_empty(i64 %x.coerce)
struct empty f_empty(struct empty x) { return x; }

// CHECK-LABEL: define{{.*}} i64 @f_emptyarr(i64 %x.coerce)
struct empty f_emptyarr(struct emptyarr x) { return x.a[0]; }

// CHECK-LABEL: define{{.*}} i64 @f_emptyvar(i32 noundef zeroext %count, ...)
long f_emptyvar(unsigned count, ...) {
long ret;
va_list args;
va_start(args, count);

// CHECK: %[[CUR:[^ ]+]] = load ptr, ptr %args
// CHECK-DAG: %[[NXT:[^ ]+]] = getelementptr inbounds i8, ptr %[[CUR]], i64 8
// CHECK-DAG: store ptr %[[NXT]], ptr %args
va_arg(args, struct empty);

// CHECK: %[[CUR:[^ ]+]] = load ptr, ptr %args
// CHECK-DAG: %[[NXT:[^ ]+]] = getelementptr inbounds i8, ptr %[[CUR]], i64 8
// CHECK-DAG: store ptr %[[NXT]], ptr %args
// CHECK-DAG: load i64, ptr %[[CUR]]
ret = va_arg(args, long);
va_end(args);
return ret;
}

// If the zero-sized struct is contained in a non-zero-sized struct,
// though, it doesn't reserve any registers.
struct emptymixed { struct empty a; long b; };
struct emptyflex { unsigned count; struct empty data[10]; };

// CHECK-LABEL: define{{.*}} i64 @f_emptymixed(i64 %x.coerce)
long f_emptymixed(struct emptymixed x) { return x.b; }

// CHECK-LABEL: define{{.*}} i64 @f_emptyflex(i64 %x.coerce, i64 noundef %y)
long f_emptyflex(struct emptyflex x, long y) { return y; }

// Small structs are passed in registers.
struct small {
int *a, *b;
Expand Down
24 changes: 24 additions & 0 deletions clang/test/CodeGen/sparcv9-class-return.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// RUN: %clang_cc1 -triple sparcv9-unknown-unknown -emit-llvm %s -o - | FileCheck %s

class Empty {
};

class Long : public Empty {
public:
long l;
};

// CHECK: define{{.*}} i64 @_Z4foo15Empty(i64 %e.coerce)
Empty foo1(Empty e) {
return e;
}

// CHECK: define{{.*}} %class.Long @_Z4foo24Long(i64 %l.coerce)
Long foo2(Long l) {
return l;
}

// CHECK: define{{.*}} i64 @_Z4foo34Long(i64 %l.coerce)
long foo3(Long l) {
return l.l;
}
Loading