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
11 changes: 8 additions & 3 deletions clang/lib/CodeGen/Targets/Sparc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,7 @@ SparcV9ABIInfo::classifyType(QualType Ty, unsigned SizeLimit) const {
return ABIArgInfo::getIgnore();

uint64_t Size = getContext().getTypeSize(Ty);
unsigned Alignment = getContext().getTypeAlign(Ty);

// Anything too big to fit in registers is passed with an explicit indirect
// pointer / sret pointer.
Expand Down Expand Up @@ -275,10 +276,14 @@ SparcV9ABIInfo::classifyType(QualType Ty, unsigned SizeLimit) const {
// Try to use the original type for coercion.
llvm::Type *CoerceTy = CB.isUsableType(StrTy) ? StrTy : CB.getType();

// We use a pair of i64 for 9-16 byte aggregate with 8 byte alignment.
// For 9-16 byte aggregates with 16 byte alignment, we use i128.
llvm::Type *WideTy = llvm::Type::getIntNTy(getVMContext(), 128);
bool UseI128 = (Size > 64) && (Size <= 128) && (Alignment == 128);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens if the size is bigger than 16? Not sure how much it matters, since SizeLimit is 128 for arguments, but we should have some test coverage for return types.

Copy link
Contributor Author

@koachan koachan Aug 29, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Structs 17-32 bytes are passed indirectly, but returned in registers; structs over 32 bytes are also returned indirectly.

Structures or unions larger than sixteen bytes are copied by the caller and passed indirectly; the caller will pass the address of a correctly aligned structure value.

Structure and union return types up to thirty-two bytes in size are returned in registers. [...] For types with a larger size the caller allocates an area large enough and aligned properly to hold the return value, and passes a pointer to that area as an implicit first argument (of type pointer-to-data) to the callee.

I think for that case it's already tested in sparcv9-abi.c as the struct medium and struct large cases?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please also add coverage for a "medium" struct with 128-bit alignment.

Copy link
Contributor Author

@koachan koachan Sep 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, as medium_aligned~


if (CB.InReg)
return ABIArgInfo::getDirectInReg(CoerceTy);
else
return ABIArgInfo::getDirect(CoerceTy);
return ABIArgInfo::getDirectInReg(UseI128 ? WideTy : CoerceTy);
return ABIArgInfo::getDirect(UseI128 ? WideTy : CoerceTy);
}

RValue SparcV9ABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
Expand Down
21 changes: 21 additions & 0 deletions clang/test/CodeGen/sparcv9-abi.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,21 @@ long double f_ld(long double x) { return x; }
struct empty {};
struct emptyarr { struct empty a[10]; };

// 16-byte structs with 16-byte alignment gets passed as if i128.
struct align16 { _Alignas(16) int x; };

// 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{{.*}} void @f_aligncaller(i128 %a.coerce)
void f_aligncallee(int pad, struct align16 a);
void f_aligncaller(struct align16 a) {
f_aligncallee(0, a);
}

// CHECK-LABEL: define{{.*}} i64 @f_emptyvar(i32 noundef zeroext %count, ...)
long f_emptyvar(unsigned count, ...) {
long ret;
Expand Down Expand Up @@ -80,13 +89,25 @@ struct medium {
int *c, *d;
};

struct medium_aligned {
_Alignas(16) int *a;
int *b, *c, *d;
};

// CHECK-LABEL: define{{.*}} %struct.medium @f_medium(ptr dead_on_return noundef %x)
struct medium f_medium(struct medium x) {
x.a += *x.b;
x.b = 0;
return x;
}

// CHECK-LABEL: define{{.*}} %struct.medium_aligned @f_medium_aligned(ptr dead_on_return noundef %x)
struct medium_aligned f_medium_aligned(struct medium_aligned x) {
x.a += *x.b;
x.b = 0;
return x;
}

// Large structs are also returned indirectly.
struct large {
int *a, *b;
Expand Down
3 changes: 2 additions & 1 deletion llvm/lib/Target/Sparc/SparcISelLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,8 @@ static bool Analyze_CC_Sparc64_Full(bool IsReturn, unsigned &ValNo, MVT &ValVT,

// Stack space is allocated for all arguments starting from [%fp+BIAS+128].
unsigned size = (LocVT == MVT::f128) ? 16 : 8;
Align alignment = (LocVT == MVT::f128) ? Align(16) : Align(8);
Align alignment =
(LocVT == MVT::f128 || ArgFlags.isSplit()) ? Align(16) : Align(8);
unsigned Offset = State.AllocateStack(size, alignment);
unsigned Reg = 0;

Expand Down
15 changes: 14 additions & 1 deletion llvm/test/CodeGen/SPARC/64abi.ll
Original file line number Diff line number Diff line change
Expand Up @@ -473,15 +473,28 @@ declare i64 @receive_fp128(i64 %a, ...)
; HARD-DAG: ldx [%sp+[[Offset0]]], %o2
; HARD-DAG: ldx [%sp+[[Offset1]]], %o3
; SOFT-DAG: mov %i0, %o0
; SOFT-DAG: mov %i1, %o1
; SOFT-DAG: mov %i2, %o2
; SOFT-DAG: mov %i3, %o3
; CHECK: call receive_fp128
define i64 @test_fp128_variable_args(i64 %a, fp128 %b) {
entry:
%0 = call i64 (i64, ...) @receive_fp128(i64 %a, fp128 %b)
ret i64 %0
}

declare i64 @receive_i128(i64 %a, i128 %b)

; CHECK-LABEL: test_i128_args:
; CHECK: mov %i3, %o3
; CHECK: mov %i2, %o2
; CHECK: mov %i0, %o0
; CHECK: call receive_i128
define i64 @test_i128_args(i64 %a, i128 %b) {
entry:
%0 = call i64 @receive_i128(i64 %a, i128 %b)
ret i64 %0
}

; CHECK-LABEL: test_call_libfunc:
; HARD: st %f1, [%fp+[[Offset0:[0-9]+]]]
; HARD: fmovs %f3, %f1
Expand Down