|
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