|
8 | 8 |
|
9 | 9 | #include "ABIInfoImpl.h"
|
10 | 10 | #include "TargetInfo.h"
|
| 11 | +#include <algorithm> |
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<EnumType>())
|
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<BitIntType>())
|
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_cast<llvm::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 {
|
|
0 commit comments