Skip to content

Commit b49d104

Browse files
author
git apple-llvm automerger
committed
Merge commit '9ee4ac8a8359' from llvm.org/release/21.x into stable/21.x
2 parents b7b910b + 9ee4ac8 commit b49d104

File tree

4 files changed

+129
-70
lines changed

4 files changed

+129
-70
lines changed

clang/lib/CodeGen/Targets/Sparc.cpp

Lines changed: 57 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
#include "ABIInfoImpl.h"
1010
#include "TargetInfo.h"
11+
#include <algorithm>
1112

1213
using namespace clang;
1314
using namespace clang::CodeGen;
@@ -109,7 +110,8 @@ class SparcV9ABIInfo : public ABIInfo {
109110
SparcV9ABIInfo(CodeGenTypes &CGT) : ABIInfo(CGT) {}
110111

111112
private:
112-
ABIArgInfo classifyType(QualType RetTy, unsigned SizeLimit) const;
113+
ABIArgInfo classifyType(QualType RetTy, unsigned SizeLimit,
114+
unsigned &RegOffset) const;
113115
void computeInfo(CGFunctionInfo &FI) const override;
114116
RValue EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty,
115117
AggValueSlot Slot) const override;
@@ -222,127 +224,114 @@ class SparcV9ABIInfo : public ABIInfo {
222224
};
223225
} // end anonymous namespace
224226

225-
ABIArgInfo
226-
SparcV9ABIInfo::classifyType(QualType Ty, unsigned SizeLimit) const {
227+
ABIArgInfo SparcV9ABIInfo::classifyType(QualType Ty, unsigned SizeLimit,
228+
unsigned &RegOffset) const {
227229
if (Ty->isVoidType())
228230
return ABIArgInfo::getIgnore();
229231

230-
uint64_t Size = getContext().getTypeSize(Ty);
232+
auto &Context = getContext();
233+
auto &VMContext = getVMContext();
234+
235+
uint64_t Size = Context.getTypeSize(Ty);
236+
unsigned Alignment = Context.getTypeAlign(Ty);
237+
bool NeedPadding = (Alignment > 64) && (RegOffset % 2 != 0);
231238

232239
// Anything too big to fit in registers is passed with an explicit indirect
233240
// pointer / sret pointer.
234-
if (Size > SizeLimit)
241+
if (Size > SizeLimit) {
242+
RegOffset += 1;
235243
return getNaturalAlignIndirect(
236244
Ty, /*AddrSpace=*/getDataLayout().getAllocaAddrSpace(),
237245
/*ByVal=*/false);
246+
}
238247

239248
// Treat an enum type as its underlying type.
240249
if (const EnumType *EnumTy = Ty->getAs<EnumType>())
241250
Ty = EnumTy->getDecl()->getIntegerType();
242251

243252
// Integer types smaller than a register are extended.
244-
if (Size < 64 && Ty->isIntegerType())
253+
if (Size < 64 && Ty->isIntegerType()) {
254+
RegOffset += 1;
245255
return ABIArgInfo::getExtend(Ty);
256+
}
246257

247258
if (const auto *EIT = Ty->getAs<BitIntType>())
248-
if (EIT->getNumBits() < 64)
259+
if (EIT->getNumBits() < 64) {
260+
RegOffset += 1;
249261
return ABIArgInfo::getExtend(Ty);
262+
}
250263

251264
// Other non-aggregates go in registers.
252-
if (!isAggregateTypeForABI(Ty))
265+
if (!isAggregateTypeForABI(Ty)) {
266+
RegOffset += Size / 64;
253267
return ABIArgInfo::getDirect();
268+
}
254269

255270
// If a C++ object has either a non-trivial copy constructor or a non-trivial
256271
// destructor, it is passed with an explicit indirect pointer / sret pointer.
257-
if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, getCXXABI()))
272+
if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, getCXXABI())) {
273+
RegOffset += 1;
258274
return getNaturalAlignIndirect(Ty, getDataLayout().getAllocaAddrSpace(),
259275
RAA == CGCXXABI::RAA_DirectInMemory);
276+
}
260277

261278
// This is a small aggregate type that should be passed in registers.
262279
// Build a coercion type from the LLVM struct type.
263280
llvm::StructType *StrTy = dyn_cast<llvm::StructType>(CGT.ConvertType(Ty));
264-
if (!StrTy)
281+
if (!StrTy) {
282+
RegOffset += Size / 64;
265283
return ABIArgInfo::getDirect();
284+
}
266285

267-
CoerceBuilder CB(getVMContext(), getDataLayout());
286+
CoerceBuilder CB(VMContext, getDataLayout());
268287
CB.addStruct(0, StrTy);
269288
// All structs, even empty ones, should take up a register argument slot,
270289
// so pin the minimum struct size to one bit.
271290
CB.pad(llvm::alignTo(
272291
std::max(CB.DL.getTypeSizeInBits(StrTy).getKnownMinValue(), uint64_t(1)),
273292
64));
293+
RegOffset += CB.Size / 64;
294+
295+
// If we're dealing with overaligned structs we may need to add a padding in
296+
// the front, to preserve the correct register-memory mapping.
297+
//
298+
// See SCD 2.4.1, pages 3P-11 and 3P-12.
299+
llvm::Type *Padding =
300+
NeedPadding ? llvm::Type::getInt64Ty(VMContext) : nullptr;
301+
RegOffset += NeedPadding ? 1 : 0;
274302

275303
// Try to use the original type for coercion.
276304
llvm::Type *CoerceTy = CB.isUsableType(StrTy) ? StrTy : CB.getType();
277305

278-
if (CB.InReg)
279-
return ABIArgInfo::getDirectInReg(CoerceTy);
280-
else
281-
return ABIArgInfo::getDirect(CoerceTy);
306+
ABIArgInfo AAI = ABIArgInfo::getDirect(CoerceTy, 0, Padding);
307+
AAI.setInReg(CB.InReg);
308+
return AAI;
282309
}
283310

284311
RValue SparcV9ABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
285312
QualType Ty, AggValueSlot Slot) const {
286-
ABIArgInfo AI = classifyType(Ty, 16 * 8);
287-
llvm::Type *ArgTy = CGT.ConvertType(Ty);
288-
if (AI.canHaveCoerceToType() && !AI.getCoerceToType())
289-
AI.setCoerceToType(ArgTy);
290-
291313
CharUnits SlotSize = CharUnits::fromQuantity(8);
314+
auto TInfo = getContext().getTypeInfoInChars(Ty);
292315

293-
CGBuilderTy &Builder = CGF.Builder;
294-
Address Addr = Address(Builder.CreateLoad(VAListAddr, "ap.cur"),
295-
getVAListElementType(CGF), SlotSize);
296-
llvm::Type *ArgPtrTy = CGF.UnqualPtrTy;
297-
298-
auto TypeInfo = getContext().getTypeInfoInChars(Ty);
299-
300-
Address ArgAddr = Address::invalid();
301-
CharUnits Stride;
302-
switch (AI.getKind()) {
303-
case ABIArgInfo::Expand:
304-
case ABIArgInfo::CoerceAndExpand:
305-
case ABIArgInfo::InAlloca:
306-
llvm_unreachable("Unsupported ABI kind for va_arg");
307-
308-
case ABIArgInfo::Extend: {
309-
Stride = SlotSize;
310-
CharUnits Offset = SlotSize - TypeInfo.Width;
311-
ArgAddr = Builder.CreateConstInBoundsByteGEP(Addr, Offset, "extend");
312-
break;
313-
}
314-
315-
case ABIArgInfo::Direct: {
316-
auto AllocSize = getDataLayout().getTypeAllocSize(AI.getCoerceToType());
317-
Stride = CharUnits::fromQuantity(AllocSize).alignTo(SlotSize);
318-
ArgAddr = Addr;
319-
break;
320-
}
321-
322-
case ABIArgInfo::Indirect:
323-
case ABIArgInfo::IndirectAliased:
324-
Stride = SlotSize;
325-
ArgAddr = Addr.withElementType(ArgPtrTy);
326-
ArgAddr = Address(Builder.CreateLoad(ArgAddr, "indirect.arg"), ArgTy,
327-
TypeInfo.Align);
328-
break;
316+
// Zero-sized types have a width of one byte for parameter passing purposes.
317+
TInfo.Width = std::max(TInfo.Width, CharUnits::fromQuantity(1));
329318

330-
case ABIArgInfo::Ignore:
331-
return Slot.asRValue();
332-
}
333-
334-
// Update VAList.
335-
Address NextPtr = Builder.CreateConstInBoundsByteGEP(Addr, Stride, "ap.next");
336-
Builder.CreateStore(NextPtr.emitRawPointer(CGF), VAListAddr);
337-
338-
return CGF.EmitLoadOfAnyValue(
339-
CGF.MakeAddrLValue(ArgAddr.withElementType(ArgTy), Ty), Slot);
319+
// Arguments bigger than 2*SlotSize bytes are passed indirectly.
320+
return emitVoidPtrVAArg(CGF, VAListAddr, Ty,
321+
/*IsIndirect=*/TInfo.Width > 2 * SlotSize, TInfo,
322+
SlotSize,
323+
/*AllowHigherAlign=*/true, Slot);
340324
}
341325

342326
void SparcV9ABIInfo::computeInfo(CGFunctionInfo &FI) const {
343-
FI.getReturnInfo() = classifyType(FI.getReturnType(), 32 * 8);
327+
unsigned RetOffset = 0;
328+
ABIArgInfo RetType = classifyType(FI.getReturnType(), 32 * 8, RetOffset);
329+
FI.getReturnInfo() = RetType;
330+
331+
// Indirect returns will have its pointer passed as an argument.
332+
unsigned ArgOffset = RetType.isIndirect() ? RetOffset : 0;
344333
for (auto &I : FI.arguments())
345-
I.info = classifyType(I.type, 16 * 8);
334+
I.info = classifyType(I.type, 16 * 8, ArgOffset);
346335
}
347336

348337
namespace {

clang/test/CodeGen/sparcv9-abi.c

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,35 @@ long double f_ld(long double x) { return x; }
2525
struct empty {};
2626
struct emptyarr { struct empty a[10]; };
2727

28+
// In 16-byte structs, 16-byte aligned members are expanded
29+
// to their corresponding i128/f128 types.
30+
struct align16_int { _Alignas(16) int x; };
31+
struct align16_mixed { _Alignas(16) int x; double y; };
32+
struct align16_longdouble { long double x; };
33+
2834
// CHECK-LABEL: define{{.*}} i64 @f_empty(i64 %x.coerce)
2935
struct empty f_empty(struct empty x) { return x; }
3036

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

40+
// CHECK-LABEL: define{{.*}} void @f_aligncaller(i64 %a.coerce0, i64 %a.coerce1)
41+
// CHECK-LABEL: declare{{.*}} void @f_aligncallee(i32 noundef signext, i64, i64, i64)
42+
void f_aligncallee(int pad, struct align16_int a);
43+
void f_aligncaller(struct align16_int a) {
44+
f_aligncallee(0, a);
45+
}
46+
47+
// CHECK-LABEL: define{{.*}} double @f_mixed_aligned(i64 noundef %a, i64 %0, i64 %b.coerce0, double %b.coerce1)
48+
double f_mixed_aligned(long a, struct align16_mixed b) {
49+
return b.y;
50+
}
51+
52+
// CHECK-LABEL: define{{.*}} fp128 @f_longdouble(i64 noundef %a, i64 %0, fp128 %b.coerce)
53+
long double f_longdouble(long a, struct align16_longdouble b) {
54+
return b.x;
55+
}
56+
3457
// CHECK-LABEL: define{{.*}} i64 @f_emptyvar(i32 noundef zeroext %count, ...)
3558
long f_emptyvar(unsigned count, ...) {
3659
long ret;
@@ -80,13 +103,25 @@ struct medium {
80103
int *c, *d;
81104
};
82105

106+
struct medium_aligned {
107+
_Alignas(16) int *a;
108+
int *b, *c, *d;
109+
};
110+
83111
// CHECK-LABEL: define{{.*}} %struct.medium @f_medium(ptr noundef %x)
84112
struct medium f_medium(struct medium x) {
85113
x.a += *x.b;
86114
x.b = 0;
87115
return x;
88116
}
89117

118+
// CHECK-LABEL: define{{.*}} %struct.medium_aligned @f_medium_aligned(ptr noundef %x)
119+
struct medium_aligned f_medium_aligned(struct medium_aligned x) {
120+
x.a += *x.b;
121+
x.b = 0;
122+
return x;
123+
}
124+
90125
// Large structs are also returned indirectly.
91126
struct large {
92127
int *a, *b;
@@ -101,6 +136,15 @@ struct large f_large(struct large x) {
101136
return x;
102137
}
103138

139+
// Large returns are converted into a pointer argument.
140+
// Such conversion should preserve the alignment of overaligned arguments.
141+
// define{{.*}} void @f_largereturn_aligned(ptr dead_on_unwind noalias writable sret(%struct.large) align 8 %agg.result, i64 %0, i64 %x.coerce0, i64 %x.coerce1)
142+
struct large f_largereturn_aligned(struct align16_int x) {
143+
struct large ret;
144+
ret.x = x.x;
145+
return ret;
146+
}
147+
104148
// A 64-bit struct fits in a register.
105149
struct reg {
106150
int a, b;
@@ -215,6 +259,18 @@ int f_variable(char *f, ...) {
215259
case 'm':
216260
s += *va_arg(ap, struct medium).a;
217261
break;
262+
263+
// CHECK: %[[CUR:[^ ]+]] = load ptr, ptr %ap
264+
// CHECK-DAG: %[[TMP:[^ ]+]] = getelementptr inbounds i8, ptr %[[CUR]], i32 15
265+
// CHECK-DAG: %[[ALIGNED:[^ ]+]] = call ptr @llvm.ptrmask.p0.i64(ptr %[[TMP]], i64 -16)
266+
// CHECK-DAG: %[[NXT:[^ ]+]] = getelementptr inbounds i8, ptr %[[ALIGNED]], i64 16
267+
// CHECK-DAG: store ptr %[[NXT]], ptr %ap
268+
// CHECK-DAG: call void @llvm.memcpy.p0.p0.i64(ptr align 16 {{.*}}, ptr align 16 %[[ALIGNED]], i64 16, i1 false)
269+
// CHECK: br
270+
case 'a':
271+
s += va_arg(ap, struct align16_int).x;
272+
break;
218273
}
274+
va_end(ap);
219275
return s;
220276
}

llvm/lib/Target/Sparc/SparcISelLowering.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,8 @@ static bool Analyze_CC_Sparc64_Full(bool IsReturn, unsigned &ValNo, MVT &ValVT,
115115

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

llvm/test/CodeGen/SPARC/64abi.ll

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -473,15 +473,28 @@ declare i64 @receive_fp128(i64 %a, ...)
473473
; HARD-DAG: ldx [%sp+[[Offset0]]], %o2
474474
; HARD-DAG: ldx [%sp+[[Offset1]]], %o3
475475
; SOFT-DAG: mov %i0, %o0
476-
; SOFT-DAG: mov %i1, %o1
477476
; SOFT-DAG: mov %i2, %o2
477+
; SOFT-DAG: mov %i3, %o3
478478
; CHECK: call receive_fp128
479479
define i64 @test_fp128_variable_args(i64 %a, fp128 %b) {
480480
entry:
481481
%0 = call i64 (i64, ...) @receive_fp128(i64 %a, fp128 %b)
482482
ret i64 %0
483483
}
484484

485+
declare i64 @receive_i128(i64 %a, i128 %b)
486+
487+
; CHECK-LABEL: test_i128_args:
488+
; CHECK: mov %i3, %o3
489+
; CHECK: mov %i2, %o2
490+
; CHECK: mov %i0, %o0
491+
; CHECK: call receive_i128
492+
define i64 @test_i128_args(i64 %a, i128 %b) {
493+
entry:
494+
%0 = call i64 @receive_i128(i64 %a, i128 %b)
495+
ret i64 %0
496+
}
497+
485498
; CHECK-LABEL: test_call_libfunc:
486499
; HARD: st %f1, [%fp+[[Offset0:[0-9]+]]]
487500
; HARD: fmovs %f3, %f1

0 commit comments

Comments
 (0)