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