1 | //===- SystemZ.cpp --------------------------------------------------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #include "ABIInfoImpl.h" |
10 | #include "TargetInfo.h" |
11 | #include "clang/Basic/Builtins.h" |
12 | #include "llvm/IR/IntrinsicsS390.h" |
13 | |
14 | using namespace clang; |
15 | using namespace clang::CodeGen; |
16 | |
17 | //===----------------------------------------------------------------------===// |
18 | // SystemZ ABI Implementation |
19 | //===----------------------------------------------------------------------===// |
20 | |
21 | namespace { |
22 | |
23 | class SystemZABIInfo : public ABIInfo { |
24 | bool HasVector; |
25 | bool IsSoftFloatABI; |
26 | |
27 | public: |
28 | SystemZABIInfo(CodeGenTypes &CGT, bool HV, bool SF) |
29 | : ABIInfo(CGT), HasVector(HV), IsSoftFloatABI(SF) {} |
30 | |
31 | bool isPromotableIntegerTypeForABI(QualType Ty) const; |
32 | bool isCompoundType(QualType Ty) const; |
33 | bool isVectorArgumentType(QualType Ty) const; |
34 | llvm::Type *getFPArgumentType(QualType Ty, uint64_t Size) const; |
35 | QualType GetSingleElementType(QualType Ty) const; |
36 | |
37 | ABIArgInfo classifyReturnType(QualType RetTy) const; |
38 | ABIArgInfo classifyArgumentType(QualType ArgTy) const; |
39 | |
40 | void computeInfo(CGFunctionInfo &FI) const override; |
41 | RValue EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty, |
42 | AggValueSlot Slot) const override; |
43 | }; |
44 | |
45 | class SystemZTargetCodeGenInfo : public TargetCodeGenInfo { |
46 | ASTContext &Ctx; |
47 | |
48 | // These are used for speeding up the search for a visible vector ABI. |
49 | mutable bool HasVisibleVecABIFlag = false; |
50 | mutable std::set<const Type *> SeenTypes; |
51 | |
52 | // Returns true (the first time) if Ty is, or is found to include, a vector |
53 | // type that exposes the vector ABI. This is any vector >=16 bytes which |
54 | // with vector support are aligned to only 8 bytes. When IsParam is true, |
55 | // the type belongs to a value as passed between functions. If it is a |
56 | // vector <=16 bytes it will be passed in a vector register (if supported). |
57 | bool isVectorTypeBased(const Type *Ty, bool IsParam) const; |
58 | |
59 | public: |
60 | SystemZTargetCodeGenInfo(CodeGenTypes &CGT, bool HasVector, bool SoftFloatABI) |
61 | : TargetCodeGenInfo( |
62 | std::make_unique<SystemZABIInfo>(args&: CGT, args&: HasVector, args&: SoftFloatABI)), |
63 | Ctx(CGT.getContext()) { |
64 | SwiftInfo = |
65 | std::make_unique<SwiftABIInfo>(args&: CGT, /*SwiftErrorInRegister=*/args: false); |
66 | } |
67 | |
68 | // The vector ABI is different when the vector facility is present and when |
69 | // a module e.g. defines an externally visible vector variable, a flag |
70 | // indicating a visible vector ABI is added. Eventually this will result in |
71 | // a GNU attribute indicating the vector ABI of the module. Ty is the type |
72 | // of a variable or function parameter that is globally visible. |
73 | void handleExternallyVisibleObjABI(const Type *Ty, CodeGen::CodeGenModule &M, |
74 | bool IsParam) const { |
75 | if (!HasVisibleVecABIFlag && isVectorTypeBased(Ty, IsParam)) { |
76 | M.getModule().addModuleFlag(Behavior: llvm::Module::Warning, |
77 | Key: "s390x-visible-vector-ABI" , Val: 1); |
78 | HasVisibleVecABIFlag = true; |
79 | } |
80 | } |
81 | |
82 | void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV, |
83 | CodeGen::CodeGenModule &M) const override { |
84 | if (!D) |
85 | return; |
86 | |
87 | // Check if the vector ABI becomes visible by an externally visible |
88 | // variable or function. |
89 | if (const auto *VD = dyn_cast<VarDecl>(Val: D)) { |
90 | if (VD->isExternallyVisible()) |
91 | handleExternallyVisibleObjABI(Ty: VD->getType().getTypePtr(), M, |
92 | /*IsParam*/false); |
93 | } |
94 | else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(Val: D)) { |
95 | if (FD->isExternallyVisible()) |
96 | handleExternallyVisibleObjABI(Ty: FD->getType().getTypePtr(), M, |
97 | /*IsParam*/false); |
98 | } |
99 | } |
100 | |
101 | llvm::Value *testFPKind(llvm::Value *V, unsigned BuiltinID, |
102 | CGBuilderTy &Builder, |
103 | CodeGenModule &CGM) const override { |
104 | assert(V->getType()->isFloatingPointTy() && "V should have an FP type." ); |
105 | // Only use TDC in constrained FP mode. |
106 | if (!Builder.getIsFPConstrained()) |
107 | return nullptr; |
108 | |
109 | llvm::Type *Ty = V->getType(); |
110 | if (Ty->isHalfTy() || Ty->isFloatTy() || Ty->isDoubleTy() || |
111 | Ty->isFP128Ty()) { |
112 | llvm::Module &M = CGM.getModule(); |
113 | auto &Ctx = M.getContext(); |
114 | llvm::Function *TDCFunc = llvm::Intrinsic::getOrInsertDeclaration( |
115 | M: &M, id: llvm::Intrinsic::s390_tdc, Tys: Ty); |
116 | unsigned TDCBits = 0; |
117 | switch (BuiltinID) { |
118 | case Builtin::BI__builtin_isnan: |
119 | TDCBits = 0xf; |
120 | break; |
121 | case Builtin::BIfinite: |
122 | case Builtin::BI__finite: |
123 | case Builtin::BIfinitef: |
124 | case Builtin::BI__finitef: |
125 | case Builtin::BIfinitel: |
126 | case Builtin::BI__finitel: |
127 | case Builtin::BI__builtin_isfinite: |
128 | TDCBits = 0xfc0; |
129 | break; |
130 | case Builtin::BI__builtin_isinf: |
131 | TDCBits = 0x30; |
132 | break; |
133 | default: |
134 | break; |
135 | } |
136 | if (TDCBits) |
137 | return Builder.CreateCall( |
138 | Callee: TDCFunc, |
139 | Args: {V, llvm::ConstantInt::get(Ty: llvm::Type::getInt64Ty(C&: Ctx), V: TDCBits)}); |
140 | } |
141 | return nullptr; |
142 | } |
143 | }; |
144 | } |
145 | |
146 | bool SystemZABIInfo::isPromotableIntegerTypeForABI(QualType Ty) const { |
147 | // Treat an enum type as its underlying type. |
148 | if (const EnumType *EnumTy = Ty->getAs<EnumType>()) |
149 | Ty = EnumTy->getDecl()->getIntegerType(); |
150 | |
151 | // Promotable integer types are required to be promoted by the ABI. |
152 | if (ABIInfo::isPromotableIntegerTypeForABI(Ty)) |
153 | return true; |
154 | |
155 | if (const auto *EIT = Ty->getAs<BitIntType>()) |
156 | if (EIT->getNumBits() < 64) |
157 | return true; |
158 | |
159 | // 32-bit values must also be promoted. |
160 | if (const BuiltinType *BT = Ty->getAs<BuiltinType>()) |
161 | switch (BT->getKind()) { |
162 | case BuiltinType::Int: |
163 | case BuiltinType::UInt: |
164 | return true; |
165 | default: |
166 | return false; |
167 | } |
168 | return false; |
169 | } |
170 | |
171 | bool SystemZABIInfo::isCompoundType(QualType Ty) const { |
172 | return (Ty->isAnyComplexType() || |
173 | Ty->isVectorType() || |
174 | isAggregateTypeForABI(T: Ty)); |
175 | } |
176 | |
177 | bool SystemZABIInfo::isVectorArgumentType(QualType Ty) const { |
178 | return (HasVector && |
179 | Ty->isVectorType() && |
180 | getContext().getTypeSize(T: Ty) <= 128); |
181 | } |
182 | |
183 | // The Size argument will in case of af an overaligned single element struct |
184 | // reflect the overalignment value. In such a case the argument will be |
185 | // passed using the type matching Size. |
186 | llvm::Type *SystemZABIInfo::getFPArgumentType(QualType Ty, |
187 | uint64_t Size) const { |
188 | if (IsSoftFloatABI) |
189 | return nullptr; |
190 | |
191 | if (const BuiltinType *BT = Ty->getAs<BuiltinType>()) |
192 | switch (BT->getKind()) { |
193 | case BuiltinType::Float16: |
194 | if (Size == 16) |
195 | return llvm::Type::getHalfTy(C&: getVMContext()); |
196 | LLVM_FALLTHROUGH; |
197 | case BuiltinType::Float: |
198 | if (Size == 32) |
199 | return llvm::Type::getFloatTy(C&: getVMContext()); |
200 | LLVM_FALLTHROUGH; |
201 | case BuiltinType::Double: |
202 | return llvm::Type::getDoubleTy(C&: getVMContext()); |
203 | default: |
204 | return nullptr; |
205 | } |
206 | |
207 | return nullptr; |
208 | } |
209 | |
210 | QualType SystemZABIInfo::GetSingleElementType(QualType Ty) const { |
211 | const RecordType *RT = Ty->getAs<RecordType>(); |
212 | |
213 | if (RT && RT->isStructureOrClassType()) { |
214 | const RecordDecl *RD = RT->getDecl(); |
215 | QualType Found; |
216 | |
217 | // If this is a C++ record, check the bases first. |
218 | if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(Val: RD)) |
219 | if (CXXRD->hasDefinition()) |
220 | for (const auto &I : CXXRD->bases()) { |
221 | QualType Base = I.getType(); |
222 | |
223 | // Empty bases don't affect things either way. |
224 | if (isEmptyRecord(Context&: getContext(), T: Base, AllowArrays: true)) |
225 | continue; |
226 | |
227 | if (!Found.isNull()) |
228 | return Ty; |
229 | Found = GetSingleElementType(Ty: Base); |
230 | } |
231 | |
232 | // Check the fields. |
233 | for (const auto *FD : RD->fields()) { |
234 | // Unlike isSingleElementStruct(), empty structure and array fields |
235 | // do count. So do anonymous bitfields that aren't zero-sized. |
236 | |
237 | // Like isSingleElementStruct(), ignore C++20 empty data members. |
238 | if (FD->hasAttr<NoUniqueAddressAttr>() && |
239 | isEmptyRecord(Context&: getContext(), T: FD->getType(), AllowArrays: true)) |
240 | continue; |
241 | |
242 | // Unlike isSingleElementStruct(), arrays do not count. |
243 | // Nested structures still do though. |
244 | if (!Found.isNull()) |
245 | return Ty; |
246 | Found = GetSingleElementType(Ty: FD->getType()); |
247 | } |
248 | |
249 | // Unlike isSingleElementStruct(), trailing padding is allowed. |
250 | // An 8-byte aligned struct s { float f; } is passed as a double. |
251 | if (!Found.isNull()) |
252 | return Found; |
253 | } |
254 | |
255 | return Ty; |
256 | } |
257 | |
258 | RValue SystemZABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, |
259 | QualType Ty, AggValueSlot Slot) const { |
260 | // Assume that va_list type is correct; should be pointer to LLVM type: |
261 | // struct { |
262 | // i64 __gpr; |
263 | // i64 __fpr; |
264 | // i8 *__overflow_arg_area; |
265 | // i8 *__reg_save_area; |
266 | // }; |
267 | |
268 | // Every non-vector argument occupies 8 bytes and is passed by preference |
269 | // in either GPRs or FPRs. Vector arguments occupy 8 or 16 bytes and are |
270 | // always passed on the stack. |
271 | const SystemZTargetCodeGenInfo &SZCGI = |
272 | static_cast<const SystemZTargetCodeGenInfo &>( |
273 | CGT.getCGM().getTargetCodeGenInfo()); |
274 | Ty = getContext().getCanonicalType(T: Ty); |
275 | auto TyInfo = getContext().getTypeInfoInChars(T: Ty); |
276 | llvm::Type *ArgTy = CGF.ConvertTypeForMem(T: Ty); |
277 | llvm::Type *DirectTy = ArgTy; |
278 | ABIArgInfo AI = classifyArgumentType(ArgTy: Ty); |
279 | bool IsIndirect = AI.isIndirect(); |
280 | bool InFPRs = false; |
281 | bool IsVector = false; |
282 | CharUnits UnpaddedSize; |
283 | CharUnits DirectAlign; |
284 | SZCGI.handleExternallyVisibleObjABI(Ty: Ty.getTypePtr(), M&: CGT.getCGM(), |
285 | /*IsParam*/true); |
286 | if (IsIndirect) { |
287 | DirectTy = llvm::PointerType::getUnqual(C&: DirectTy->getContext()); |
288 | UnpaddedSize = DirectAlign = CharUnits::fromQuantity(Quantity: 8); |
289 | } else { |
290 | if (AI.getCoerceToType()) |
291 | ArgTy = AI.getCoerceToType(); |
292 | InFPRs = (!IsSoftFloatABI && |
293 | (ArgTy->isHalfTy() || ArgTy->isFloatTy() || ArgTy->isDoubleTy())); |
294 | IsVector = ArgTy->isVectorTy(); |
295 | UnpaddedSize = TyInfo.Width; |
296 | DirectAlign = TyInfo.Align; |
297 | } |
298 | CharUnits PaddedSize = CharUnits::fromQuantity(Quantity: 8); |
299 | if (IsVector && UnpaddedSize > PaddedSize) |
300 | PaddedSize = CharUnits::fromQuantity(Quantity: 16); |
301 | assert((UnpaddedSize <= PaddedSize) && "Invalid argument size." ); |
302 | |
303 | CharUnits Padding = (PaddedSize - UnpaddedSize); |
304 | |
305 | llvm::Type *IndexTy = CGF.Int64Ty; |
306 | llvm::Value *PaddedSizeV = |
307 | llvm::ConstantInt::get(Ty: IndexTy, V: PaddedSize.getQuantity()); |
308 | |
309 | if (IsVector) { |
310 | // Work out the address of a vector argument on the stack. |
311 | // Vector arguments are always passed in the high bits of a |
312 | // single (8 byte) or double (16 byte) stack slot. |
313 | Address OverflowArgAreaPtr = |
314 | CGF.Builder.CreateStructGEP(Addr: VAListAddr, Index: 2, Name: "overflow_arg_area_ptr" ); |
315 | Address OverflowArgArea = |
316 | Address(CGF.Builder.CreateLoad(Addr: OverflowArgAreaPtr, Name: "overflow_arg_area" ), |
317 | CGF.Int8Ty, TyInfo.Align); |
318 | Address MemAddr = OverflowArgArea.withElementType(ElemTy: DirectTy); |
319 | |
320 | // Update overflow_arg_area_ptr pointer |
321 | llvm::Value *NewOverflowArgArea = CGF.Builder.CreateGEP( |
322 | Ty: OverflowArgArea.getElementType(), Ptr: OverflowArgArea.emitRawPointer(CGF), |
323 | IdxList: PaddedSizeV, Name: "overflow_arg_area" ); |
324 | CGF.Builder.CreateStore(Val: NewOverflowArgArea, Addr: OverflowArgAreaPtr); |
325 | |
326 | return CGF.EmitLoadOfAnyValue(V: CGF.MakeAddrLValue(Addr: MemAddr, T: Ty), Slot); |
327 | } |
328 | |
329 | assert(PaddedSize.getQuantity() == 8); |
330 | |
331 | unsigned MaxRegs, RegCountField, RegSaveIndex; |
332 | CharUnits RegPadding; |
333 | if (InFPRs) { |
334 | MaxRegs = 4; // Maximum of 4 FPR arguments |
335 | RegCountField = 1; // __fpr |
336 | RegSaveIndex = 16; // save offset for f0 |
337 | RegPadding = CharUnits(); // floats are passed in the high bits of an FPR |
338 | } else { |
339 | MaxRegs = 5; // Maximum of 5 GPR arguments |
340 | RegCountField = 0; // __gpr |
341 | RegSaveIndex = 2; // save offset for r2 |
342 | RegPadding = Padding; // values are passed in the low bits of a GPR |
343 | } |
344 | |
345 | Address RegCountPtr = |
346 | CGF.Builder.CreateStructGEP(Addr: VAListAddr, Index: RegCountField, Name: "reg_count_ptr" ); |
347 | llvm::Value *RegCount = CGF.Builder.CreateLoad(Addr: RegCountPtr, Name: "reg_count" ); |
348 | llvm::Value *MaxRegsV = llvm::ConstantInt::get(Ty: IndexTy, V: MaxRegs); |
349 | llvm::Value *InRegs = CGF.Builder.CreateICmpULT(LHS: RegCount, RHS: MaxRegsV, |
350 | Name: "fits_in_regs" ); |
351 | |
352 | llvm::BasicBlock *InRegBlock = CGF.createBasicBlock(name: "vaarg.in_reg" ); |
353 | llvm::BasicBlock *InMemBlock = CGF.createBasicBlock(name: "vaarg.in_mem" ); |
354 | llvm::BasicBlock *ContBlock = CGF.createBasicBlock(name: "vaarg.end" ); |
355 | CGF.Builder.CreateCondBr(Cond: InRegs, True: InRegBlock, False: InMemBlock); |
356 | |
357 | // Emit code to load the value if it was passed in registers. |
358 | CGF.EmitBlock(BB: InRegBlock); |
359 | |
360 | // Work out the address of an argument register. |
361 | llvm::Value *ScaledRegCount = |
362 | CGF.Builder.CreateMul(LHS: RegCount, RHS: PaddedSizeV, Name: "scaled_reg_count" ); |
363 | llvm::Value *RegBase = |
364 | llvm::ConstantInt::get(Ty: IndexTy, V: RegSaveIndex * PaddedSize.getQuantity() |
365 | + RegPadding.getQuantity()); |
366 | llvm::Value *RegOffset = |
367 | CGF.Builder.CreateAdd(LHS: ScaledRegCount, RHS: RegBase, Name: "reg_offset" ); |
368 | Address RegSaveAreaPtr = |
369 | CGF.Builder.CreateStructGEP(Addr: VAListAddr, Index: 3, Name: "reg_save_area_ptr" ); |
370 | llvm::Value *RegSaveArea = |
371 | CGF.Builder.CreateLoad(Addr: RegSaveAreaPtr, Name: "reg_save_area" ); |
372 | Address RawRegAddr( |
373 | CGF.Builder.CreateGEP(Ty: CGF.Int8Ty, Ptr: RegSaveArea, IdxList: RegOffset, Name: "raw_reg_addr" ), |
374 | CGF.Int8Ty, PaddedSize); |
375 | Address RegAddr = RawRegAddr.withElementType(ElemTy: DirectTy); |
376 | |
377 | // Update the register count |
378 | llvm::Value *One = llvm::ConstantInt::get(Ty: IndexTy, V: 1); |
379 | llvm::Value *NewRegCount = |
380 | CGF.Builder.CreateAdd(LHS: RegCount, RHS: One, Name: "reg_count" ); |
381 | CGF.Builder.CreateStore(Val: NewRegCount, Addr: RegCountPtr); |
382 | CGF.EmitBranch(Block: ContBlock); |
383 | |
384 | // Emit code to load the value if it was passed in memory. |
385 | CGF.EmitBlock(BB: InMemBlock); |
386 | |
387 | // Work out the address of a stack argument. |
388 | Address OverflowArgAreaPtr = |
389 | CGF.Builder.CreateStructGEP(Addr: VAListAddr, Index: 2, Name: "overflow_arg_area_ptr" ); |
390 | Address OverflowArgArea = |
391 | Address(CGF.Builder.CreateLoad(Addr: OverflowArgAreaPtr, Name: "overflow_arg_area" ), |
392 | CGF.Int8Ty, PaddedSize); |
393 | Address RawMemAddr = |
394 | CGF.Builder.CreateConstByteGEP(Addr: OverflowArgArea, Offset: Padding, Name: "raw_mem_addr" ); |
395 | Address MemAddr = RawMemAddr.withElementType(ElemTy: DirectTy); |
396 | |
397 | // Update overflow_arg_area_ptr pointer |
398 | llvm::Value *NewOverflowArgArea = CGF.Builder.CreateGEP( |
399 | Ty: OverflowArgArea.getElementType(), Ptr: OverflowArgArea.emitRawPointer(CGF), |
400 | IdxList: PaddedSizeV, Name: "overflow_arg_area" ); |
401 | CGF.Builder.CreateStore(Val: NewOverflowArgArea, Addr: OverflowArgAreaPtr); |
402 | CGF.EmitBranch(Block: ContBlock); |
403 | |
404 | // Return the appropriate result. |
405 | CGF.EmitBlock(BB: ContBlock); |
406 | Address ResAddr = emitMergePHI(CGF, Addr1: RegAddr, Block1: InRegBlock, Addr2: MemAddr, Block2: InMemBlock, |
407 | Name: "va_arg.addr" ); |
408 | |
409 | if (IsIndirect) |
410 | ResAddr = Address(CGF.Builder.CreateLoad(Addr: ResAddr, Name: "indirect_arg" ), ArgTy, |
411 | TyInfo.Align); |
412 | |
413 | return CGF.EmitLoadOfAnyValue(V: CGF.MakeAddrLValue(Addr: ResAddr, T: Ty), Slot); |
414 | } |
415 | |
416 | ABIArgInfo SystemZABIInfo::classifyReturnType(QualType RetTy) const { |
417 | if (RetTy->isVoidType()) |
418 | return ABIArgInfo::getIgnore(); |
419 | if (isVectorArgumentType(Ty: RetTy)) |
420 | return ABIArgInfo::getDirect(); |
421 | if (isCompoundType(Ty: RetTy) || getContext().getTypeSize(T: RetTy) > 64) |
422 | return getNaturalAlignIndirect(Ty: RetTy, AddrSpace: getDataLayout().getAllocaAddrSpace()); |
423 | return (isPromotableIntegerTypeForABI(Ty: RetTy) ? ABIArgInfo::getExtend(Ty: RetTy) |
424 | : ABIArgInfo::getDirect()); |
425 | } |
426 | |
427 | ABIArgInfo SystemZABIInfo::classifyArgumentType(QualType Ty) const { |
428 | // Handle transparent union types. |
429 | Ty = useFirstFieldIfTransparentUnion(Ty); |
430 | |
431 | // Handle the generic C++ ABI. |
432 | if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(T: Ty, CXXABI&: getCXXABI())) |
433 | return getNaturalAlignIndirect(Ty, AddrSpace: getDataLayout().getAllocaAddrSpace(), |
434 | ByVal: RAA == CGCXXABI::RAA_DirectInMemory); |
435 | |
436 | // Integers and enums are extended to full register width. |
437 | if (isPromotableIntegerTypeForABI(Ty)) |
438 | return ABIArgInfo::getExtend(Ty, T: CGT.ConvertType(T: Ty)); |
439 | |
440 | // Handle vector types and vector-like structure types. Note that |
441 | // as opposed to float-like structure types, we do not allow any |
442 | // padding for vector-like structures, so verify the sizes match. |
443 | uint64_t Size = getContext().getTypeSize(T: Ty); |
444 | QualType SingleElementTy = GetSingleElementType(Ty); |
445 | if (isVectorArgumentType(Ty: SingleElementTy) && |
446 | getContext().getTypeSize(T: SingleElementTy) == Size) |
447 | return ABIArgInfo::getDirect(T: CGT.ConvertType(T: SingleElementTy)); |
448 | |
449 | // Values that are not 1, 2, 4 or 8 bytes in size are passed indirectly. |
450 | if (Size != 8 && Size != 16 && Size != 32 && Size != 64) |
451 | return getNaturalAlignIndirect(Ty, AddrSpace: getDataLayout().getAllocaAddrSpace(), |
452 | /*ByVal=*/false); |
453 | |
454 | // Handle small structures. |
455 | if (const RecordType *RT = Ty->getAs<RecordType>()) { |
456 | // Structures with flexible arrays have variable length, so really |
457 | // fail the size test above. |
458 | const RecordDecl *RD = RT->getDecl(); |
459 | if (RD->hasFlexibleArrayMember()) |
460 | return getNaturalAlignIndirect(Ty, AddrSpace: getDataLayout().getAllocaAddrSpace(), |
461 | /*ByVal=*/false); |
462 | |
463 | // The structure is passed as an unextended integer, a half, a float, |
464 | // or a double. |
465 | if (llvm::Type *FPArgTy = getFPArgumentType(Ty: SingleElementTy, Size)) { |
466 | assert(Size == 16 || Size == 32 || Size == 64); |
467 | return ABIArgInfo::getDirect(T: FPArgTy); |
468 | } else { |
469 | llvm::IntegerType *PassTy = llvm::IntegerType::get(C&: getVMContext(), NumBits: Size); |
470 | return Size <= 32 ? ABIArgInfo::getNoExtend(T: PassTy) |
471 | : ABIArgInfo::getDirect(T: PassTy); |
472 | } |
473 | } |
474 | |
475 | // Non-structure compounds are passed indirectly. |
476 | if (isCompoundType(Ty)) |
477 | return getNaturalAlignIndirect(Ty, AddrSpace: getDataLayout().getAllocaAddrSpace(), |
478 | /*ByVal=*/false); |
479 | |
480 | return ABIArgInfo::getDirect(T: nullptr); |
481 | } |
482 | |
483 | void SystemZABIInfo::computeInfo(CGFunctionInfo &FI) const { |
484 | const SystemZTargetCodeGenInfo &SZCGI = |
485 | static_cast<const SystemZTargetCodeGenInfo &>( |
486 | CGT.getCGM().getTargetCodeGenInfo()); |
487 | if (!getCXXABI().classifyReturnType(FI)) |
488 | FI.getReturnInfo() = classifyReturnType(RetTy: FI.getReturnType()); |
489 | unsigned Idx = 0; |
490 | for (auto &I : FI.arguments()) { |
491 | I.info = classifyArgumentType(Ty: I.type); |
492 | if (FI.isVariadic() && Idx++ >= FI.getNumRequiredArgs()) |
493 | // Check if a vararg vector argument is passed, in which case the |
494 | // vector ABI becomes visible as the va_list could be passed on to |
495 | // other functions. |
496 | SZCGI.handleExternallyVisibleObjABI(Ty: I.type.getTypePtr(), M&: CGT.getCGM(), |
497 | /*IsParam*/true); |
498 | } |
499 | } |
500 | |
501 | bool SystemZTargetCodeGenInfo::isVectorTypeBased(const Type *Ty, |
502 | bool IsParam) const { |
503 | if (!SeenTypes.insert(x: Ty).second) |
504 | return false; |
505 | |
506 | if (IsParam) { |
507 | // A narrow (<16 bytes) vector will as a parameter also expose the ABI as |
508 | // it will be passed in a vector register. A wide (>16 bytes) vector will |
509 | // be passed via "hidden" pointer where any extra alignment is not |
510 | // required (per GCC). |
511 | const Type *SingleEltTy = getABIInfo<SystemZABIInfo>() |
512 | .GetSingleElementType(Ty: QualType(Ty, 0)) |
513 | .getTypePtr(); |
514 | bool SingleVecEltStruct = SingleEltTy != Ty && SingleEltTy->isVectorType() && |
515 | Ctx.getTypeSize(T: SingleEltTy) == Ctx.getTypeSize(T: Ty); |
516 | if (Ty->isVectorType() || SingleVecEltStruct) |
517 | return Ctx.getTypeSize(T: Ty) / 8 <= 16; |
518 | } |
519 | |
520 | // Assume pointers are dereferenced. |
521 | while (Ty->isPointerType() || Ty->isArrayType()) |
522 | Ty = Ty->getPointeeOrArrayElementType(); |
523 | |
524 | // Vectors >= 16 bytes expose the ABI through alignment requirements. |
525 | if (Ty->isVectorType() && Ctx.getTypeSize(T: Ty) / 8 >= 16) |
526 | return true; |
527 | |
528 | if (const auto *RecordTy = Ty->getAs<RecordType>()) { |
529 | const RecordDecl *RD = RecordTy->getDecl(); |
530 | if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(Val: RD)) |
531 | if (CXXRD->hasDefinition()) |
532 | for (const auto &I : CXXRD->bases()) |
533 | if (isVectorTypeBased(Ty: I.getType().getTypePtr(), /*IsParam*/false)) |
534 | return true; |
535 | for (const auto *FD : RD->fields()) |
536 | if (isVectorTypeBased(Ty: FD->getType().getTypePtr(), /*IsParam*/false)) |
537 | return true; |
538 | } |
539 | |
540 | if (const auto *FT = Ty->getAs<FunctionType>()) |
541 | if (isVectorTypeBased(Ty: FT->getReturnType().getTypePtr(), /*IsParam*/true)) |
542 | return true; |
543 | if (const FunctionProtoType *Proto = Ty->getAs<FunctionProtoType>()) |
544 | for (const auto &ParamType : Proto->getParamTypes()) |
545 | if (isVectorTypeBased(Ty: ParamType.getTypePtr(), /*IsParam*/true)) |
546 | return true; |
547 | |
548 | return false; |
549 | } |
550 | |
551 | std::unique_ptr<TargetCodeGenInfo> |
552 | CodeGen::createSystemZTargetCodeGenInfo(CodeGenModule &CGM, bool HasVector, |
553 | bool SoftFloatABI) { |
554 | return std::make_unique<SystemZTargetCodeGenInfo>(args&: CGM.getTypes(), args&: HasVector, |
555 | args&: SoftFloatABI); |
556 | } |
557 | |