1 | //===- XCore.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 | |
12 | using namespace clang; |
13 | using namespace clang::CodeGen; |
14 | |
15 | //===----------------------------------------------------------------------===// |
16 | // XCore ABI Implementation |
17 | //===----------------------------------------------------------------------===// |
18 | |
19 | namespace { |
20 | |
21 | /// A SmallStringEnc instance is used to build up the TypeString by passing |
22 | /// it by reference between functions that append to it. |
23 | typedef llvm::SmallString<128> SmallStringEnc; |
24 | |
25 | /// TypeStringCache caches the meta encodings of Types. |
26 | /// |
27 | /// The reason for caching TypeStrings is two fold: |
28 | /// 1. To cache a type's encoding for later uses; |
29 | /// 2. As a means to break recursive member type inclusion. |
30 | /// |
31 | /// A cache Entry can have a Status of: |
32 | /// NonRecursive: The type encoding is not recursive; |
33 | /// Recursive: The type encoding is recursive; |
34 | /// Incomplete: An incomplete TypeString; |
35 | /// IncompleteUsed: An incomplete TypeString that has been used in a |
36 | /// Recursive type encoding. |
37 | /// |
38 | /// A NonRecursive entry will have all of its sub-members expanded as fully |
39 | /// as possible. Whilst it may contain types which are recursive, the type |
40 | /// itself is not recursive and thus its encoding may be safely used whenever |
41 | /// the type is encountered. |
42 | /// |
43 | /// A Recursive entry will have all of its sub-members expanded as fully as |
44 | /// possible. The type itself is recursive and it may contain other types which |
45 | /// are recursive. The Recursive encoding must not be used during the expansion |
46 | /// of a recursive type's recursive branch. For simplicity the code uses |
47 | /// IncompleteCount to reject all usage of Recursive encodings for member types. |
48 | /// |
49 | /// An Incomplete entry is always a RecordType and only encodes its |
50 | /// identifier e.g. "s(S){}". Incomplete 'StubEnc' entries are ephemeral and |
51 | /// are placed into the cache during type expansion as a means to identify and |
52 | /// handle recursive inclusion of types as sub-members. If there is recursion |
53 | /// the entry becomes IncompleteUsed. |
54 | /// |
55 | /// During the expansion of a RecordType's members: |
56 | /// |
57 | /// If the cache contains a NonRecursive encoding for the member type, the |
58 | /// cached encoding is used; |
59 | /// |
60 | /// If the cache contains a Recursive encoding for the member type, the |
61 | /// cached encoding is 'Swapped' out, as it may be incorrect, and... |
62 | /// |
63 | /// If the member is a RecordType, an Incomplete encoding is placed into the |
64 | /// cache to break potential recursive inclusion of itself as a sub-member; |
65 | /// |
66 | /// Once a member RecordType has been expanded, its temporary incomplete |
67 | /// entry is removed from the cache. If a Recursive encoding was swapped out |
68 | /// it is swapped back in; |
69 | /// |
70 | /// If an incomplete entry is used to expand a sub-member, the incomplete |
71 | /// entry is marked as IncompleteUsed. The cache keeps count of how many |
72 | /// IncompleteUsed entries it currently contains in IncompleteUsedCount; |
73 | /// |
74 | /// If a member's encoding is found to be a NonRecursive or Recursive viz: |
75 | /// IncompleteUsedCount==0, the member's encoding is added to the cache. |
76 | /// Else the member is part of a recursive type and thus the recursion has |
77 | /// been exited too soon for the encoding to be correct for the member. |
78 | /// |
79 | class TypeStringCache { |
80 | enum Status {NonRecursive, Recursive, Incomplete, IncompleteUsed}; |
81 | struct Entry { |
82 | std::string Str; // The encoded TypeString for the type. |
83 | enum Status State; // Information about the encoding in 'Str'. |
84 | std::string Swapped; // A temporary place holder for a Recursive encoding |
85 | // during the expansion of RecordType's members. |
86 | }; |
87 | std::map<const IdentifierInfo *, struct Entry> Map; |
88 | unsigned IncompleteCount; // Number of Incomplete entries in the Map. |
89 | unsigned IncompleteUsedCount; // Number of IncompleteUsed entries in the Map. |
90 | public: |
91 | TypeStringCache() : IncompleteCount(0), IncompleteUsedCount(0) {} |
92 | void addIncomplete(const IdentifierInfo *ID, std::string StubEnc); |
93 | bool removeIncomplete(const IdentifierInfo *ID); |
94 | void addIfComplete(const IdentifierInfo *ID, StringRef Str, |
95 | bool IsRecursive); |
96 | StringRef lookupStr(const IdentifierInfo *ID); |
97 | }; |
98 | |
99 | /// TypeString encodings for enum & union fields must be order. |
100 | /// FieldEncoding is a helper for this ordering process. |
101 | class FieldEncoding { |
102 | bool HasName; |
103 | std::string Enc; |
104 | public: |
105 | FieldEncoding(bool b, SmallStringEnc &e) : HasName(b), Enc(e.c_str()) {} |
106 | StringRef str() { return Enc; } |
107 | bool operator<(const FieldEncoding &rhs) const { |
108 | if (HasName != rhs.HasName) return HasName; |
109 | return Enc < rhs.Enc; |
110 | } |
111 | }; |
112 | |
113 | class XCoreABIInfo : public DefaultABIInfo { |
114 | public: |
115 | XCoreABIInfo(CodeGen::CodeGenTypes &CGT) : DefaultABIInfo(CGT) {} |
116 | RValue EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty, |
117 | AggValueSlot Slot) const override; |
118 | }; |
119 | |
120 | class XCoreTargetCodeGenInfo : public TargetCodeGenInfo { |
121 | mutable TypeStringCache TSC; |
122 | void emitTargetMD(const Decl *D, llvm::GlobalValue *GV, |
123 | const CodeGen::CodeGenModule &M) const; |
124 | |
125 | public: |
126 | XCoreTargetCodeGenInfo(CodeGenTypes &CGT) |
127 | : TargetCodeGenInfo(std::make_unique<XCoreABIInfo>(args&: CGT)) {} |
128 | void emitTargetMetadata(CodeGen::CodeGenModule &CGM, |
129 | const llvm::MapVector<GlobalDecl, StringRef> |
130 | &MangledDeclNames) const override; |
131 | }; |
132 | |
133 | } // End anonymous namespace. |
134 | |
135 | // TODO: this implementation is likely now redundant with the default |
136 | // EmitVAArg. |
137 | RValue XCoreABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, |
138 | QualType Ty, AggValueSlot Slot) const { |
139 | CGBuilderTy &Builder = CGF.Builder; |
140 | |
141 | // Get the VAList. |
142 | CharUnits SlotSize = CharUnits::fromQuantity(Quantity: 4); |
143 | Address AP = Address(Builder.CreateLoad(Addr: VAListAddr), |
144 | getVAListElementType(CGF), SlotSize); |
145 | |
146 | // Handle the argument. |
147 | ABIArgInfo AI = classifyArgumentType(RetTy: Ty); |
148 | CharUnits TypeAlign = getContext().getTypeAlignInChars(T: Ty); |
149 | llvm::Type *ArgTy = CGT.ConvertType(T: Ty); |
150 | if (AI.canHaveCoerceToType() && !AI.getCoerceToType()) |
151 | AI.setCoerceToType(ArgTy); |
152 | llvm::Type *ArgPtrTy = llvm::PointerType::getUnqual(ElementType: ArgTy); |
153 | |
154 | Address Val = Address::invalid(); |
155 | CharUnits ArgSize = CharUnits::Zero(); |
156 | switch (AI.getKind()) { |
157 | case ABIArgInfo::Expand: |
158 | case ABIArgInfo::CoerceAndExpand: |
159 | case ABIArgInfo::InAlloca: |
160 | llvm_unreachable("Unsupported ABI kind for va_arg" ); |
161 | case ABIArgInfo::Ignore: |
162 | Val = Address(llvm::UndefValue::get(T: ArgPtrTy), ArgTy, TypeAlign); |
163 | ArgSize = CharUnits::Zero(); |
164 | break; |
165 | case ABIArgInfo::Extend: |
166 | case ABIArgInfo::Direct: |
167 | Val = AP.withElementType(ElemTy: ArgTy); |
168 | ArgSize = CharUnits::fromQuantity( |
169 | Quantity: getDataLayout().getTypeAllocSize(Ty: AI.getCoerceToType())); |
170 | ArgSize = ArgSize.alignTo(Align: SlotSize); |
171 | break; |
172 | case ABIArgInfo::Indirect: |
173 | case ABIArgInfo::IndirectAliased: |
174 | Val = AP.withElementType(ElemTy: ArgPtrTy); |
175 | Val = Address(Builder.CreateLoad(Addr: Val), ArgTy, TypeAlign); |
176 | ArgSize = SlotSize; |
177 | break; |
178 | } |
179 | |
180 | // Increment the VAList. |
181 | if (!ArgSize.isZero()) { |
182 | Address APN = Builder.CreateConstInBoundsByteGEP(Addr: AP, Offset: ArgSize); |
183 | Builder.CreateStore(Val: APN.emitRawPointer(CGF), Addr: VAListAddr); |
184 | } |
185 | |
186 | return CGF.EmitLoadOfAnyValue(V: CGF.MakeAddrLValue(Addr: Val, T: Ty), Slot); |
187 | } |
188 | |
189 | /// During the expansion of a RecordType, an incomplete TypeString is placed |
190 | /// into the cache as a means to identify and break recursion. |
191 | /// If there is a Recursive encoding in the cache, it is swapped out and will |
192 | /// be reinserted by removeIncomplete(). |
193 | /// All other types of encoding should have been used rather than arriving here. |
194 | void TypeStringCache::addIncomplete(const IdentifierInfo *ID, |
195 | std::string StubEnc) { |
196 | if (!ID) |
197 | return; |
198 | Entry &E = Map[ID]; |
199 | assert( (E.Str.empty() || E.State == Recursive) && |
200 | "Incorrectly use of addIncomplete" ); |
201 | assert(!StubEnc.empty() && "Passing an empty string to addIncomplete()" ); |
202 | E.Swapped.swap(s&: E.Str); // swap out the Recursive |
203 | E.Str.swap(s&: StubEnc); |
204 | E.State = Incomplete; |
205 | ++IncompleteCount; |
206 | } |
207 | |
208 | /// Once the RecordType has been expanded, the temporary incomplete TypeString |
209 | /// must be removed from the cache. |
210 | /// If a Recursive was swapped out by addIncomplete(), it will be replaced. |
211 | /// Returns true if the RecordType was defined recursively. |
212 | bool TypeStringCache::removeIncomplete(const IdentifierInfo *ID) { |
213 | if (!ID) |
214 | return false; |
215 | auto I = Map.find(x: ID); |
216 | assert(I != Map.end() && "Entry not present" ); |
217 | Entry &E = I->second; |
218 | assert( (E.State == Incomplete || |
219 | E.State == IncompleteUsed) && |
220 | "Entry must be an incomplete type" ); |
221 | bool IsRecursive = false; |
222 | if (E.State == IncompleteUsed) { |
223 | // We made use of our Incomplete encoding, thus we are recursive. |
224 | IsRecursive = true; |
225 | --IncompleteUsedCount; |
226 | } |
227 | if (E.Swapped.empty()) |
228 | Map.erase(position: I); |
229 | else { |
230 | // Swap the Recursive back. |
231 | E.Swapped.swap(s&: E.Str); |
232 | E.Swapped.clear(); |
233 | E.State = Recursive; |
234 | } |
235 | --IncompleteCount; |
236 | return IsRecursive; |
237 | } |
238 | |
239 | /// Add the encoded TypeString to the cache only if it is NonRecursive or |
240 | /// Recursive (viz: all sub-members were expanded as fully as possible). |
241 | void TypeStringCache::addIfComplete(const IdentifierInfo *ID, StringRef Str, |
242 | bool IsRecursive) { |
243 | if (!ID || IncompleteUsedCount) |
244 | return; // No key or it is an incomplete sub-type so don't add. |
245 | Entry &E = Map[ID]; |
246 | if (IsRecursive && !E.Str.empty()) { |
247 | assert(E.State==Recursive && E.Str.size() == Str.size() && |
248 | "This is not the same Recursive entry" ); |
249 | // The parent container was not recursive after all, so we could have used |
250 | // this Recursive sub-member entry after all, but we assumed the worse when |
251 | // we started viz: IncompleteCount!=0. |
252 | return; |
253 | } |
254 | assert(E.Str.empty() && "Entry already present" ); |
255 | E.Str = Str.str(); |
256 | E.State = IsRecursive? Recursive : NonRecursive; |
257 | } |
258 | |
259 | /// Return a cached TypeString encoding for the ID. If there isn't one, or we |
260 | /// are recursively expanding a type (IncompleteCount != 0) and the cached |
261 | /// encoding is Recursive, return an empty StringRef. |
262 | StringRef TypeStringCache::lookupStr(const IdentifierInfo *ID) { |
263 | if (!ID) |
264 | return StringRef(); // We have no key. |
265 | auto I = Map.find(x: ID); |
266 | if (I == Map.end()) |
267 | return StringRef(); // We have no encoding. |
268 | Entry &E = I->second; |
269 | if (E.State == Recursive && IncompleteCount) |
270 | return StringRef(); // We don't use Recursive encodings for member types. |
271 | |
272 | if (E.State == Incomplete) { |
273 | // The incomplete type is being used to break out of recursion. |
274 | E.State = IncompleteUsed; |
275 | ++IncompleteUsedCount; |
276 | } |
277 | return E.Str; |
278 | } |
279 | |
280 | /// The XCore ABI includes a type information section that communicates symbol |
281 | /// type information to the linker. The linker uses this information to verify |
282 | /// safety/correctness of things such as array bound and pointers et al. |
283 | /// The ABI only requires C (and XC) language modules to emit TypeStrings. |
284 | /// This type information (TypeString) is emitted into meta data for all global |
285 | /// symbols: definitions, declarations, functions & variables. |
286 | /// |
287 | /// The TypeString carries type, qualifier, name, size & value details. |
288 | /// Please see 'Tools Development Guide' section 2.16.2 for format details: |
289 | /// https://www.xmos.com/download/public/Tools-Development-Guide%28X9114A%29.pdf |
290 | /// The output is tested by test/CodeGen/xcore-stringtype.c. |
291 | /// |
292 | static bool getTypeString(SmallStringEnc &Enc, const Decl *D, |
293 | const CodeGen::CodeGenModule &CGM, |
294 | TypeStringCache &TSC); |
295 | |
296 | /// XCore uses emitTargetMD to emit TypeString metadata for global symbols. |
297 | void XCoreTargetCodeGenInfo::emitTargetMD( |
298 | const Decl *D, llvm::GlobalValue *GV, |
299 | const CodeGen::CodeGenModule &CGM) const { |
300 | SmallStringEnc Enc; |
301 | if (getTypeString(Enc, D, CGM, TSC)) { |
302 | llvm::LLVMContext &Ctx = CGM.getModule().getContext(); |
303 | llvm::Metadata *MDVals[] = {llvm::ConstantAsMetadata::get(C: GV), |
304 | llvm::MDString::get(Context&: Ctx, Str: Enc.str())}; |
305 | llvm::NamedMDNode *MD = |
306 | CGM.getModule().getOrInsertNamedMetadata(Name: "xcore.typestrings" ); |
307 | MD->addOperand(M: llvm::MDNode::get(Context&: Ctx, MDs: MDVals)); |
308 | } |
309 | } |
310 | |
311 | void XCoreTargetCodeGenInfo::emitTargetMetadata( |
312 | CodeGen::CodeGenModule &CGM, |
313 | const llvm::MapVector<GlobalDecl, StringRef> &MangledDeclNames) const { |
314 | // Warning, new MangledDeclNames may be appended within this loop. |
315 | // We rely on MapVector insertions adding new elements to the end |
316 | // of the container. |
317 | for (unsigned I = 0; I != MangledDeclNames.size(); ++I) { |
318 | auto Val = *(MangledDeclNames.begin() + I); |
319 | llvm::GlobalValue *GV = CGM.GetGlobalValue(Ref: Val.second); |
320 | if (GV) { |
321 | const Decl *D = Val.first.getDecl()->getMostRecentDecl(); |
322 | emitTargetMD(D, GV, CGM); |
323 | } |
324 | } |
325 | } |
326 | |
327 | static bool appendType(SmallStringEnc &Enc, QualType QType, |
328 | const CodeGen::CodeGenModule &CGM, |
329 | TypeStringCache &TSC); |
330 | |
331 | /// Helper function for appendRecordType(). |
332 | /// Builds a SmallVector containing the encoded field types in declaration |
333 | /// order. |
334 | static bool (SmallVectorImpl<FieldEncoding> &FE, |
335 | const RecordDecl *RD, |
336 | const CodeGen::CodeGenModule &CGM, |
337 | TypeStringCache &TSC) { |
338 | for (const auto *Field : RD->fields()) { |
339 | SmallStringEnc Enc; |
340 | Enc += "m(" ; |
341 | Enc += Field->getName(); |
342 | Enc += "){" ; |
343 | if (Field->isBitField()) { |
344 | Enc += "b(" ; |
345 | llvm::raw_svector_ostream OS(Enc); |
346 | OS << Field->getBitWidthValue(Ctx: CGM.getContext()); |
347 | Enc += ':'; |
348 | } |
349 | if (!appendType(Enc, QType: Field->getType(), CGM, TSC)) |
350 | return false; |
351 | if (Field->isBitField()) |
352 | Enc += ')'; |
353 | Enc += '}'; |
354 | FE.emplace_back(Args: !Field->getName().empty(), Args&: Enc); |
355 | } |
356 | return true; |
357 | } |
358 | |
359 | /// Appends structure and union types to Enc and adds encoding to cache. |
360 | /// Recursively calls appendType (via extractFieldType) for each field. |
361 | /// Union types have their fields ordered according to the ABI. |
362 | static bool appendRecordType(SmallStringEnc &Enc, const RecordType *RT, |
363 | const CodeGen::CodeGenModule &CGM, |
364 | TypeStringCache &TSC, const IdentifierInfo *ID) { |
365 | // Append the cached TypeString if we have one. |
366 | StringRef TypeString = TSC.lookupStr(ID); |
367 | if (!TypeString.empty()) { |
368 | Enc += TypeString; |
369 | return true; |
370 | } |
371 | |
372 | // Start to emit an incomplete TypeString. |
373 | size_t Start = Enc.size(); |
374 | Enc += (RT->isUnionType()? 'u' : 's'); |
375 | Enc += '('; |
376 | if (ID) |
377 | Enc += ID->getName(); |
378 | Enc += "){" ; |
379 | |
380 | // We collect all encoded fields and order as necessary. |
381 | bool IsRecursive = false; |
382 | const RecordDecl *RD = RT->getDecl()->getDefinition(); |
383 | if (RD && !RD->field_empty()) { |
384 | // An incomplete TypeString stub is placed in the cache for this RecordType |
385 | // so that recursive calls to this RecordType will use it whilst building a |
386 | // complete TypeString for this RecordType. |
387 | SmallVector<FieldEncoding, 16> FE; |
388 | std::string StubEnc(Enc.substr(Start).str()); |
389 | StubEnc += '}'; // StubEnc now holds a valid incomplete TypeString. |
390 | TSC.addIncomplete(ID, StubEnc: std::move(StubEnc)); |
391 | if (!extractFieldType(FE, RD, CGM, TSC)) { |
392 | (void) TSC.removeIncomplete(ID); |
393 | return false; |
394 | } |
395 | IsRecursive = TSC.removeIncomplete(ID); |
396 | // The ABI requires unions to be sorted but not structures. |
397 | // See FieldEncoding::operator< for sort algorithm. |
398 | if (RT->isUnionType()) |
399 | llvm::sort(C&: FE); |
400 | // We can now complete the TypeString. |
401 | unsigned E = FE.size(); |
402 | for (unsigned I = 0; I != E; ++I) { |
403 | if (I) |
404 | Enc += ','; |
405 | Enc += FE[I].str(); |
406 | } |
407 | } |
408 | Enc += '}'; |
409 | TSC.addIfComplete(ID, Str: Enc.substr(Start), IsRecursive); |
410 | return true; |
411 | } |
412 | |
413 | /// Appends enum types to Enc and adds the encoding to the cache. |
414 | static bool appendEnumType(SmallStringEnc &Enc, const EnumType *ET, |
415 | TypeStringCache &TSC, |
416 | const IdentifierInfo *ID) { |
417 | // Append the cached TypeString if we have one. |
418 | StringRef TypeString = TSC.lookupStr(ID); |
419 | if (!TypeString.empty()) { |
420 | Enc += TypeString; |
421 | return true; |
422 | } |
423 | |
424 | size_t Start = Enc.size(); |
425 | Enc += "e(" ; |
426 | if (ID) |
427 | Enc += ID->getName(); |
428 | Enc += "){" ; |
429 | |
430 | // We collect all encoded enumerations and order them alphanumerically. |
431 | if (const EnumDecl *ED = ET->getDecl()->getDefinition()) { |
432 | SmallVector<FieldEncoding, 16> FE; |
433 | for (auto I = ED->enumerator_begin(), E = ED->enumerator_end(); I != E; |
434 | ++I) { |
435 | SmallStringEnc EnumEnc; |
436 | EnumEnc += "m(" ; |
437 | EnumEnc += I->getName(); |
438 | EnumEnc += "){" ; |
439 | I->getInitVal().toString(Str&: EnumEnc); |
440 | EnumEnc += '}'; |
441 | FE.push_back(Elt: FieldEncoding(!I->getName().empty(), EnumEnc)); |
442 | } |
443 | llvm::sort(C&: FE); |
444 | unsigned E = FE.size(); |
445 | for (unsigned I = 0; I != E; ++I) { |
446 | if (I) |
447 | Enc += ','; |
448 | Enc += FE[I].str(); |
449 | } |
450 | } |
451 | Enc += '}'; |
452 | TSC.addIfComplete(ID, Str: Enc.substr(Start), IsRecursive: false); |
453 | return true; |
454 | } |
455 | |
456 | /// Appends type's qualifier to Enc. |
457 | /// This is done prior to appending the type's encoding. |
458 | static void appendQualifier(SmallStringEnc &Enc, QualType QT) { |
459 | // Qualifiers are emitted in alphabetical order. |
460 | static const char *const Table[]={"" ,"c:" ,"r:" ,"cr:" ,"v:" ,"cv:" ,"rv:" ,"crv:" }; |
461 | int Lookup = 0; |
462 | if (QT.isConstQualified()) |
463 | Lookup += 1<<0; |
464 | if (QT.isRestrictQualified()) |
465 | Lookup += 1<<1; |
466 | if (QT.isVolatileQualified()) |
467 | Lookup += 1<<2; |
468 | Enc += Table[Lookup]; |
469 | } |
470 | |
471 | /// Appends built-in types to Enc. |
472 | static bool appendBuiltinType(SmallStringEnc &Enc, const BuiltinType *BT) { |
473 | const char *EncType; |
474 | switch (BT->getKind()) { |
475 | case BuiltinType::Void: |
476 | EncType = "0" ; |
477 | break; |
478 | case BuiltinType::Bool: |
479 | EncType = "b" ; |
480 | break; |
481 | case BuiltinType::Char_U: |
482 | EncType = "uc" ; |
483 | break; |
484 | case BuiltinType::UChar: |
485 | EncType = "uc" ; |
486 | break; |
487 | case BuiltinType::SChar: |
488 | EncType = "sc" ; |
489 | break; |
490 | case BuiltinType::UShort: |
491 | EncType = "us" ; |
492 | break; |
493 | case BuiltinType::Short: |
494 | EncType = "ss" ; |
495 | break; |
496 | case BuiltinType::UInt: |
497 | EncType = "ui" ; |
498 | break; |
499 | case BuiltinType::Int: |
500 | EncType = "si" ; |
501 | break; |
502 | case BuiltinType::ULong: |
503 | EncType = "ul" ; |
504 | break; |
505 | case BuiltinType::Long: |
506 | EncType = "sl" ; |
507 | break; |
508 | case BuiltinType::ULongLong: |
509 | EncType = "ull" ; |
510 | break; |
511 | case BuiltinType::LongLong: |
512 | EncType = "sll" ; |
513 | break; |
514 | case BuiltinType::Float: |
515 | EncType = "ft" ; |
516 | break; |
517 | case BuiltinType::Double: |
518 | EncType = "d" ; |
519 | break; |
520 | case BuiltinType::LongDouble: |
521 | EncType = "ld" ; |
522 | break; |
523 | default: |
524 | return false; |
525 | } |
526 | Enc += EncType; |
527 | return true; |
528 | } |
529 | |
530 | /// Appends a pointer encoding to Enc before calling appendType for the pointee. |
531 | static bool appendPointerType(SmallStringEnc &Enc, const PointerType *PT, |
532 | const CodeGen::CodeGenModule &CGM, |
533 | TypeStringCache &TSC) { |
534 | Enc += "p(" ; |
535 | if (!appendType(Enc, QType: PT->getPointeeType(), CGM, TSC)) |
536 | return false; |
537 | Enc += ')'; |
538 | return true; |
539 | } |
540 | |
541 | /// Appends array encoding to Enc before calling appendType for the element. |
542 | static bool appendArrayType(SmallStringEnc &Enc, QualType QT, |
543 | const ArrayType *AT, |
544 | const CodeGen::CodeGenModule &CGM, |
545 | TypeStringCache &TSC, StringRef NoSizeEnc) { |
546 | if (AT->getSizeModifier() != ArraySizeModifier::Normal) |
547 | return false; |
548 | Enc += "a(" ; |
549 | if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(Val: AT)) |
550 | CAT->getSize().toStringUnsigned(Str&: Enc); |
551 | else |
552 | Enc += NoSizeEnc; // Global arrays use "*", otherwise it is "". |
553 | Enc += ':'; |
554 | // The Qualifiers should be attached to the type rather than the array. |
555 | appendQualifier(Enc, QT); |
556 | if (!appendType(Enc, QType: AT->getElementType(), CGM, TSC)) |
557 | return false; |
558 | Enc += ')'; |
559 | return true; |
560 | } |
561 | |
562 | /// Appends a function encoding to Enc, calling appendType for the return type |
563 | /// and the arguments. |
564 | static bool appendFunctionType(SmallStringEnc &Enc, const FunctionType *FT, |
565 | const CodeGen::CodeGenModule &CGM, |
566 | TypeStringCache &TSC) { |
567 | Enc += "f{" ; |
568 | if (!appendType(Enc, QType: FT->getReturnType(), CGM, TSC)) |
569 | return false; |
570 | Enc += "}(" ; |
571 | if (const FunctionProtoType *FPT = FT->getAs<FunctionProtoType>()) { |
572 | // N.B. we are only interested in the adjusted param types. |
573 | auto I = FPT->param_type_begin(); |
574 | auto E = FPT->param_type_end(); |
575 | if (I != E) { |
576 | do { |
577 | if (!appendType(Enc, QType: *I, CGM, TSC)) |
578 | return false; |
579 | ++I; |
580 | if (I != E) |
581 | Enc += ','; |
582 | } while (I != E); |
583 | if (FPT->isVariadic()) |
584 | Enc += ",va" ; |
585 | } else { |
586 | if (FPT->isVariadic()) |
587 | Enc += "va" ; |
588 | else |
589 | Enc += '0'; |
590 | } |
591 | } |
592 | Enc += ')'; |
593 | return true; |
594 | } |
595 | |
596 | /// Handles the type's qualifier before dispatching a call to handle specific |
597 | /// type encodings. |
598 | static bool appendType(SmallStringEnc &Enc, QualType QType, |
599 | const CodeGen::CodeGenModule &CGM, |
600 | TypeStringCache &TSC) { |
601 | |
602 | QualType QT = QType.getCanonicalType(); |
603 | |
604 | if (const ArrayType *AT = QT->getAsArrayTypeUnsafe()) |
605 | // The Qualifiers should be attached to the type rather than the array. |
606 | // Thus we don't call appendQualifier() here. |
607 | return appendArrayType(Enc, QT, AT, CGM, TSC, NoSizeEnc: "" ); |
608 | |
609 | appendQualifier(Enc, QT); |
610 | |
611 | if (const BuiltinType *BT = QT->getAs<BuiltinType>()) |
612 | return appendBuiltinType(Enc, BT); |
613 | |
614 | if (const PointerType *PT = QT->getAs<PointerType>()) |
615 | return appendPointerType(Enc, PT, CGM, TSC); |
616 | |
617 | if (const EnumType *ET = QT->getAs<EnumType>()) |
618 | return appendEnumType(Enc, ET, TSC, ID: QT.getBaseTypeIdentifier()); |
619 | |
620 | if (const RecordType *RT = QT->getAsStructureType()) |
621 | return appendRecordType(Enc, RT, CGM, TSC, ID: QT.getBaseTypeIdentifier()); |
622 | |
623 | if (const RecordType *RT = QT->getAsUnionType()) |
624 | return appendRecordType(Enc, RT, CGM, TSC, ID: QT.getBaseTypeIdentifier()); |
625 | |
626 | if (const FunctionType *FT = QT->getAs<FunctionType>()) |
627 | return appendFunctionType(Enc, FT, CGM, TSC); |
628 | |
629 | return false; |
630 | } |
631 | |
632 | static bool getTypeString(SmallStringEnc &Enc, const Decl *D, |
633 | const CodeGen::CodeGenModule &CGM, |
634 | TypeStringCache &TSC) { |
635 | if (!D) |
636 | return false; |
637 | |
638 | if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(Val: D)) { |
639 | if (FD->getLanguageLinkage() != CLanguageLinkage) |
640 | return false; |
641 | return appendType(Enc, QType: FD->getType(), CGM, TSC); |
642 | } |
643 | |
644 | if (const VarDecl *VD = dyn_cast<VarDecl>(Val: D)) { |
645 | if (VD->getLanguageLinkage() != CLanguageLinkage) |
646 | return false; |
647 | QualType QT = VD->getType().getCanonicalType(); |
648 | if (const ArrayType *AT = QT->getAsArrayTypeUnsafe()) { |
649 | // Global ArrayTypes are given a size of '*' if the size is unknown. |
650 | // The Qualifiers should be attached to the type rather than the array. |
651 | // Thus we don't call appendQualifier() here. |
652 | return appendArrayType(Enc, QT, AT, CGM, TSC, NoSizeEnc: "*" ); |
653 | } |
654 | return appendType(Enc, QType: QT, CGM, TSC); |
655 | } |
656 | return false; |
657 | } |
658 | |
659 | std::unique_ptr<TargetCodeGenInfo> |
660 | CodeGen::createXCoreTargetCodeGenInfo(CodeGenModule &CGM) { |
661 | return std::make_unique<XCoreTargetCodeGenInfo>(args&: CGM.getTypes()); |
662 | } |
663 | |