1 | //===- ABIInfoImpl.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 | |
11 | using namespace clang; |
12 | using namespace clang::CodeGen; |
13 | |
14 | // Pin the vtable to this file. |
15 | DefaultABIInfo::~DefaultABIInfo() = default; |
16 | |
17 | ABIArgInfo DefaultABIInfo::classifyArgumentType(QualType Ty) const { |
18 | Ty = useFirstFieldIfTransparentUnion(Ty); |
19 | |
20 | if (isAggregateTypeForABI(T: Ty)) { |
21 | // Records with non-trivial destructors/copy-constructors should not be |
22 | // passed by value. |
23 | if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(T: Ty, CXXABI&: getCXXABI())) |
24 | return getNaturalAlignIndirect(Ty, ByVal: RAA == CGCXXABI::RAA_DirectInMemory); |
25 | |
26 | return getNaturalAlignIndirect(Ty); |
27 | } |
28 | |
29 | // Treat an enum type as its underlying type. |
30 | if (const EnumType *EnumTy = Ty->getAs<EnumType>()) |
31 | Ty = EnumTy->getDecl()->getIntegerType(); |
32 | |
33 | ASTContext &Context = getContext(); |
34 | if (const auto *EIT = Ty->getAs<BitIntType>()) |
35 | if (EIT->getNumBits() > |
36 | Context.getTypeSize(Context.getTargetInfo().hasInt128Type() |
37 | ? Context.Int128Ty |
38 | : Context.LongLongTy)) |
39 | return getNaturalAlignIndirect(Ty); |
40 | |
41 | return (isPromotableIntegerTypeForABI(Ty) ? ABIArgInfo::getExtend(Ty) |
42 | : ABIArgInfo::getDirect()); |
43 | } |
44 | |
45 | ABIArgInfo DefaultABIInfo::classifyReturnType(QualType RetTy) const { |
46 | if (RetTy->isVoidType()) |
47 | return ABIArgInfo::getIgnore(); |
48 | |
49 | if (isAggregateTypeForABI(T: RetTy)) |
50 | return getNaturalAlignIndirect(Ty: RetTy); |
51 | |
52 | // Treat an enum type as its underlying type. |
53 | if (const EnumType *EnumTy = RetTy->getAs<EnumType>()) |
54 | RetTy = EnumTy->getDecl()->getIntegerType(); |
55 | |
56 | if (const auto *EIT = RetTy->getAs<BitIntType>()) |
57 | if (EIT->getNumBits() > |
58 | getContext().getTypeSize(getContext().getTargetInfo().hasInt128Type() |
59 | ? getContext().Int128Ty |
60 | : getContext().LongLongTy)) |
61 | return getNaturalAlignIndirect(Ty: RetTy); |
62 | |
63 | return (isPromotableIntegerTypeForABI(Ty: RetTy) ? ABIArgInfo::getExtend(Ty: RetTy) |
64 | : ABIArgInfo::getDirect()); |
65 | } |
66 | |
67 | void DefaultABIInfo::computeInfo(CGFunctionInfo &FI) const { |
68 | if (!getCXXABI().classifyReturnType(FI)) |
69 | FI.getReturnInfo() = classifyReturnType(RetTy: FI.getReturnType()); |
70 | for (auto &I : FI.arguments()) |
71 | I.info = classifyArgumentType(Ty: I.type); |
72 | } |
73 | |
74 | Address DefaultABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, |
75 | QualType Ty) const { |
76 | return EmitVAArgInstr(CGF, VAListAddr, Ty, AI: classifyArgumentType(Ty)); |
77 | } |
78 | |
79 | ABIArgInfo CodeGen::coerceToIntArray(QualType Ty, ASTContext &Context, |
80 | llvm::LLVMContext &LLVMContext) { |
81 | // Alignment and Size are measured in bits. |
82 | const uint64_t Size = Context.getTypeSize(T: Ty); |
83 | const uint64_t Alignment = Context.getTypeAlign(T: Ty); |
84 | llvm::Type *IntType = llvm::Type::getIntNTy(C&: LLVMContext, N: Alignment); |
85 | const uint64_t NumElements = (Size + Alignment - 1) / Alignment; |
86 | return ABIArgInfo::getDirect(T: llvm::ArrayType::get(ElementType: IntType, NumElements)); |
87 | } |
88 | |
89 | void CodeGen::AssignToArrayRange(CodeGen::CGBuilderTy &Builder, |
90 | llvm::Value *Array, llvm::Value *Value, |
91 | unsigned FirstIndex, unsigned LastIndex) { |
92 | // Alternatively, we could emit this as a loop in the source. |
93 | for (unsigned I = FirstIndex; I <= LastIndex; ++I) { |
94 | llvm::Value *Cell = |
95 | Builder.CreateConstInBoundsGEP1_32(Ty: Builder.getInt8Ty(), Ptr: Array, Idx0: I); |
96 | Builder.CreateAlignedStore(Val: Value, Addr: Cell, Align: CharUnits::One()); |
97 | } |
98 | } |
99 | |
100 | bool CodeGen::isAggregateTypeForABI(QualType T) { |
101 | return !CodeGenFunction::hasScalarEvaluationKind(T) || |
102 | T->isMemberFunctionPointerType(); |
103 | } |
104 | |
105 | llvm::Type *CodeGen::getVAListElementType(CodeGenFunction &CGF) { |
106 | return CGF.ConvertTypeForMem( |
107 | T: CGF.getContext().getBuiltinVaListType()->getPointeeType()); |
108 | } |
109 | |
110 | CGCXXABI::RecordArgABI CodeGen::getRecordArgABI(const RecordType *RT, |
111 | CGCXXABI &CXXABI) { |
112 | const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(Val: RT->getDecl()); |
113 | if (!RD) { |
114 | if (!RT->getDecl()->canPassInRegisters()) |
115 | return CGCXXABI::RAA_Indirect; |
116 | return CGCXXABI::RAA_Default; |
117 | } |
118 | return CXXABI.getRecordArgABI(RD); |
119 | } |
120 | |
121 | CGCXXABI::RecordArgABI CodeGen::getRecordArgABI(QualType T, CGCXXABI &CXXABI) { |
122 | const RecordType *RT = T->getAs<RecordType>(); |
123 | if (!RT) |
124 | return CGCXXABI::RAA_Default; |
125 | return getRecordArgABI(RT, CXXABI); |
126 | } |
127 | |
128 | bool CodeGen::classifyReturnType(const CGCXXABI &CXXABI, CGFunctionInfo &FI, |
129 | const ABIInfo &Info) { |
130 | QualType Ty = FI.getReturnType(); |
131 | |
132 | if (const auto *RT = Ty->getAs<RecordType>()) |
133 | if (!isa<CXXRecordDecl>(Val: RT->getDecl()) && |
134 | !RT->getDecl()->canPassInRegisters()) { |
135 | FI.getReturnInfo() = Info.getNaturalAlignIndirect(Ty); |
136 | return true; |
137 | } |
138 | |
139 | return CXXABI.classifyReturnType(FI); |
140 | } |
141 | |
142 | QualType CodeGen::useFirstFieldIfTransparentUnion(QualType Ty) { |
143 | if (const RecordType *UT = Ty->getAsUnionType()) { |
144 | const RecordDecl *UD = UT->getDecl(); |
145 | if (UD->hasAttr<TransparentUnionAttr>()) { |
146 | assert(!UD->field_empty() && "sema created an empty transparent union" ); |
147 | return UD->field_begin()->getType(); |
148 | } |
149 | } |
150 | return Ty; |
151 | } |
152 | |
153 | llvm::Value *CodeGen::emitRoundPointerUpToAlignment(CodeGenFunction &CGF, |
154 | llvm::Value *Ptr, |
155 | CharUnits Align) { |
156 | // OverflowArgArea = (OverflowArgArea + Align - 1) & -Align; |
157 | llvm::Value *RoundUp = CGF.Builder.CreateConstInBoundsGEP1_32( |
158 | Ty: CGF.Builder.getInt8Ty(), Ptr, Idx0: Align.getQuantity() - 1); |
159 | return CGF.Builder.CreateIntrinsic( |
160 | llvm::Intrinsic::ptrmask, {Ptr->getType(), CGF.IntPtrTy}, |
161 | {RoundUp, llvm::ConstantInt::get(CGF.IntPtrTy, -Align.getQuantity())}, |
162 | nullptr, Ptr->getName() + ".aligned" ); |
163 | } |
164 | |
165 | Address |
166 | CodeGen::emitVoidPtrDirectVAArg(CodeGenFunction &CGF, Address VAListAddr, |
167 | llvm::Type *DirectTy, CharUnits DirectSize, |
168 | CharUnits DirectAlign, CharUnits SlotSize, |
169 | bool AllowHigherAlign, bool ForceRightAdjust) { |
170 | // Cast the element type to i8* if necessary. Some platforms define |
171 | // va_list as a struct containing an i8* instead of just an i8*. |
172 | if (VAListAddr.getElementType() != CGF.Int8PtrTy) |
173 | VAListAddr = VAListAddr.withElementType(ElemTy: CGF.Int8PtrTy); |
174 | |
175 | llvm::Value *Ptr = CGF.Builder.CreateLoad(Addr: VAListAddr, Name: "argp.cur" ); |
176 | |
177 | // If the CC aligns values higher than the slot size, do so if needed. |
178 | Address Addr = Address::invalid(); |
179 | if (AllowHigherAlign && DirectAlign > SlotSize) { |
180 | Addr = Address(emitRoundPointerUpToAlignment(CGF, Ptr, Align: DirectAlign), |
181 | CGF.Int8Ty, DirectAlign); |
182 | } else { |
183 | Addr = Address(Ptr, CGF.Int8Ty, SlotSize); |
184 | } |
185 | |
186 | // Advance the pointer past the argument, then store that back. |
187 | CharUnits FullDirectSize = DirectSize.alignTo(Align: SlotSize); |
188 | Address NextPtr = |
189 | CGF.Builder.CreateConstInBoundsByteGEP(Addr, Offset: FullDirectSize, Name: "argp.next" ); |
190 | CGF.Builder.CreateStore(Val: NextPtr.emitRawPointer(CGF), Addr: VAListAddr); |
191 | |
192 | // If the argument is smaller than a slot, and this is a big-endian |
193 | // target, the argument will be right-adjusted in its slot. |
194 | if (DirectSize < SlotSize && CGF.CGM.getDataLayout().isBigEndian() && |
195 | (!DirectTy->isStructTy() || ForceRightAdjust)) { |
196 | Addr = CGF.Builder.CreateConstInBoundsByteGEP(Addr, Offset: SlotSize - DirectSize); |
197 | } |
198 | |
199 | return Addr.withElementType(ElemTy: DirectTy); |
200 | } |
201 | |
202 | Address CodeGen::emitVoidPtrVAArg(CodeGenFunction &CGF, Address VAListAddr, |
203 | QualType ValueTy, bool IsIndirect, |
204 | TypeInfoChars ValueInfo, |
205 | CharUnits SlotSizeAndAlign, |
206 | bool AllowHigherAlign, |
207 | bool ForceRightAdjust) { |
208 | // The size and alignment of the value that was passed directly. |
209 | CharUnits DirectSize, DirectAlign; |
210 | if (IsIndirect) { |
211 | DirectSize = CGF.getPointerSize(); |
212 | DirectAlign = CGF.getPointerAlign(); |
213 | } else { |
214 | DirectSize = ValueInfo.Width; |
215 | DirectAlign = ValueInfo.Align; |
216 | } |
217 | |
218 | // Cast the address we've calculated to the right type. |
219 | llvm::Type *DirectTy = CGF.ConvertTypeForMem(T: ValueTy), *ElementTy = DirectTy; |
220 | if (IsIndirect) { |
221 | unsigned AllocaAS = CGF.CGM.getDataLayout().getAllocaAddrSpace(); |
222 | DirectTy = llvm::PointerType::get(C&: CGF.getLLVMContext(), AddressSpace: AllocaAS); |
223 | } |
224 | |
225 | Address Addr = emitVoidPtrDirectVAArg(CGF, VAListAddr, DirectTy, DirectSize, |
226 | DirectAlign, SlotSize: SlotSizeAndAlign, |
227 | AllowHigherAlign, ForceRightAdjust); |
228 | |
229 | if (IsIndirect) { |
230 | Addr = Address(CGF.Builder.CreateLoad(Addr), ElementTy, ValueInfo.Align); |
231 | } |
232 | |
233 | return Addr; |
234 | } |
235 | |
236 | Address CodeGen::emitMergePHI(CodeGenFunction &CGF, Address Addr1, |
237 | llvm::BasicBlock *Block1, Address Addr2, |
238 | llvm::BasicBlock *Block2, |
239 | const llvm::Twine &Name) { |
240 | assert(Addr1.getType() == Addr2.getType()); |
241 | llvm::PHINode *PHI = CGF.Builder.CreatePHI(Ty: Addr1.getType(), NumReservedValues: 2, Name); |
242 | PHI->addIncoming(V: Addr1.emitRawPointer(CGF), BB: Block1); |
243 | PHI->addIncoming(V: Addr2.emitRawPointer(CGF), BB: Block2); |
244 | CharUnits Align = std::min(a: Addr1.getAlignment(), b: Addr2.getAlignment()); |
245 | return Address(PHI, Addr1.getElementType(), Align); |
246 | } |
247 | |
248 | bool CodeGen::isEmptyField(ASTContext &Context, const FieldDecl *FD, |
249 | bool AllowArrays, bool AsIfNoUniqueAddr) { |
250 | if (FD->isUnnamedBitField()) |
251 | return true; |
252 | |
253 | QualType FT = FD->getType(); |
254 | |
255 | // Constant arrays of empty records count as empty, strip them off. |
256 | // Constant arrays of zero length always count as empty. |
257 | bool WasArray = false; |
258 | if (AllowArrays) |
259 | while (const ConstantArrayType *AT = Context.getAsConstantArrayType(T: FT)) { |
260 | if (AT->isZeroSize()) |
261 | return true; |
262 | FT = AT->getElementType(); |
263 | // The [[no_unique_address]] special case below does not apply to |
264 | // arrays of C++ empty records, so we need to remember this fact. |
265 | WasArray = true; |
266 | } |
267 | |
268 | const RecordType *RT = FT->getAs<RecordType>(); |
269 | if (!RT) |
270 | return false; |
271 | |
272 | // C++ record fields are never empty, at least in the Itanium ABI. |
273 | // |
274 | // FIXME: We should use a predicate for whether this behavior is true in the |
275 | // current ABI. |
276 | // |
277 | // The exception to the above rule are fields marked with the |
278 | // [[no_unique_address]] attribute (since C++20). Those do count as empty |
279 | // according to the Itanium ABI. The exception applies only to records, |
280 | // not arrays of records, so we must also check whether we stripped off an |
281 | // array type above. |
282 | if (isa<CXXRecordDecl>(RT->getDecl()) && |
283 | (WasArray || (!AsIfNoUniqueAddr && !FD->hasAttr<NoUniqueAddressAttr>()))) |
284 | return false; |
285 | |
286 | return isEmptyRecord(Context, T: FT, AllowArrays, AsIfNoUniqueAddr); |
287 | } |
288 | |
289 | bool CodeGen::isEmptyRecord(ASTContext &Context, QualType T, bool AllowArrays, |
290 | bool AsIfNoUniqueAddr) { |
291 | const RecordType *RT = T->getAs<RecordType>(); |
292 | if (!RT) |
293 | return false; |
294 | const RecordDecl *RD = RT->getDecl(); |
295 | if (RD->hasFlexibleArrayMember()) |
296 | return false; |
297 | |
298 | // If this is a C++ record, check the bases first. |
299 | if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(Val: RD)) |
300 | for (const auto &I : CXXRD->bases()) |
301 | if (!isEmptyRecord(Context, T: I.getType(), AllowArrays: true, AsIfNoUniqueAddr)) |
302 | return false; |
303 | |
304 | for (const auto *I : RD->fields()) |
305 | if (!isEmptyField(Context, FD: I, AllowArrays, AsIfNoUniqueAddr)) |
306 | return false; |
307 | return true; |
308 | } |
309 | |
310 | const Type *CodeGen::isSingleElementStruct(QualType T, ASTContext &Context) { |
311 | const RecordType *RT = T->getAs<RecordType>(); |
312 | if (!RT) |
313 | return nullptr; |
314 | |
315 | const RecordDecl *RD = RT->getDecl(); |
316 | if (RD->hasFlexibleArrayMember()) |
317 | return nullptr; |
318 | |
319 | const Type *Found = nullptr; |
320 | |
321 | // If this is a C++ record, check the bases first. |
322 | if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(Val: RD)) { |
323 | for (const auto &I : CXXRD->bases()) { |
324 | // Ignore empty records. |
325 | if (isEmptyRecord(Context, T: I.getType(), AllowArrays: true)) |
326 | continue; |
327 | |
328 | // If we already found an element then this isn't a single-element struct. |
329 | if (Found) |
330 | return nullptr; |
331 | |
332 | // If this is non-empty and not a single element struct, the composite |
333 | // cannot be a single element struct. |
334 | Found = isSingleElementStruct(T: I.getType(), Context); |
335 | if (!Found) |
336 | return nullptr; |
337 | } |
338 | } |
339 | |
340 | // Check for single element. |
341 | for (const auto *FD : RD->fields()) { |
342 | QualType FT = FD->getType(); |
343 | |
344 | // Ignore empty fields. |
345 | if (isEmptyField(Context, FD, AllowArrays: true)) |
346 | continue; |
347 | |
348 | // If we already found an element then this isn't a single-element |
349 | // struct. |
350 | if (Found) |
351 | return nullptr; |
352 | |
353 | // Treat single element arrays as the element. |
354 | while (const ConstantArrayType *AT = Context.getAsConstantArrayType(T: FT)) { |
355 | if (AT->getZExtSize() != 1) |
356 | break; |
357 | FT = AT->getElementType(); |
358 | } |
359 | |
360 | if (!isAggregateTypeForABI(T: FT)) { |
361 | Found = FT.getTypePtr(); |
362 | } else { |
363 | Found = isSingleElementStruct(T: FT, Context); |
364 | if (!Found) |
365 | return nullptr; |
366 | } |
367 | } |
368 | |
369 | // We don't consider a struct a single-element struct if it has |
370 | // padding beyond the element type. |
371 | if (Found && Context.getTypeSize(T: Found) != Context.getTypeSize(T)) |
372 | return nullptr; |
373 | |
374 | return Found; |
375 | } |
376 | |
377 | Address CodeGen::EmitVAArgInstr(CodeGenFunction &CGF, Address VAListAddr, |
378 | QualType Ty, const ABIArgInfo &AI) { |
379 | // This default implementation defers to the llvm backend's va_arg |
380 | // instruction. It can handle only passing arguments directly |
381 | // (typically only handled in the backend for primitive types), or |
382 | // aggregates passed indirectly by pointer (NOTE: if the "byval" |
383 | // flag has ABI impact in the callee, this implementation cannot |
384 | // work.) |
385 | |
386 | // Only a few cases are covered here at the moment -- those needed |
387 | // by the default abi. |
388 | llvm::Value *Val; |
389 | |
390 | if (AI.isIndirect()) { |
391 | assert(!AI.getPaddingType() && |
392 | "Unexpected PaddingType seen in arginfo in generic VAArg emitter!" ); |
393 | assert( |
394 | !AI.getIndirectRealign() && |
395 | "Unexpected IndirectRealign seen in arginfo in generic VAArg emitter!" ); |
396 | |
397 | auto TyInfo = CGF.getContext().getTypeInfoInChars(T: Ty); |
398 | CharUnits TyAlignForABI = TyInfo.Align; |
399 | |
400 | llvm::Type *ElementTy = CGF.ConvertTypeForMem(T: Ty); |
401 | llvm::Type *BaseTy = llvm::PointerType::getUnqual(ElementType: ElementTy); |
402 | llvm::Value *Addr = |
403 | CGF.Builder.CreateVAArg(List: VAListAddr.emitRawPointer(CGF), Ty: BaseTy); |
404 | return Address(Addr, ElementTy, TyAlignForABI); |
405 | } else { |
406 | assert((AI.isDirect() || AI.isExtend()) && |
407 | "Unexpected ArgInfo Kind in generic VAArg emitter!" ); |
408 | |
409 | assert(!AI.getInReg() && |
410 | "Unexpected InReg seen in arginfo in generic VAArg emitter!" ); |
411 | assert(!AI.getPaddingType() && |
412 | "Unexpected PaddingType seen in arginfo in generic VAArg emitter!" ); |
413 | assert(!AI.getDirectOffset() && |
414 | "Unexpected DirectOffset seen in arginfo in generic VAArg emitter!" ); |
415 | assert(!AI.getCoerceToType() && |
416 | "Unexpected CoerceToType seen in arginfo in generic VAArg emitter!" ); |
417 | |
418 | Address Temp = CGF.CreateMemTemp(T: Ty, Name: "varet" ); |
419 | Val = CGF.Builder.CreateVAArg(List: VAListAddr.emitRawPointer(CGF), |
420 | Ty: CGF.ConvertTypeForMem(T: Ty)); |
421 | CGF.Builder.CreateStore(Val, Addr: Temp); |
422 | return Temp; |
423 | } |
424 | } |
425 | |
426 | bool CodeGen::isSIMDVectorType(ASTContext &Context, QualType Ty) { |
427 | return Ty->getAs<VectorType>() && Context.getTypeSize(T: Ty) == 128; |
428 | } |
429 | |
430 | bool CodeGen::isRecordWithSIMDVectorType(ASTContext &Context, QualType Ty) { |
431 | const RecordType *RT = Ty->getAs<RecordType>(); |
432 | if (!RT) |
433 | return false; |
434 | const RecordDecl *RD = RT->getDecl(); |
435 | |
436 | // If this is a C++ record, check the bases first. |
437 | if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(Val: RD)) |
438 | for (const auto &I : CXXRD->bases()) |
439 | if (!isRecordWithSIMDVectorType(Context, Ty: I.getType())) |
440 | return false; |
441 | |
442 | for (const auto *i : RD->fields()) { |
443 | QualType FT = i->getType(); |
444 | |
445 | if (isSIMDVectorType(Context, Ty: FT)) |
446 | return true; |
447 | |
448 | if (isRecordWithSIMDVectorType(Context, Ty: FT)) |
449 | return true; |
450 | } |
451 | |
452 | return false; |
453 | } |
454 | |