Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
14 | pmbaty | 1 | //==-- CGFunctionInfo.h - Representation of function argument/return types -==// |
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 | // Defines CGFunctionInfo and associated types used in representing the |
||
10 | // LLVM source types and ABI-coerced types for function arguments and |
||
11 | // return values. |
||
12 | // |
||
13 | //===----------------------------------------------------------------------===// |
||
14 | |||
15 | #ifndef LLVM_CLANG_CODEGEN_CGFUNCTIONINFO_H |
||
16 | #define LLVM_CLANG_CODEGEN_CGFUNCTIONINFO_H |
||
17 | |||
18 | #include "clang/AST/CanonicalType.h" |
||
19 | #include "clang/AST/CharUnits.h" |
||
20 | #include "clang/AST/Decl.h" |
||
21 | #include "clang/AST/Type.h" |
||
22 | #include "llvm/IR/DerivedTypes.h" |
||
23 | #include "llvm/ADT/FoldingSet.h" |
||
24 | #include "llvm/Support/TrailingObjects.h" |
||
25 | #include <cassert> |
||
26 | |||
27 | namespace clang { |
||
28 | namespace CodeGen { |
||
29 | |||
30 | /// ABIArgInfo - Helper class to encapsulate information about how a |
||
31 | /// specific C type should be passed to or returned from a function. |
||
32 | class ABIArgInfo { |
||
33 | public: |
||
34 | enum Kind : uint8_t { |
||
35 | /// Direct - Pass the argument directly using the normal converted LLVM |
||
36 | /// type, or by coercing to another specified type stored in |
||
37 | /// 'CoerceToType'). If an offset is specified (in UIntData), then the |
||
38 | /// argument passed is offset by some number of bytes in the memory |
||
39 | /// representation. A dummy argument is emitted before the real argument |
||
40 | /// if the specified type stored in "PaddingType" is not zero. |
||
41 | Direct, |
||
42 | |||
43 | /// Extend - Valid only for integer argument types. Same as 'direct' |
||
44 | /// but also emit a zero/sign extension attribute. |
||
45 | Extend, |
||
46 | |||
47 | /// Indirect - Pass the argument indirectly via a hidden pointer with the |
||
48 | /// specified alignment (0 indicates default alignment) and address space. |
||
49 | Indirect, |
||
50 | |||
51 | /// IndirectAliased - Similar to Indirect, but the pointer may be to an |
||
52 | /// object that is otherwise referenced. The object is known to not be |
||
53 | /// modified through any other references for the duration of the call, and |
||
54 | /// the callee must not itself modify the object. Because C allows |
||
55 | /// parameter variables to be modified and guarantees that they have unique |
||
56 | /// addresses, the callee must defensively copy the object into a local |
||
57 | /// variable if it might be modified or its address might be compared. |
||
58 | /// Since those are uncommon, in principle this convention allows programs |
||
59 | /// to avoid copies in more situations. However, it may introduce *extra* |
||
60 | /// copies if the callee fails to prove that a copy is unnecessary and the |
||
61 | /// caller naturally produces an unaliased object for the argument. |
||
62 | IndirectAliased, |
||
63 | |||
64 | /// Ignore - Ignore the argument (treat as void). Useful for void and |
||
65 | /// empty structs. |
||
66 | Ignore, |
||
67 | |||
68 | /// Expand - Only valid for aggregate argument types. The structure should |
||
69 | /// be expanded into consecutive arguments for its constituent fields. |
||
70 | /// Currently expand is only allowed on structures whose fields |
||
71 | /// are all scalar types or are themselves expandable types. |
||
72 | Expand, |
||
73 | |||
74 | /// CoerceAndExpand - Only valid for aggregate argument types. The |
||
75 | /// structure should be expanded into consecutive arguments corresponding |
||
76 | /// to the non-array elements of the type stored in CoerceToType. |
||
77 | /// Array elements in the type are assumed to be padding and skipped. |
||
78 | CoerceAndExpand, |
||
79 | |||
80 | /// InAlloca - Pass the argument directly using the LLVM inalloca attribute. |
||
81 | /// This is similar to indirect with byval, except it only applies to |
||
82 | /// arguments stored in memory and forbids any implicit copies. When |
||
83 | /// applied to a return type, it means the value is returned indirectly via |
||
84 | /// an implicit sret parameter stored in the argument struct. |
||
85 | InAlloca, |
||
86 | KindFirst = Direct, |
||
87 | KindLast = InAlloca |
||
88 | }; |
||
89 | |||
90 | private: |
||
91 | llvm::Type *TypeData; // canHaveCoerceToType() |
||
92 | union { |
||
93 | llvm::Type *PaddingType; // canHavePaddingType() |
||
94 | llvm::Type *UnpaddedCoerceAndExpandType; // isCoerceAndExpand() |
||
95 | }; |
||
96 | struct DirectAttrInfo { |
||
97 | unsigned Offset; |
||
98 | unsigned Align; |
||
99 | }; |
||
100 | struct IndirectAttrInfo { |
||
101 | unsigned Align; |
||
102 | unsigned AddrSpace; |
||
103 | }; |
||
104 | union { |
||
105 | DirectAttrInfo DirectAttr; // isDirect() || isExtend() |
||
106 | IndirectAttrInfo IndirectAttr; // isIndirect() |
||
107 | unsigned AllocaFieldIndex; // isInAlloca() |
||
108 | }; |
||
109 | Kind TheKind; |
||
110 | bool PaddingInReg : 1; |
||
111 | bool InAllocaSRet : 1; // isInAlloca() |
||
112 | bool InAllocaIndirect : 1;// isInAlloca() |
||
113 | bool IndirectByVal : 1; // isIndirect() |
||
114 | bool IndirectRealign : 1; // isIndirect() |
||
115 | bool SRetAfterThis : 1; // isIndirect() |
||
116 | bool InReg : 1; // isDirect() || isExtend() || isIndirect() |
||
117 | bool CanBeFlattened: 1; // isDirect() |
||
118 | bool SignExt : 1; // isExtend() |
||
119 | |||
120 | bool canHavePaddingType() const { |
||
121 | return isDirect() || isExtend() || isIndirect() || isIndirectAliased() || |
||
122 | isExpand(); |
||
123 | } |
||
124 | void setPaddingType(llvm::Type *T) { |
||
125 | assert(canHavePaddingType()); |
||
126 | PaddingType = T; |
||
127 | } |
||
128 | |||
129 | void setUnpaddedCoerceToType(llvm::Type *T) { |
||
130 | assert(isCoerceAndExpand()); |
||
131 | UnpaddedCoerceAndExpandType = T; |
||
132 | } |
||
133 | |||
134 | public: |
||
135 | ABIArgInfo(Kind K = Direct) |
||
136 | : TypeData(nullptr), PaddingType(nullptr), DirectAttr{0, 0}, TheKind(K), |
||
137 | PaddingInReg(false), InAllocaSRet(false), |
||
138 | InAllocaIndirect(false), IndirectByVal(false), IndirectRealign(false), |
||
139 | SRetAfterThis(false), InReg(false), CanBeFlattened(false), |
||
140 | SignExt(false) {} |
||
141 | |||
142 | static ABIArgInfo getDirect(llvm::Type *T = nullptr, unsigned Offset = 0, |
||
143 | llvm::Type *Padding = nullptr, |
||
144 | bool CanBeFlattened = true, unsigned Align = 0) { |
||
145 | auto AI = ABIArgInfo(Direct); |
||
146 | AI.setCoerceToType(T); |
||
147 | AI.setPaddingType(Padding); |
||
148 | AI.setDirectOffset(Offset); |
||
149 | AI.setDirectAlign(Align); |
||
150 | AI.setCanBeFlattened(CanBeFlattened); |
||
151 | return AI; |
||
152 | } |
||
153 | static ABIArgInfo getDirectInReg(llvm::Type *T = nullptr) { |
||
154 | auto AI = getDirect(T); |
||
155 | AI.setInReg(true); |
||
156 | return AI; |
||
157 | } |
||
158 | |||
159 | static ABIArgInfo getSignExtend(QualType Ty, llvm::Type *T = nullptr) { |
||
160 | assert(Ty->isIntegralOrEnumerationType() && "Unexpected QualType"); |
||
161 | auto AI = ABIArgInfo(Extend); |
||
162 | AI.setCoerceToType(T); |
||
163 | AI.setPaddingType(nullptr); |
||
164 | AI.setDirectOffset(0); |
||
165 | AI.setDirectAlign(0); |
||
166 | AI.setSignExt(true); |
||
167 | return AI; |
||
168 | } |
||
169 | |||
170 | static ABIArgInfo getZeroExtend(QualType Ty, llvm::Type *T = nullptr) { |
||
171 | assert(Ty->isIntegralOrEnumerationType() && "Unexpected QualType"); |
||
172 | auto AI = ABIArgInfo(Extend); |
||
173 | AI.setCoerceToType(T); |
||
174 | AI.setPaddingType(nullptr); |
||
175 | AI.setDirectOffset(0); |
||
176 | AI.setDirectAlign(0); |
||
177 | AI.setSignExt(false); |
||
178 | return AI; |
||
179 | } |
||
180 | |||
181 | // ABIArgInfo will record the argument as being extended based on the sign |
||
182 | // of its type. |
||
183 | static ABIArgInfo getExtend(QualType Ty, llvm::Type *T = nullptr) { |
||
184 | assert(Ty->isIntegralOrEnumerationType() && "Unexpected QualType"); |
||
185 | if (Ty->hasSignedIntegerRepresentation()) |
||
186 | return getSignExtend(Ty, T); |
||
187 | return getZeroExtend(Ty, T); |
||
188 | } |
||
189 | |||
190 | static ABIArgInfo getExtendInReg(QualType Ty, llvm::Type *T = nullptr) { |
||
191 | auto AI = getExtend(Ty, T); |
||
192 | AI.setInReg(true); |
||
193 | return AI; |
||
194 | } |
||
195 | static ABIArgInfo getIgnore() { |
||
196 | return ABIArgInfo(Ignore); |
||
197 | } |
||
198 | static ABIArgInfo getIndirect(CharUnits Alignment, bool ByVal = true, |
||
199 | bool Realign = false, |
||
200 | llvm::Type *Padding = nullptr) { |
||
201 | auto AI = ABIArgInfo(Indirect); |
||
202 | AI.setIndirectAlign(Alignment); |
||
203 | AI.setIndirectByVal(ByVal); |
||
204 | AI.setIndirectRealign(Realign); |
||
205 | AI.setSRetAfterThis(false); |
||
206 | AI.setPaddingType(Padding); |
||
207 | return AI; |
||
208 | } |
||
209 | |||
210 | /// Pass this in memory using the IR byref attribute. |
||
211 | static ABIArgInfo getIndirectAliased(CharUnits Alignment, unsigned AddrSpace, |
||
212 | bool Realign = false, |
||
213 | llvm::Type *Padding = nullptr) { |
||
214 | auto AI = ABIArgInfo(IndirectAliased); |
||
215 | AI.setIndirectAlign(Alignment); |
||
216 | AI.setIndirectRealign(Realign); |
||
217 | AI.setPaddingType(Padding); |
||
218 | AI.setIndirectAddrSpace(AddrSpace); |
||
219 | return AI; |
||
220 | } |
||
221 | |||
222 | static ABIArgInfo getIndirectInReg(CharUnits Alignment, bool ByVal = true, |
||
223 | bool Realign = false) { |
||
224 | auto AI = getIndirect(Alignment, ByVal, Realign); |
||
225 | AI.setInReg(true); |
||
226 | return AI; |
||
227 | } |
||
228 | static ABIArgInfo getInAlloca(unsigned FieldIndex, bool Indirect = false) { |
||
229 | auto AI = ABIArgInfo(InAlloca); |
||
230 | AI.setInAllocaFieldIndex(FieldIndex); |
||
231 | AI.setInAllocaIndirect(Indirect); |
||
232 | return AI; |
||
233 | } |
||
234 | static ABIArgInfo getExpand() { |
||
235 | auto AI = ABIArgInfo(Expand); |
||
236 | AI.setPaddingType(nullptr); |
||
237 | return AI; |
||
238 | } |
||
239 | static ABIArgInfo getExpandWithPadding(bool PaddingInReg, |
||
240 | llvm::Type *Padding) { |
||
241 | auto AI = getExpand(); |
||
242 | AI.setPaddingInReg(PaddingInReg); |
||
243 | AI.setPaddingType(Padding); |
||
244 | return AI; |
||
245 | } |
||
246 | |||
247 | /// \param unpaddedCoerceToType The coerce-to type with padding elements |
||
248 | /// removed, canonicalized to a single element if it would otherwise |
||
249 | /// have exactly one element. |
||
250 | static ABIArgInfo getCoerceAndExpand(llvm::StructType *coerceToType, |
||
251 | llvm::Type *unpaddedCoerceToType) { |
||
252 | #ifndef NDEBUG |
||
253 | // Check that unpaddedCoerceToType has roughly the right shape. |
||
254 | |||
255 | // Assert that we only have a struct type if there are multiple elements. |
||
256 | auto unpaddedStruct = dyn_cast<llvm::StructType>(unpaddedCoerceToType); |
||
257 | assert(!unpaddedStruct || unpaddedStruct->getNumElements() != 1); |
||
258 | |||
259 | // Assert that all the non-padding elements have a corresponding element |
||
260 | // in the unpadded type. |
||
261 | unsigned unpaddedIndex = 0; |
||
262 | for (auto eltType : coerceToType->elements()) { |
||
263 | if (isPaddingForCoerceAndExpand(eltType)) continue; |
||
264 | if (unpaddedStruct) { |
||
265 | assert(unpaddedStruct->getElementType(unpaddedIndex) == eltType); |
||
266 | } else { |
||
267 | assert(unpaddedIndex == 0 && unpaddedCoerceToType == eltType); |
||
268 | } |
||
269 | unpaddedIndex++; |
||
270 | } |
||
271 | |||
272 | // Assert that there aren't extra elements in the unpadded type. |
||
273 | if (unpaddedStruct) { |
||
274 | assert(unpaddedStruct->getNumElements() == unpaddedIndex); |
||
275 | } else { |
||
276 | assert(unpaddedIndex == 1); |
||
277 | } |
||
278 | #endif |
||
279 | |||
280 | auto AI = ABIArgInfo(CoerceAndExpand); |
||
281 | AI.setCoerceToType(coerceToType); |
||
282 | AI.setUnpaddedCoerceToType(unpaddedCoerceToType); |
||
283 | return AI; |
||
284 | } |
||
285 | |||
286 | static bool isPaddingForCoerceAndExpand(llvm::Type *eltType) { |
||
287 | if (eltType->isArrayTy()) { |
||
288 | assert(eltType->getArrayElementType()->isIntegerTy(8)); |
||
289 | return true; |
||
290 | } else { |
||
291 | return false; |
||
292 | } |
||
293 | } |
||
294 | |||
295 | Kind getKind() const { return TheKind; } |
||
296 | bool isDirect() const { return TheKind == Direct; } |
||
297 | bool isInAlloca() const { return TheKind == InAlloca; } |
||
298 | bool isExtend() const { return TheKind == Extend; } |
||
299 | bool isIgnore() const { return TheKind == Ignore; } |
||
300 | bool isIndirect() const { return TheKind == Indirect; } |
||
301 | bool isIndirectAliased() const { return TheKind == IndirectAliased; } |
||
302 | bool isExpand() const { return TheKind == Expand; } |
||
303 | bool isCoerceAndExpand() const { return TheKind == CoerceAndExpand; } |
||
304 | |||
305 | bool canHaveCoerceToType() const { |
||
306 | return isDirect() || isExtend() || isCoerceAndExpand(); |
||
307 | } |
||
308 | |||
309 | // Direct/Extend accessors |
||
310 | unsigned getDirectOffset() const { |
||
311 | assert((isDirect() || isExtend()) && "Not a direct or extend kind"); |
||
312 | return DirectAttr.Offset; |
||
313 | } |
||
314 | void setDirectOffset(unsigned Offset) { |
||
315 | assert((isDirect() || isExtend()) && "Not a direct or extend kind"); |
||
316 | DirectAttr.Offset = Offset; |
||
317 | } |
||
318 | |||
319 | unsigned getDirectAlign() const { |
||
320 | assert((isDirect() || isExtend()) && "Not a direct or extend kind"); |
||
321 | return DirectAttr.Align; |
||
322 | } |
||
323 | void setDirectAlign(unsigned Align) { |
||
324 | assert((isDirect() || isExtend()) && "Not a direct or extend kind"); |
||
325 | DirectAttr.Align = Align; |
||
326 | } |
||
327 | |||
328 | bool isSignExt() const { |
||
329 | assert(isExtend() && "Invalid kind!"); |
||
330 | return SignExt; |
||
331 | } |
||
332 | void setSignExt(bool SExt) { |
||
333 | assert(isExtend() && "Invalid kind!"); |
||
334 | SignExt = SExt; |
||
335 | } |
||
336 | |||
337 | llvm::Type *getPaddingType() const { |
||
338 | return (canHavePaddingType() ? PaddingType : nullptr); |
||
339 | } |
||
340 | |||
341 | bool getPaddingInReg() const { |
||
342 | return PaddingInReg; |
||
343 | } |
||
344 | void setPaddingInReg(bool PIR) { |
||
345 | PaddingInReg = PIR; |
||
346 | } |
||
347 | |||
348 | llvm::Type *getCoerceToType() const { |
||
349 | assert(canHaveCoerceToType() && "Invalid kind!"); |
||
350 | return TypeData; |
||
351 | } |
||
352 | |||
353 | void setCoerceToType(llvm::Type *T) { |
||
354 | assert(canHaveCoerceToType() && "Invalid kind!"); |
||
355 | TypeData = T; |
||
356 | } |
||
357 | |||
358 | llvm::StructType *getCoerceAndExpandType() const { |
||
359 | assert(isCoerceAndExpand()); |
||
360 | return cast<llvm::StructType>(TypeData); |
||
361 | } |
||
362 | |||
363 | llvm::Type *getUnpaddedCoerceAndExpandType() const { |
||
364 | assert(isCoerceAndExpand()); |
||
365 | return UnpaddedCoerceAndExpandType; |
||
366 | } |
||
367 | |||
368 | ArrayRef<llvm::Type *>getCoerceAndExpandTypeSequence() const { |
||
369 | assert(isCoerceAndExpand()); |
||
370 | if (auto structTy = |
||
371 | dyn_cast<llvm::StructType>(UnpaddedCoerceAndExpandType)) { |
||
372 | return structTy->elements(); |
||
373 | } else { |
||
374 | return llvm::ArrayRef(&UnpaddedCoerceAndExpandType, 1); |
||
375 | } |
||
376 | } |
||
377 | |||
378 | bool getInReg() const { |
||
379 | assert((isDirect() || isExtend() || isIndirect()) && "Invalid kind!"); |
||
380 | return InReg; |
||
381 | } |
||
382 | |||
383 | void setInReg(bool IR) { |
||
384 | assert((isDirect() || isExtend() || isIndirect()) && "Invalid kind!"); |
||
385 | InReg = IR; |
||
386 | } |
||
387 | |||
388 | // Indirect accessors |
||
389 | CharUnits getIndirectAlign() const { |
||
390 | assert((isIndirect() || isIndirectAliased()) && "Invalid kind!"); |
||
391 | return CharUnits::fromQuantity(IndirectAttr.Align); |
||
392 | } |
||
393 | void setIndirectAlign(CharUnits IA) { |
||
394 | assert((isIndirect() || isIndirectAliased()) && "Invalid kind!"); |
||
395 | IndirectAttr.Align = IA.getQuantity(); |
||
396 | } |
||
397 | |||
398 | bool getIndirectByVal() const { |
||
399 | assert(isIndirect() && "Invalid kind!"); |
||
400 | return IndirectByVal; |
||
401 | } |
||
402 | void setIndirectByVal(bool IBV) { |
||
403 | assert(isIndirect() && "Invalid kind!"); |
||
404 | IndirectByVal = IBV; |
||
405 | } |
||
406 | |||
407 | unsigned getIndirectAddrSpace() const { |
||
408 | assert(isIndirectAliased() && "Invalid kind!"); |
||
409 | return IndirectAttr.AddrSpace; |
||
410 | } |
||
411 | |||
412 | void setIndirectAddrSpace(unsigned AddrSpace) { |
||
413 | assert(isIndirectAliased() && "Invalid kind!"); |
||
414 | IndirectAttr.AddrSpace = AddrSpace; |
||
415 | } |
||
416 | |||
417 | bool getIndirectRealign() const { |
||
418 | assert((isIndirect() || isIndirectAliased()) && "Invalid kind!"); |
||
419 | return IndirectRealign; |
||
420 | } |
||
421 | void setIndirectRealign(bool IR) { |
||
422 | assert((isIndirect() || isIndirectAliased()) && "Invalid kind!"); |
||
423 | IndirectRealign = IR; |
||
424 | } |
||
425 | |||
426 | bool isSRetAfterThis() const { |
||
427 | assert(isIndirect() && "Invalid kind!"); |
||
428 | return SRetAfterThis; |
||
429 | } |
||
430 | void setSRetAfterThis(bool AfterThis) { |
||
431 | assert(isIndirect() && "Invalid kind!"); |
||
432 | SRetAfterThis = AfterThis; |
||
433 | } |
||
434 | |||
435 | unsigned getInAllocaFieldIndex() const { |
||
436 | assert(isInAlloca() && "Invalid kind!"); |
||
437 | return AllocaFieldIndex; |
||
438 | } |
||
439 | void setInAllocaFieldIndex(unsigned FieldIndex) { |
||
440 | assert(isInAlloca() && "Invalid kind!"); |
||
441 | AllocaFieldIndex = FieldIndex; |
||
442 | } |
||
443 | |||
444 | unsigned getInAllocaIndirect() const { |
||
445 | assert(isInAlloca() && "Invalid kind!"); |
||
446 | return InAllocaIndirect; |
||
447 | } |
||
448 | void setInAllocaIndirect(bool Indirect) { |
||
449 | assert(isInAlloca() && "Invalid kind!"); |
||
450 | InAllocaIndirect = Indirect; |
||
451 | } |
||
452 | |||
453 | /// Return true if this field of an inalloca struct should be returned |
||
454 | /// to implement a struct return calling convention. |
||
455 | bool getInAllocaSRet() const { |
||
456 | assert(isInAlloca() && "Invalid kind!"); |
||
457 | return InAllocaSRet; |
||
458 | } |
||
459 | |||
460 | void setInAllocaSRet(bool SRet) { |
||
461 | assert(isInAlloca() && "Invalid kind!"); |
||
462 | InAllocaSRet = SRet; |
||
463 | } |
||
464 | |||
465 | bool getCanBeFlattened() const { |
||
466 | assert(isDirect() && "Invalid kind!"); |
||
467 | return CanBeFlattened; |
||
468 | } |
||
469 | |||
470 | void setCanBeFlattened(bool Flatten) { |
||
471 | assert(isDirect() && "Invalid kind!"); |
||
472 | CanBeFlattened = Flatten; |
||
473 | } |
||
474 | |||
475 | void dump() const; |
||
476 | }; |
||
477 | |||
478 | /// A class for recording the number of arguments that a function |
||
479 | /// signature requires. |
||
480 | class RequiredArgs { |
||
481 | /// The number of required arguments, or ~0 if the signature does |
||
482 | /// not permit optional arguments. |
||
483 | unsigned NumRequired; |
||
484 | public: |
||
485 | enum All_t { All }; |
||
486 | |||
487 | RequiredArgs(All_t _) : NumRequired(~0U) {} |
||
488 | explicit RequiredArgs(unsigned n) : NumRequired(n) { |
||
489 | assert(n != ~0U); |
||
490 | } |
||
491 | |||
492 | /// Compute the arguments required by the given formal prototype, |
||
493 | /// given that there may be some additional, non-formal arguments |
||
494 | /// in play. |
||
495 | /// |
||
496 | /// If FD is not null, this will consider pass_object_size params in FD. |
||
497 | static RequiredArgs forPrototypePlus(const FunctionProtoType *prototype, |
||
498 | unsigned additional) { |
||
499 | if (!prototype->isVariadic()) return All; |
||
500 | |||
501 | if (prototype->hasExtParameterInfos()) |
||
502 | additional += llvm::count_if( |
||
503 | prototype->getExtParameterInfos(), |
||
504 | [](const FunctionProtoType::ExtParameterInfo &ExtInfo) { |
||
505 | return ExtInfo.hasPassObjectSize(); |
||
506 | }); |
||
507 | |||
508 | return RequiredArgs(prototype->getNumParams() + additional); |
||
509 | } |
||
510 | |||
511 | static RequiredArgs forPrototypePlus(CanQual<FunctionProtoType> prototype, |
||
512 | unsigned additional) { |
||
513 | return forPrototypePlus(prototype.getTypePtr(), additional); |
||
514 | } |
||
515 | |||
516 | static RequiredArgs forPrototype(const FunctionProtoType *prototype) { |
||
517 | return forPrototypePlus(prototype, 0); |
||
518 | } |
||
519 | |||
520 | static RequiredArgs forPrototype(CanQual<FunctionProtoType> prototype) { |
||
521 | return forPrototypePlus(prototype.getTypePtr(), 0); |
||
522 | } |
||
523 | |||
524 | bool allowsOptionalArgs() const { return NumRequired != ~0U; } |
||
525 | unsigned getNumRequiredArgs() const { |
||
526 | assert(allowsOptionalArgs()); |
||
527 | return NumRequired; |
||
528 | } |
||
529 | |||
530 | unsigned getOpaqueData() const { return NumRequired; } |
||
531 | static RequiredArgs getFromOpaqueData(unsigned value) { |
||
532 | if (value == ~0U) return All; |
||
533 | return RequiredArgs(value); |
||
534 | } |
||
535 | }; |
||
536 | |||
537 | // Implementation detail of CGFunctionInfo, factored out so it can be named |
||
538 | // in the TrailingObjects base class of CGFunctionInfo. |
||
539 | struct CGFunctionInfoArgInfo { |
||
540 | CanQualType type; |
||
541 | ABIArgInfo info; |
||
542 | }; |
||
543 | |||
544 | /// CGFunctionInfo - Class to encapsulate the information about a |
||
545 | /// function definition. |
||
546 | class CGFunctionInfo final |
||
547 | : public llvm::FoldingSetNode, |
||
548 | private llvm::TrailingObjects<CGFunctionInfo, CGFunctionInfoArgInfo, |
||
549 | FunctionProtoType::ExtParameterInfo> { |
||
550 | typedef CGFunctionInfoArgInfo ArgInfo; |
||
551 | typedef FunctionProtoType::ExtParameterInfo ExtParameterInfo; |
||
552 | |||
553 | /// The LLVM::CallingConv to use for this function (as specified by the |
||
554 | /// user). |
||
555 | unsigned CallingConvention : 8; |
||
556 | |||
557 | /// The LLVM::CallingConv to actually use for this function, which may |
||
558 | /// depend on the ABI. |
||
559 | unsigned EffectiveCallingConvention : 8; |
||
560 | |||
561 | /// The clang::CallingConv that this was originally created with. |
||
562 | unsigned ASTCallingConvention : 6; |
||
563 | |||
564 | /// Whether this is an instance method. |
||
565 | unsigned InstanceMethod : 1; |
||
566 | |||
567 | /// Whether this is a chain call. |
||
568 | unsigned ChainCall : 1; |
||
569 | |||
570 | /// Whether this function is a CMSE nonsecure call |
||
571 | unsigned CmseNSCall : 1; |
||
572 | |||
573 | /// Whether this function is noreturn. |
||
574 | unsigned NoReturn : 1; |
||
575 | |||
576 | /// Whether this function is returns-retained. |
||
577 | unsigned ReturnsRetained : 1; |
||
578 | |||
579 | /// Whether this function saved caller registers. |
||
580 | unsigned NoCallerSavedRegs : 1; |
||
581 | |||
582 | /// How many arguments to pass inreg. |
||
583 | unsigned HasRegParm : 1; |
||
584 | unsigned RegParm : 3; |
||
585 | |||
586 | /// Whether this function has nocf_check attribute. |
||
587 | unsigned NoCfCheck : 1; |
||
588 | |||
589 | /// Log 2 of the maximum vector width. |
||
590 | unsigned MaxVectorWidth : 4; |
||
591 | |||
592 | RequiredArgs Required; |
||
593 | |||
594 | /// The struct representing all arguments passed in memory. Only used when |
||
595 | /// passing non-trivial types with inalloca. Not part of the profile. |
||
596 | llvm::StructType *ArgStruct; |
||
597 | unsigned ArgStructAlign : 31; |
||
598 | unsigned HasExtParameterInfos : 1; |
||
599 | |||
600 | unsigned NumArgs; |
||
601 | |||
602 | ArgInfo *getArgsBuffer() { |
||
603 | return getTrailingObjects<ArgInfo>(); |
||
604 | } |
||
605 | const ArgInfo *getArgsBuffer() const { |
||
606 | return getTrailingObjects<ArgInfo>(); |
||
607 | } |
||
608 | |||
609 | ExtParameterInfo *getExtParameterInfosBuffer() { |
||
610 | return getTrailingObjects<ExtParameterInfo>(); |
||
611 | } |
||
612 | const ExtParameterInfo *getExtParameterInfosBuffer() const{ |
||
613 | return getTrailingObjects<ExtParameterInfo>(); |
||
614 | } |
||
615 | |||
616 | CGFunctionInfo() : Required(RequiredArgs::All) {} |
||
617 | |||
618 | public: |
||
619 | static CGFunctionInfo *create(unsigned llvmCC, |
||
620 | bool instanceMethod, |
||
621 | bool chainCall, |
||
622 | const FunctionType::ExtInfo &extInfo, |
||
623 | ArrayRef<ExtParameterInfo> paramInfos, |
||
624 | CanQualType resultType, |
||
625 | ArrayRef<CanQualType> argTypes, |
||
626 | RequiredArgs required); |
||
627 | void operator delete(void *p) { ::operator delete(p); } |
||
628 | |||
629 | // Friending class TrailingObjects is apparently not good enough for MSVC, |
||
630 | // so these have to be public. |
||
631 | friend class TrailingObjects; |
||
632 | size_t numTrailingObjects(OverloadToken<ArgInfo>) const { |
||
633 | return NumArgs + 1; |
||
634 | } |
||
635 | size_t numTrailingObjects(OverloadToken<ExtParameterInfo>) const { |
||
636 | return (HasExtParameterInfos ? NumArgs : 0); |
||
637 | } |
||
638 | |||
639 | typedef const ArgInfo *const_arg_iterator; |
||
640 | typedef ArgInfo *arg_iterator; |
||
641 | |||
642 | MutableArrayRef<ArgInfo> arguments() { |
||
643 | return MutableArrayRef<ArgInfo>(arg_begin(), NumArgs); |
||
644 | } |
||
645 | ArrayRef<ArgInfo> arguments() const { |
||
646 | return ArrayRef<ArgInfo>(arg_begin(), NumArgs); |
||
647 | } |
||
648 | |||
649 | const_arg_iterator arg_begin() const { return getArgsBuffer() + 1; } |
||
650 | const_arg_iterator arg_end() const { return getArgsBuffer() + 1 + NumArgs; } |
||
651 | arg_iterator arg_begin() { return getArgsBuffer() + 1; } |
||
652 | arg_iterator arg_end() { return getArgsBuffer() + 1 + NumArgs; } |
||
653 | |||
654 | unsigned arg_size() const { return NumArgs; } |
||
655 | |||
656 | bool isVariadic() const { return Required.allowsOptionalArgs(); } |
||
657 | RequiredArgs getRequiredArgs() const { return Required; } |
||
658 | unsigned getNumRequiredArgs() const { |
||
659 | return isVariadic() ? getRequiredArgs().getNumRequiredArgs() : arg_size(); |
||
660 | } |
||
661 | |||
662 | bool isInstanceMethod() const { return InstanceMethod; } |
||
663 | |||
664 | bool isChainCall() const { return ChainCall; } |
||
665 | |||
666 | bool isCmseNSCall() const { return CmseNSCall; } |
||
667 | |||
668 | bool isNoReturn() const { return NoReturn; } |
||
669 | |||
670 | /// In ARC, whether this function retains its return value. This |
||
671 | /// is not always reliable for call sites. |
||
672 | bool isReturnsRetained() const { return ReturnsRetained; } |
||
673 | |||
674 | /// Whether this function no longer saves caller registers. |
||
675 | bool isNoCallerSavedRegs() const { return NoCallerSavedRegs; } |
||
676 | |||
677 | /// Whether this function has nocf_check attribute. |
||
678 | bool isNoCfCheck() const { return NoCfCheck; } |
||
679 | |||
680 | /// getASTCallingConvention() - Return the AST-specified calling |
||
681 | /// convention. |
||
682 | CallingConv getASTCallingConvention() const { |
||
683 | return CallingConv(ASTCallingConvention); |
||
684 | } |
||
685 | |||
686 | /// getCallingConvention - Return the user specified calling |
||
687 | /// convention, which has been translated into an LLVM CC. |
||
688 | unsigned getCallingConvention() const { return CallingConvention; } |
||
689 | |||
690 | /// getEffectiveCallingConvention - Return the actual calling convention to |
||
691 | /// use, which may depend on the ABI. |
||
692 | unsigned getEffectiveCallingConvention() const { |
||
693 | return EffectiveCallingConvention; |
||
694 | } |
||
695 | void setEffectiveCallingConvention(unsigned Value) { |
||
696 | EffectiveCallingConvention = Value; |
||
697 | } |
||
698 | |||
699 | bool getHasRegParm() const { return HasRegParm; } |
||
700 | unsigned getRegParm() const { return RegParm; } |
||
701 | |||
702 | FunctionType::ExtInfo getExtInfo() const { |
||
703 | return FunctionType::ExtInfo(isNoReturn(), getHasRegParm(), getRegParm(), |
||
704 | getASTCallingConvention(), isReturnsRetained(), |
||
705 | isNoCallerSavedRegs(), isNoCfCheck(), |
||
706 | isCmseNSCall()); |
||
707 | } |
||
708 | |||
709 | CanQualType getReturnType() const { return getArgsBuffer()[0].type; } |
||
710 | |||
711 | ABIArgInfo &getReturnInfo() { return getArgsBuffer()[0].info; } |
||
712 | const ABIArgInfo &getReturnInfo() const { return getArgsBuffer()[0].info; } |
||
713 | |||
714 | ArrayRef<ExtParameterInfo> getExtParameterInfos() const { |
||
715 | if (!HasExtParameterInfos) return {}; |
||
716 | return llvm::ArrayRef(getExtParameterInfosBuffer(), NumArgs); |
||
717 | } |
||
718 | ExtParameterInfo getExtParameterInfo(unsigned argIndex) const { |
||
719 | assert(argIndex <= NumArgs); |
||
720 | if (!HasExtParameterInfos) return ExtParameterInfo(); |
||
721 | return getExtParameterInfos()[argIndex]; |
||
722 | } |
||
723 | |||
724 | /// Return true if this function uses inalloca arguments. |
||
725 | bool usesInAlloca() const { return ArgStruct; } |
||
726 | |||
727 | /// Get the struct type used to represent all the arguments in memory. |
||
728 | llvm::StructType *getArgStruct() const { return ArgStruct; } |
||
729 | CharUnits getArgStructAlignment() const { |
||
730 | return CharUnits::fromQuantity(ArgStructAlign); |
||
731 | } |
||
732 | void setArgStruct(llvm::StructType *Ty, CharUnits Align) { |
||
733 | ArgStruct = Ty; |
||
734 | ArgStructAlign = Align.getQuantity(); |
||
735 | } |
||
736 | |||
737 | /// Return the maximum vector width in the arguments. |
||
738 | unsigned getMaxVectorWidth() const { |
||
739 | return MaxVectorWidth ? 1U << (MaxVectorWidth - 1) : 0; |
||
740 | } |
||
741 | |||
742 | /// Set the maximum vector width in the arguments. |
||
743 | void setMaxVectorWidth(unsigned Width) { |
||
744 | assert(llvm::isPowerOf2_32(Width) && "Expected power of 2 vector"); |
||
745 | MaxVectorWidth = llvm::countTrailingZeros(Width) + 1; |
||
746 | } |
||
747 | |||
748 | void Profile(llvm::FoldingSetNodeID &ID) { |
||
749 | ID.AddInteger(getASTCallingConvention()); |
||
750 | ID.AddBoolean(InstanceMethod); |
||
751 | ID.AddBoolean(ChainCall); |
||
752 | ID.AddBoolean(NoReturn); |
||
753 | ID.AddBoolean(ReturnsRetained); |
||
754 | ID.AddBoolean(NoCallerSavedRegs); |
||
755 | ID.AddBoolean(HasRegParm); |
||
756 | ID.AddInteger(RegParm); |
||
757 | ID.AddBoolean(NoCfCheck); |
||
758 | ID.AddBoolean(CmseNSCall); |
||
759 | ID.AddInteger(Required.getOpaqueData()); |
||
760 | ID.AddBoolean(HasExtParameterInfos); |
||
761 | if (HasExtParameterInfos) { |
||
762 | for (auto paramInfo : getExtParameterInfos()) |
||
763 | ID.AddInteger(paramInfo.getOpaqueValue()); |
||
764 | } |
||
765 | getReturnType().Profile(ID); |
||
766 | for (const auto &I : arguments()) |
||
767 | I.type.Profile(ID); |
||
768 | } |
||
769 | static void Profile(llvm::FoldingSetNodeID &ID, |
||
770 | bool InstanceMethod, |
||
771 | bool ChainCall, |
||
772 | const FunctionType::ExtInfo &info, |
||
773 | ArrayRef<ExtParameterInfo> paramInfos, |
||
774 | RequiredArgs required, |
||
775 | CanQualType resultType, |
||
776 | ArrayRef<CanQualType> argTypes) { |
||
777 | ID.AddInteger(info.getCC()); |
||
778 | ID.AddBoolean(InstanceMethod); |
||
779 | ID.AddBoolean(ChainCall); |
||
780 | ID.AddBoolean(info.getNoReturn()); |
||
781 | ID.AddBoolean(info.getProducesResult()); |
||
782 | ID.AddBoolean(info.getNoCallerSavedRegs()); |
||
783 | ID.AddBoolean(info.getHasRegParm()); |
||
784 | ID.AddInteger(info.getRegParm()); |
||
785 | ID.AddBoolean(info.getNoCfCheck()); |
||
786 | ID.AddBoolean(info.getCmseNSCall()); |
||
787 | ID.AddInteger(required.getOpaqueData()); |
||
788 | ID.AddBoolean(!paramInfos.empty()); |
||
789 | if (!paramInfos.empty()) { |
||
790 | for (auto paramInfo : paramInfos) |
||
791 | ID.AddInteger(paramInfo.getOpaqueValue()); |
||
792 | } |
||
793 | resultType.Profile(ID); |
||
794 | for (ArrayRef<CanQualType>::iterator |
||
795 | i = argTypes.begin(), e = argTypes.end(); i != e; ++i) { |
||
796 | i->Profile(ID); |
||
797 | } |
||
798 | } |
||
799 | }; |
||
800 | |||
801 | } // end namespace CodeGen |
||
802 | } // end namespace clang |
||
803 | |||
804 | #endif |