[clang][SPARC] Pass 16-aligned structs with the correct alignment in … · llvm/llvm-project@9ee4ac8 (original) (raw)
`@@ -8,6 +8,7 @@
`
8
8
``
9
9
`#include "ABIInfoImpl.h"
`
10
10
`#include "TargetInfo.h"
`
``
11
`+
#include
`
11
12
``
12
13
`using namespace clang;
`
13
14
`using namespace clang::CodeGen;
`
`@@ -109,7 +110,8 @@ class SparcV9ABIInfo : public ABIInfo {
`
109
110
`SparcV9ABIInfo(CodeGenTypes &CGT) : ABIInfo(CGT) {}
`
110
111
``
111
112
`private:
`
112
``
`-
ABIArgInfo classifyType(QualType RetTy, unsigned SizeLimit) const;
`
``
113
`+
ABIArgInfo classifyType(QualType RetTy, unsigned SizeLimit,
`
``
114
`+
unsigned &RegOffset) const;
`
113
115
`void computeInfo(CGFunctionInfo &FI) const override;
`
114
116
` RValue EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty,
`
115
117
` AggValueSlot Slot) const override;
`
`@@ -222,127 +224,114 @@ class SparcV9ABIInfo : public ABIInfo {
`
222
224
`};
`
223
225
`} // end anonymous namespace
`
224
226
``
225
``
`-
ABIArgInfo
`
226
``
`-
SparcV9ABIInfo::classifyType(QualType Ty, unsigned SizeLimit) const {
`
``
227
`+
ABIArgInfo SparcV9ABIInfo::classifyType(QualType Ty, unsigned SizeLimit,
`
``
228
`+
unsigned &RegOffset) const {
`
227
229
`if (Ty->isVoidType())
`
228
230
`return ABIArgInfo::getIgnore();
`
229
231
``
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);
`
231
238
``
232
239
`// Anything too big to fit in registers is passed with an explicit indirect
`
233
240
`// pointer / sret pointer.
`
234
``
`-
if (Size > SizeLimit)
`
``
241
`+
if (Size > SizeLimit) {
`
``
242
`+
RegOffset += 1;
`
235
243
`return getNaturalAlignIndirect(
`
236
244
` Ty, /AddrSpace=/getDataLayout().getAllocaAddrSpace(),
`
237
245
`/ByVal=/false);
`
``
246
`+
}
`
238
247
``
239
248
`// Treat an enum type as its underlying type.
`
240
249
`if (const EnumType *EnumTy = Ty->getAs())
`
241
250
` Ty = EnumTy->getDecl()->getIntegerType();
`
242
251
``
243
252
`// Integer types smaller than a register are extended.
`
244
``
`-
if (Size < 64 && Ty->isIntegerType())
`
``
253
`+
if (Size < 64 && Ty->isIntegerType()) {
`
``
254
`+
RegOffset += 1;
`
245
255
`return ABIArgInfo::getExtend(Ty);
`
``
256
`+
}
`
246
257
``
247
258
`if (const auto *EIT = Ty->getAs())
`
248
``
`-
if (EIT->getNumBits() < 64)
`
``
259
`+
if (EIT->getNumBits() < 64) {
`
``
260
`+
RegOffset += 1;
`
249
261
`return ABIArgInfo::getExtend(Ty);
`
``
262
`+
}
`
250
263
``
251
264
`// Other non-aggregates go in registers.
`
252
``
`-
if (!isAggregateTypeForABI(Ty))
`
``
265
`+
if (!isAggregateTypeForABI(Ty)) {
`
``
266
`+
RegOffset += Size / 64;
`
253
267
`return ABIArgInfo::getDirect();
`
``
268
`+
}
`
254
269
``
255
270
`// If a C++ object has either a non-trivial copy constructor or a non-trivial
`
256
271
`// 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;
`
258
274
`return getNaturalAlignIndirect(Ty, getDataLayout().getAllocaAddrSpace(),
`
259
275
` RAA == CGCXXABI::RAA_DirectInMemory);
`
``
276
`+
}
`
260
277
``
261
278
`// This is a small aggregate type that should be passed in registers.
`
262
279
`// Build a coercion type from the LLVM struct type.
`
263
280
` llvm::StructType *StrTy = dyn_castllvm::StructType(CGT.ConvertType(Ty));
`
264
``
`-
if (!StrTy)
`
``
281
`+
if (!StrTy) {
`
``
282
`+
RegOffset += Size / 64;
`
265
283
`return ABIArgInfo::getDirect();
`
``
284
`+
}
`
266
285
``
267
``
`-
CoerceBuilder CB(getVMContext(), getDataLayout());
`
``
286
`+
CoerceBuilder CB(VMContext, getDataLayout());
`
268
287
` CB.addStruct(0, StrTy);
`
269
288
`// All structs, even empty ones, should take up a register argument slot,
`
270
289
`// so pin the minimum struct size to one bit.
`
271
290
` CB.pad(llvm::alignTo(
`
272
291
`std::max(CB.DL.getTypeSizeInBits(StrTy).getKnownMinValue(), uint64_t(1)),
`
273
292
`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;
`
274
302
``
275
303
`// Try to use the original type for coercion.
`
276
304
` llvm::Type *CoerceTy = CB.isUsableType(StrTy) ? StrTy : CB.getType();
`
277
305
``
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;
`
282
309
`}
`
283
310
``
284
311
`RValue SparcV9ABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
`
285
312
` 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
``
-
291
313
` CharUnits SlotSize = CharUnits::fromQuantity(8);
`
``
314
`+
auto TInfo = getContext().getTypeInfoInChars(Ty);
`
292
315
``
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));
`
329
318
``
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);
`
340
324
`}
`
341
325
``
342
326
`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;
`
344
333
`for (auto &I : FI.arguments())
`
345
``
`-
I.info = classifyType(I.type, 16 * 8);
`
``
334
`+
I.info = classifyType(I.type, 16 * 8, ArgOffset);
`
346
335
`}
`
347
336
``
348
337
`namespace {
`