xref: /freebsd-src/contrib/llvm-project/clang/lib/CodeGen/Targets/XCore.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
106c3fb27SDimitry Andric //===- XCore.cpp ----------------------------------------------------------===//
206c3fb27SDimitry Andric //
306c3fb27SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
406c3fb27SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
506c3fb27SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
606c3fb27SDimitry Andric //
706c3fb27SDimitry Andric //===----------------------------------------------------------------------===//
806c3fb27SDimitry Andric 
906c3fb27SDimitry Andric #include "ABIInfoImpl.h"
1006c3fb27SDimitry Andric #include "TargetInfo.h"
1106c3fb27SDimitry Andric 
1206c3fb27SDimitry Andric using namespace clang;
1306c3fb27SDimitry Andric using namespace clang::CodeGen;
1406c3fb27SDimitry Andric 
1506c3fb27SDimitry Andric //===----------------------------------------------------------------------===//
1606c3fb27SDimitry Andric // XCore ABI Implementation
1706c3fb27SDimitry Andric //===----------------------------------------------------------------------===//
1806c3fb27SDimitry Andric 
1906c3fb27SDimitry Andric namespace {
2006c3fb27SDimitry Andric 
2106c3fb27SDimitry Andric /// A SmallStringEnc instance is used to build up the TypeString by passing
2206c3fb27SDimitry Andric /// it by reference between functions that append to it.
2306c3fb27SDimitry Andric typedef llvm::SmallString<128> SmallStringEnc;
2406c3fb27SDimitry Andric 
2506c3fb27SDimitry Andric /// TypeStringCache caches the meta encodings of Types.
2606c3fb27SDimitry Andric ///
2706c3fb27SDimitry Andric /// The reason for caching TypeStrings is two fold:
2806c3fb27SDimitry Andric ///   1. To cache a type's encoding for later uses;
2906c3fb27SDimitry Andric ///   2. As a means to break recursive member type inclusion.
3006c3fb27SDimitry Andric ///
3106c3fb27SDimitry Andric /// A cache Entry can have a Status of:
3206c3fb27SDimitry Andric ///   NonRecursive:   The type encoding is not recursive;
3306c3fb27SDimitry Andric ///   Recursive:      The type encoding is recursive;
3406c3fb27SDimitry Andric ///   Incomplete:     An incomplete TypeString;
3506c3fb27SDimitry Andric ///   IncompleteUsed: An incomplete TypeString that has been used in a
3606c3fb27SDimitry Andric ///                   Recursive type encoding.
3706c3fb27SDimitry Andric ///
3806c3fb27SDimitry Andric /// A NonRecursive entry will have all of its sub-members expanded as fully
3906c3fb27SDimitry Andric /// as possible. Whilst it may contain types which are recursive, the type
4006c3fb27SDimitry Andric /// itself is not recursive and thus its encoding may be safely used whenever
4106c3fb27SDimitry Andric /// the type is encountered.
4206c3fb27SDimitry Andric ///
4306c3fb27SDimitry Andric /// A Recursive entry will have all of its sub-members expanded as fully as
4406c3fb27SDimitry Andric /// possible. The type itself is recursive and it may contain other types which
4506c3fb27SDimitry Andric /// are recursive. The Recursive encoding must not be used during the expansion
4606c3fb27SDimitry Andric /// of a recursive type's recursive branch. For simplicity the code uses
4706c3fb27SDimitry Andric /// IncompleteCount to reject all usage of Recursive encodings for member types.
4806c3fb27SDimitry Andric ///
4906c3fb27SDimitry Andric /// An Incomplete entry is always a RecordType and only encodes its
5006c3fb27SDimitry Andric /// identifier e.g. "s(S){}". Incomplete 'StubEnc' entries are ephemeral and
5106c3fb27SDimitry Andric /// are placed into the cache during type expansion as a means to identify and
5206c3fb27SDimitry Andric /// handle recursive inclusion of types as sub-members. If there is recursion
5306c3fb27SDimitry Andric /// the entry becomes IncompleteUsed.
5406c3fb27SDimitry Andric ///
5506c3fb27SDimitry Andric /// During the expansion of a RecordType's members:
5606c3fb27SDimitry Andric ///
5706c3fb27SDimitry Andric ///   If the cache contains a NonRecursive encoding for the member type, the
5806c3fb27SDimitry Andric ///   cached encoding is used;
5906c3fb27SDimitry Andric ///
6006c3fb27SDimitry Andric ///   If the cache contains a Recursive encoding for the member type, the
6106c3fb27SDimitry Andric ///   cached encoding is 'Swapped' out, as it may be incorrect, and...
6206c3fb27SDimitry Andric ///
6306c3fb27SDimitry Andric ///   If the member is a RecordType, an Incomplete encoding is placed into the
6406c3fb27SDimitry Andric ///   cache to break potential recursive inclusion of itself as a sub-member;
6506c3fb27SDimitry Andric ///
6606c3fb27SDimitry Andric ///   Once a member RecordType has been expanded, its temporary incomplete
6706c3fb27SDimitry Andric ///   entry is removed from the cache. If a Recursive encoding was swapped out
6806c3fb27SDimitry Andric ///   it is swapped back in;
6906c3fb27SDimitry Andric ///
7006c3fb27SDimitry Andric ///   If an incomplete entry is used to expand a sub-member, the incomplete
7106c3fb27SDimitry Andric ///   entry is marked as IncompleteUsed. The cache keeps count of how many
7206c3fb27SDimitry Andric ///   IncompleteUsed entries it currently contains in IncompleteUsedCount;
7306c3fb27SDimitry Andric ///
7406c3fb27SDimitry Andric ///   If a member's encoding is found to be a NonRecursive or Recursive viz:
7506c3fb27SDimitry Andric ///   IncompleteUsedCount==0, the member's encoding is added to the cache.
7606c3fb27SDimitry Andric ///   Else the member is part of a recursive type and thus the recursion has
7706c3fb27SDimitry Andric ///   been exited too soon for the encoding to be correct for the member.
7806c3fb27SDimitry Andric ///
7906c3fb27SDimitry Andric class TypeStringCache {
8006c3fb27SDimitry Andric   enum Status {NonRecursive, Recursive, Incomplete, IncompleteUsed};
8106c3fb27SDimitry Andric   struct Entry {
8206c3fb27SDimitry Andric     std::string Str;     // The encoded TypeString for the type.
8306c3fb27SDimitry Andric     enum Status State;   // Information about the encoding in 'Str'.
8406c3fb27SDimitry Andric     std::string Swapped; // A temporary place holder for a Recursive encoding
8506c3fb27SDimitry Andric                          // during the expansion of RecordType's members.
8606c3fb27SDimitry Andric   };
8706c3fb27SDimitry Andric   std::map<const IdentifierInfo *, struct Entry> Map;
8806c3fb27SDimitry Andric   unsigned IncompleteCount;     // Number of Incomplete entries in the Map.
8906c3fb27SDimitry Andric   unsigned IncompleteUsedCount; // Number of IncompleteUsed entries in the Map.
9006c3fb27SDimitry Andric public:
9106c3fb27SDimitry Andric   TypeStringCache() : IncompleteCount(0), IncompleteUsedCount(0) {}
9206c3fb27SDimitry Andric   void addIncomplete(const IdentifierInfo *ID, std::string StubEnc);
9306c3fb27SDimitry Andric   bool removeIncomplete(const IdentifierInfo *ID);
9406c3fb27SDimitry Andric   void addIfComplete(const IdentifierInfo *ID, StringRef Str,
9506c3fb27SDimitry Andric                      bool IsRecursive);
9606c3fb27SDimitry Andric   StringRef lookupStr(const IdentifierInfo *ID);
9706c3fb27SDimitry Andric };
9806c3fb27SDimitry Andric 
9906c3fb27SDimitry Andric /// TypeString encodings for enum & union fields must be order.
10006c3fb27SDimitry Andric /// FieldEncoding is a helper for this ordering process.
10106c3fb27SDimitry Andric class FieldEncoding {
10206c3fb27SDimitry Andric   bool HasName;
10306c3fb27SDimitry Andric   std::string Enc;
10406c3fb27SDimitry Andric public:
10506c3fb27SDimitry Andric   FieldEncoding(bool b, SmallStringEnc &e) : HasName(b), Enc(e.c_str()) {}
10606c3fb27SDimitry Andric   StringRef str() { return Enc; }
10706c3fb27SDimitry Andric   bool operator<(const FieldEncoding &rhs) const {
10806c3fb27SDimitry Andric     if (HasName != rhs.HasName) return HasName;
10906c3fb27SDimitry Andric     return Enc < rhs.Enc;
11006c3fb27SDimitry Andric   }
11106c3fb27SDimitry Andric };
11206c3fb27SDimitry Andric 
11306c3fb27SDimitry Andric class XCoreABIInfo : public DefaultABIInfo {
11406c3fb27SDimitry Andric public:
11506c3fb27SDimitry Andric   XCoreABIInfo(CodeGen::CodeGenTypes &CGT) : DefaultABIInfo(CGT) {}
116*0fca6ea1SDimitry Andric   RValue EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty,
117*0fca6ea1SDimitry Andric                    AggValueSlot Slot) const override;
11806c3fb27SDimitry Andric };
11906c3fb27SDimitry Andric 
12006c3fb27SDimitry Andric class XCoreTargetCodeGenInfo : public TargetCodeGenInfo {
12106c3fb27SDimitry Andric   mutable TypeStringCache TSC;
12206c3fb27SDimitry Andric   void emitTargetMD(const Decl *D, llvm::GlobalValue *GV,
12306c3fb27SDimitry Andric                     const CodeGen::CodeGenModule &M) const;
12406c3fb27SDimitry Andric 
12506c3fb27SDimitry Andric public:
12606c3fb27SDimitry Andric   XCoreTargetCodeGenInfo(CodeGenTypes &CGT)
12706c3fb27SDimitry Andric       : TargetCodeGenInfo(std::make_unique<XCoreABIInfo>(CGT)) {}
12806c3fb27SDimitry Andric   void emitTargetMetadata(CodeGen::CodeGenModule &CGM,
12906c3fb27SDimitry Andric                           const llvm::MapVector<GlobalDecl, StringRef>
13006c3fb27SDimitry Andric                               &MangledDeclNames) const override;
13106c3fb27SDimitry Andric };
13206c3fb27SDimitry Andric 
13306c3fb27SDimitry Andric } // End anonymous namespace.
13406c3fb27SDimitry Andric 
13506c3fb27SDimitry Andric // TODO: this implementation is likely now redundant with the default
13606c3fb27SDimitry Andric // EmitVAArg.
137*0fca6ea1SDimitry Andric RValue XCoreABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
138*0fca6ea1SDimitry Andric                                QualType Ty, AggValueSlot Slot) const {
13906c3fb27SDimitry Andric   CGBuilderTy &Builder = CGF.Builder;
14006c3fb27SDimitry Andric 
14106c3fb27SDimitry Andric   // Get the VAList.
14206c3fb27SDimitry Andric   CharUnits SlotSize = CharUnits::fromQuantity(4);
14306c3fb27SDimitry Andric   Address AP = Address(Builder.CreateLoad(VAListAddr),
14406c3fb27SDimitry Andric                        getVAListElementType(CGF), SlotSize);
14506c3fb27SDimitry Andric 
14606c3fb27SDimitry Andric   // Handle the argument.
14706c3fb27SDimitry Andric   ABIArgInfo AI = classifyArgumentType(Ty);
14806c3fb27SDimitry Andric   CharUnits TypeAlign = getContext().getTypeAlignInChars(Ty);
14906c3fb27SDimitry Andric   llvm::Type *ArgTy = CGT.ConvertType(Ty);
15006c3fb27SDimitry Andric   if (AI.canHaveCoerceToType() && !AI.getCoerceToType())
15106c3fb27SDimitry Andric     AI.setCoerceToType(ArgTy);
15206c3fb27SDimitry Andric   llvm::Type *ArgPtrTy = llvm::PointerType::getUnqual(ArgTy);
15306c3fb27SDimitry Andric 
15406c3fb27SDimitry Andric   Address Val = Address::invalid();
15506c3fb27SDimitry Andric   CharUnits ArgSize = CharUnits::Zero();
15606c3fb27SDimitry Andric   switch (AI.getKind()) {
15706c3fb27SDimitry Andric   case ABIArgInfo::Expand:
15806c3fb27SDimitry Andric   case ABIArgInfo::CoerceAndExpand:
15906c3fb27SDimitry Andric   case ABIArgInfo::InAlloca:
16006c3fb27SDimitry Andric     llvm_unreachable("Unsupported ABI kind for va_arg");
16106c3fb27SDimitry Andric   case ABIArgInfo::Ignore:
16206c3fb27SDimitry Andric     Val = Address(llvm::UndefValue::get(ArgPtrTy), ArgTy, TypeAlign);
16306c3fb27SDimitry Andric     ArgSize = CharUnits::Zero();
16406c3fb27SDimitry Andric     break;
16506c3fb27SDimitry Andric   case ABIArgInfo::Extend:
16606c3fb27SDimitry Andric   case ABIArgInfo::Direct:
16706c3fb27SDimitry Andric     Val = AP.withElementType(ArgTy);
16806c3fb27SDimitry Andric     ArgSize = CharUnits::fromQuantity(
16906c3fb27SDimitry Andric         getDataLayout().getTypeAllocSize(AI.getCoerceToType()));
17006c3fb27SDimitry Andric     ArgSize = ArgSize.alignTo(SlotSize);
17106c3fb27SDimitry Andric     break;
17206c3fb27SDimitry Andric   case ABIArgInfo::Indirect:
17306c3fb27SDimitry Andric   case ABIArgInfo::IndirectAliased:
17406c3fb27SDimitry Andric     Val = AP.withElementType(ArgPtrTy);
17506c3fb27SDimitry Andric     Val = Address(Builder.CreateLoad(Val), ArgTy, TypeAlign);
17606c3fb27SDimitry Andric     ArgSize = SlotSize;
17706c3fb27SDimitry Andric     break;
17806c3fb27SDimitry Andric   }
17906c3fb27SDimitry Andric 
18006c3fb27SDimitry Andric   // Increment the VAList.
18106c3fb27SDimitry Andric   if (!ArgSize.isZero()) {
18206c3fb27SDimitry Andric     Address APN = Builder.CreateConstInBoundsByteGEP(AP, ArgSize);
183*0fca6ea1SDimitry Andric     Builder.CreateStore(APN.emitRawPointer(CGF), VAListAddr);
18406c3fb27SDimitry Andric   }
18506c3fb27SDimitry Andric 
186*0fca6ea1SDimitry Andric   return CGF.EmitLoadOfAnyValue(CGF.MakeAddrLValue(Val, Ty), Slot);
18706c3fb27SDimitry Andric }
18806c3fb27SDimitry Andric 
18906c3fb27SDimitry Andric /// During the expansion of a RecordType, an incomplete TypeString is placed
19006c3fb27SDimitry Andric /// into the cache as a means to identify and break recursion.
19106c3fb27SDimitry Andric /// If there is a Recursive encoding in the cache, it is swapped out and will
19206c3fb27SDimitry Andric /// be reinserted by removeIncomplete().
19306c3fb27SDimitry Andric /// All other types of encoding should have been used rather than arriving here.
19406c3fb27SDimitry Andric void TypeStringCache::addIncomplete(const IdentifierInfo *ID,
19506c3fb27SDimitry Andric                                     std::string StubEnc) {
19606c3fb27SDimitry Andric   if (!ID)
19706c3fb27SDimitry Andric     return;
19806c3fb27SDimitry Andric   Entry &E = Map[ID];
19906c3fb27SDimitry Andric   assert( (E.Str.empty() || E.State == Recursive) &&
20006c3fb27SDimitry Andric          "Incorrectly use of addIncomplete");
20106c3fb27SDimitry Andric   assert(!StubEnc.empty() && "Passing an empty string to addIncomplete()");
20206c3fb27SDimitry Andric   E.Swapped.swap(E.Str); // swap out the Recursive
20306c3fb27SDimitry Andric   E.Str.swap(StubEnc);
20406c3fb27SDimitry Andric   E.State = Incomplete;
20506c3fb27SDimitry Andric   ++IncompleteCount;
20606c3fb27SDimitry Andric }
20706c3fb27SDimitry Andric 
20806c3fb27SDimitry Andric /// Once the RecordType has been expanded, the temporary incomplete TypeString
20906c3fb27SDimitry Andric /// must be removed from the cache.
21006c3fb27SDimitry Andric /// If a Recursive was swapped out by addIncomplete(), it will be replaced.
21106c3fb27SDimitry Andric /// Returns true if the RecordType was defined recursively.
21206c3fb27SDimitry Andric bool TypeStringCache::removeIncomplete(const IdentifierInfo *ID) {
21306c3fb27SDimitry Andric   if (!ID)
21406c3fb27SDimitry Andric     return false;
21506c3fb27SDimitry Andric   auto I = Map.find(ID);
21606c3fb27SDimitry Andric   assert(I != Map.end() && "Entry not present");
21706c3fb27SDimitry Andric   Entry &E = I->second;
21806c3fb27SDimitry Andric   assert( (E.State == Incomplete ||
21906c3fb27SDimitry Andric            E.State == IncompleteUsed) &&
22006c3fb27SDimitry Andric          "Entry must be an incomplete type");
22106c3fb27SDimitry Andric   bool IsRecursive = false;
22206c3fb27SDimitry Andric   if (E.State == IncompleteUsed) {
22306c3fb27SDimitry Andric     // We made use of our Incomplete encoding, thus we are recursive.
22406c3fb27SDimitry Andric     IsRecursive = true;
22506c3fb27SDimitry Andric     --IncompleteUsedCount;
22606c3fb27SDimitry Andric   }
22706c3fb27SDimitry Andric   if (E.Swapped.empty())
22806c3fb27SDimitry Andric     Map.erase(I);
22906c3fb27SDimitry Andric   else {
23006c3fb27SDimitry Andric     // Swap the Recursive back.
23106c3fb27SDimitry Andric     E.Swapped.swap(E.Str);
23206c3fb27SDimitry Andric     E.Swapped.clear();
23306c3fb27SDimitry Andric     E.State = Recursive;
23406c3fb27SDimitry Andric   }
23506c3fb27SDimitry Andric   --IncompleteCount;
23606c3fb27SDimitry Andric   return IsRecursive;
23706c3fb27SDimitry Andric }
23806c3fb27SDimitry Andric 
23906c3fb27SDimitry Andric /// Add the encoded TypeString to the cache only if it is NonRecursive or
24006c3fb27SDimitry Andric /// Recursive (viz: all sub-members were expanded as fully as possible).
24106c3fb27SDimitry Andric void TypeStringCache::addIfComplete(const IdentifierInfo *ID, StringRef Str,
24206c3fb27SDimitry Andric                                     bool IsRecursive) {
24306c3fb27SDimitry Andric   if (!ID || IncompleteUsedCount)
24406c3fb27SDimitry Andric     return; // No key or it is an incomplete sub-type so don't add.
24506c3fb27SDimitry Andric   Entry &E = Map[ID];
24606c3fb27SDimitry Andric   if (IsRecursive && !E.Str.empty()) {
24706c3fb27SDimitry Andric     assert(E.State==Recursive && E.Str.size() == Str.size() &&
24806c3fb27SDimitry Andric            "This is not the same Recursive entry");
24906c3fb27SDimitry Andric     // The parent container was not recursive after all, so we could have used
25006c3fb27SDimitry Andric     // this Recursive sub-member entry after all, but we assumed the worse when
25106c3fb27SDimitry Andric     // we started viz: IncompleteCount!=0.
25206c3fb27SDimitry Andric     return;
25306c3fb27SDimitry Andric   }
25406c3fb27SDimitry Andric   assert(E.Str.empty() && "Entry already present");
25506c3fb27SDimitry Andric   E.Str = Str.str();
25606c3fb27SDimitry Andric   E.State = IsRecursive? Recursive : NonRecursive;
25706c3fb27SDimitry Andric }
25806c3fb27SDimitry Andric 
25906c3fb27SDimitry Andric /// Return a cached TypeString encoding for the ID. If there isn't one, or we
26006c3fb27SDimitry Andric /// are recursively expanding a type (IncompleteCount != 0) and the cached
26106c3fb27SDimitry Andric /// encoding is Recursive, return an empty StringRef.
26206c3fb27SDimitry Andric StringRef TypeStringCache::lookupStr(const IdentifierInfo *ID) {
26306c3fb27SDimitry Andric   if (!ID)
26406c3fb27SDimitry Andric     return StringRef();   // We have no key.
26506c3fb27SDimitry Andric   auto I = Map.find(ID);
26606c3fb27SDimitry Andric   if (I == Map.end())
26706c3fb27SDimitry Andric     return StringRef();   // We have no encoding.
26806c3fb27SDimitry Andric   Entry &E = I->second;
26906c3fb27SDimitry Andric   if (E.State == Recursive && IncompleteCount)
27006c3fb27SDimitry Andric     return StringRef();   // We don't use Recursive encodings for member types.
27106c3fb27SDimitry Andric 
27206c3fb27SDimitry Andric   if (E.State == Incomplete) {
27306c3fb27SDimitry Andric     // The incomplete type is being used to break out of recursion.
27406c3fb27SDimitry Andric     E.State = IncompleteUsed;
27506c3fb27SDimitry Andric     ++IncompleteUsedCount;
27606c3fb27SDimitry Andric   }
27706c3fb27SDimitry Andric   return E.Str;
27806c3fb27SDimitry Andric }
27906c3fb27SDimitry Andric 
28006c3fb27SDimitry Andric /// The XCore ABI includes a type information section that communicates symbol
28106c3fb27SDimitry Andric /// type information to the linker. The linker uses this information to verify
28206c3fb27SDimitry Andric /// safety/correctness of things such as array bound and pointers et al.
28306c3fb27SDimitry Andric /// The ABI only requires C (and XC) language modules to emit TypeStrings.
28406c3fb27SDimitry Andric /// This type information (TypeString) is emitted into meta data for all global
28506c3fb27SDimitry Andric /// symbols: definitions, declarations, functions & variables.
28606c3fb27SDimitry Andric ///
28706c3fb27SDimitry Andric /// The TypeString carries type, qualifier, name, size & value details.
28806c3fb27SDimitry Andric /// Please see 'Tools Development Guide' section 2.16.2 for format details:
28906c3fb27SDimitry Andric /// https://www.xmos.com/download/public/Tools-Development-Guide%28X9114A%29.pdf
29006c3fb27SDimitry Andric /// The output is tested by test/CodeGen/xcore-stringtype.c.
29106c3fb27SDimitry Andric ///
29206c3fb27SDimitry Andric static bool getTypeString(SmallStringEnc &Enc, const Decl *D,
29306c3fb27SDimitry Andric                           const CodeGen::CodeGenModule &CGM,
29406c3fb27SDimitry Andric                           TypeStringCache &TSC);
29506c3fb27SDimitry Andric 
29606c3fb27SDimitry Andric /// XCore uses emitTargetMD to emit TypeString metadata for global symbols.
29706c3fb27SDimitry Andric void XCoreTargetCodeGenInfo::emitTargetMD(
29806c3fb27SDimitry Andric     const Decl *D, llvm::GlobalValue *GV,
29906c3fb27SDimitry Andric     const CodeGen::CodeGenModule &CGM) const {
30006c3fb27SDimitry Andric   SmallStringEnc Enc;
30106c3fb27SDimitry Andric   if (getTypeString(Enc, D, CGM, TSC)) {
30206c3fb27SDimitry Andric     llvm::LLVMContext &Ctx = CGM.getModule().getContext();
30306c3fb27SDimitry Andric     llvm::Metadata *MDVals[] = {llvm::ConstantAsMetadata::get(GV),
30406c3fb27SDimitry Andric                                 llvm::MDString::get(Ctx, Enc.str())};
30506c3fb27SDimitry Andric     llvm::NamedMDNode *MD =
30606c3fb27SDimitry Andric       CGM.getModule().getOrInsertNamedMetadata("xcore.typestrings");
30706c3fb27SDimitry Andric     MD->addOperand(llvm::MDNode::get(Ctx, MDVals));
30806c3fb27SDimitry Andric   }
30906c3fb27SDimitry Andric }
31006c3fb27SDimitry Andric 
31106c3fb27SDimitry Andric void XCoreTargetCodeGenInfo::emitTargetMetadata(
31206c3fb27SDimitry Andric     CodeGen::CodeGenModule &CGM,
31306c3fb27SDimitry Andric     const llvm::MapVector<GlobalDecl, StringRef> &MangledDeclNames) const {
31406c3fb27SDimitry Andric   // Warning, new MangledDeclNames may be appended within this loop.
31506c3fb27SDimitry Andric   // We rely on MapVector insertions adding new elements to the end
31606c3fb27SDimitry Andric   // of the container.
31706c3fb27SDimitry Andric   for (unsigned I = 0; I != MangledDeclNames.size(); ++I) {
31806c3fb27SDimitry Andric     auto Val = *(MangledDeclNames.begin() + I);
31906c3fb27SDimitry Andric     llvm::GlobalValue *GV = CGM.GetGlobalValue(Val.second);
32006c3fb27SDimitry Andric     if (GV) {
32106c3fb27SDimitry Andric       const Decl *D = Val.first.getDecl()->getMostRecentDecl();
32206c3fb27SDimitry Andric       emitTargetMD(D, GV, CGM);
32306c3fb27SDimitry Andric     }
32406c3fb27SDimitry Andric   }
32506c3fb27SDimitry Andric }
32606c3fb27SDimitry Andric 
32706c3fb27SDimitry Andric static bool appendType(SmallStringEnc &Enc, QualType QType,
32806c3fb27SDimitry Andric                        const CodeGen::CodeGenModule &CGM,
32906c3fb27SDimitry Andric                        TypeStringCache &TSC);
33006c3fb27SDimitry Andric 
33106c3fb27SDimitry Andric /// Helper function for appendRecordType().
33206c3fb27SDimitry Andric /// Builds a SmallVector containing the encoded field types in declaration
33306c3fb27SDimitry Andric /// order.
33406c3fb27SDimitry Andric static bool extractFieldType(SmallVectorImpl<FieldEncoding> &FE,
33506c3fb27SDimitry Andric                              const RecordDecl *RD,
33606c3fb27SDimitry Andric                              const CodeGen::CodeGenModule &CGM,
33706c3fb27SDimitry Andric                              TypeStringCache &TSC) {
33806c3fb27SDimitry Andric   for (const auto *Field : RD->fields()) {
33906c3fb27SDimitry Andric     SmallStringEnc Enc;
34006c3fb27SDimitry Andric     Enc += "m(";
34106c3fb27SDimitry Andric     Enc += Field->getName();
34206c3fb27SDimitry Andric     Enc += "){";
34306c3fb27SDimitry Andric     if (Field->isBitField()) {
34406c3fb27SDimitry Andric       Enc += "b(";
34506c3fb27SDimitry Andric       llvm::raw_svector_ostream OS(Enc);
34606c3fb27SDimitry Andric       OS << Field->getBitWidthValue(CGM.getContext());
34706c3fb27SDimitry Andric       Enc += ':';
34806c3fb27SDimitry Andric     }
34906c3fb27SDimitry Andric     if (!appendType(Enc, Field->getType(), CGM, TSC))
35006c3fb27SDimitry Andric       return false;
35106c3fb27SDimitry Andric     if (Field->isBitField())
35206c3fb27SDimitry Andric       Enc += ')';
35306c3fb27SDimitry Andric     Enc += '}';
35406c3fb27SDimitry Andric     FE.emplace_back(!Field->getName().empty(), Enc);
35506c3fb27SDimitry Andric   }
35606c3fb27SDimitry Andric   return true;
35706c3fb27SDimitry Andric }
35806c3fb27SDimitry Andric 
35906c3fb27SDimitry Andric /// Appends structure and union types to Enc and adds encoding to cache.
36006c3fb27SDimitry Andric /// Recursively calls appendType (via extractFieldType) for each field.
36106c3fb27SDimitry Andric /// Union types have their fields ordered according to the ABI.
36206c3fb27SDimitry Andric static bool appendRecordType(SmallStringEnc &Enc, const RecordType *RT,
36306c3fb27SDimitry Andric                              const CodeGen::CodeGenModule &CGM,
36406c3fb27SDimitry Andric                              TypeStringCache &TSC, const IdentifierInfo *ID) {
36506c3fb27SDimitry Andric   // Append the cached TypeString if we have one.
36606c3fb27SDimitry Andric   StringRef TypeString = TSC.lookupStr(ID);
36706c3fb27SDimitry Andric   if (!TypeString.empty()) {
36806c3fb27SDimitry Andric     Enc += TypeString;
36906c3fb27SDimitry Andric     return true;
37006c3fb27SDimitry Andric   }
37106c3fb27SDimitry Andric 
37206c3fb27SDimitry Andric   // Start to emit an incomplete TypeString.
37306c3fb27SDimitry Andric   size_t Start = Enc.size();
37406c3fb27SDimitry Andric   Enc += (RT->isUnionType()? 'u' : 's');
37506c3fb27SDimitry Andric   Enc += '(';
37606c3fb27SDimitry Andric   if (ID)
37706c3fb27SDimitry Andric     Enc += ID->getName();
37806c3fb27SDimitry Andric   Enc += "){";
37906c3fb27SDimitry Andric 
38006c3fb27SDimitry Andric   // We collect all encoded fields and order as necessary.
38106c3fb27SDimitry Andric   bool IsRecursive = false;
38206c3fb27SDimitry Andric   const RecordDecl *RD = RT->getDecl()->getDefinition();
38306c3fb27SDimitry Andric   if (RD && !RD->field_empty()) {
38406c3fb27SDimitry Andric     // An incomplete TypeString stub is placed in the cache for this RecordType
38506c3fb27SDimitry Andric     // so that recursive calls to this RecordType will use it whilst building a
38606c3fb27SDimitry Andric     // complete TypeString for this RecordType.
38706c3fb27SDimitry Andric     SmallVector<FieldEncoding, 16> FE;
38806c3fb27SDimitry Andric     std::string StubEnc(Enc.substr(Start).str());
38906c3fb27SDimitry Andric     StubEnc += '}';  // StubEnc now holds a valid incomplete TypeString.
39006c3fb27SDimitry Andric     TSC.addIncomplete(ID, std::move(StubEnc));
39106c3fb27SDimitry Andric     if (!extractFieldType(FE, RD, CGM, TSC)) {
39206c3fb27SDimitry Andric       (void) TSC.removeIncomplete(ID);
39306c3fb27SDimitry Andric       return false;
39406c3fb27SDimitry Andric     }
39506c3fb27SDimitry Andric     IsRecursive = TSC.removeIncomplete(ID);
39606c3fb27SDimitry Andric     // The ABI requires unions to be sorted but not structures.
39706c3fb27SDimitry Andric     // See FieldEncoding::operator< for sort algorithm.
39806c3fb27SDimitry Andric     if (RT->isUnionType())
39906c3fb27SDimitry Andric       llvm::sort(FE);
40006c3fb27SDimitry Andric     // We can now complete the TypeString.
40106c3fb27SDimitry Andric     unsigned E = FE.size();
40206c3fb27SDimitry Andric     for (unsigned I = 0; I != E; ++I) {
40306c3fb27SDimitry Andric       if (I)
40406c3fb27SDimitry Andric         Enc += ',';
40506c3fb27SDimitry Andric       Enc += FE[I].str();
40606c3fb27SDimitry Andric     }
40706c3fb27SDimitry Andric   }
40806c3fb27SDimitry Andric   Enc += '}';
40906c3fb27SDimitry Andric   TSC.addIfComplete(ID, Enc.substr(Start), IsRecursive);
41006c3fb27SDimitry Andric   return true;
41106c3fb27SDimitry Andric }
41206c3fb27SDimitry Andric 
41306c3fb27SDimitry Andric /// Appends enum types to Enc and adds the encoding to the cache.
41406c3fb27SDimitry Andric static bool appendEnumType(SmallStringEnc &Enc, const EnumType *ET,
41506c3fb27SDimitry Andric                            TypeStringCache &TSC,
41606c3fb27SDimitry Andric                            const IdentifierInfo *ID) {
41706c3fb27SDimitry Andric   // Append the cached TypeString if we have one.
41806c3fb27SDimitry Andric   StringRef TypeString = TSC.lookupStr(ID);
41906c3fb27SDimitry Andric   if (!TypeString.empty()) {
42006c3fb27SDimitry Andric     Enc += TypeString;
42106c3fb27SDimitry Andric     return true;
42206c3fb27SDimitry Andric   }
42306c3fb27SDimitry Andric 
42406c3fb27SDimitry Andric   size_t Start = Enc.size();
42506c3fb27SDimitry Andric   Enc += "e(";
42606c3fb27SDimitry Andric   if (ID)
42706c3fb27SDimitry Andric     Enc += ID->getName();
42806c3fb27SDimitry Andric   Enc += "){";
42906c3fb27SDimitry Andric 
43006c3fb27SDimitry Andric   // We collect all encoded enumerations and order them alphanumerically.
43106c3fb27SDimitry Andric   if (const EnumDecl *ED = ET->getDecl()->getDefinition()) {
43206c3fb27SDimitry Andric     SmallVector<FieldEncoding, 16> FE;
43306c3fb27SDimitry Andric     for (auto I = ED->enumerator_begin(), E = ED->enumerator_end(); I != E;
43406c3fb27SDimitry Andric          ++I) {
43506c3fb27SDimitry Andric       SmallStringEnc EnumEnc;
43606c3fb27SDimitry Andric       EnumEnc += "m(";
43706c3fb27SDimitry Andric       EnumEnc += I->getName();
43806c3fb27SDimitry Andric       EnumEnc += "){";
43906c3fb27SDimitry Andric       I->getInitVal().toString(EnumEnc);
44006c3fb27SDimitry Andric       EnumEnc += '}';
44106c3fb27SDimitry Andric       FE.push_back(FieldEncoding(!I->getName().empty(), EnumEnc));
44206c3fb27SDimitry Andric     }
44306c3fb27SDimitry Andric     llvm::sort(FE);
44406c3fb27SDimitry Andric     unsigned E = FE.size();
44506c3fb27SDimitry Andric     for (unsigned I = 0; I != E; ++I) {
44606c3fb27SDimitry Andric       if (I)
44706c3fb27SDimitry Andric         Enc += ',';
44806c3fb27SDimitry Andric       Enc += FE[I].str();
44906c3fb27SDimitry Andric     }
45006c3fb27SDimitry Andric   }
45106c3fb27SDimitry Andric   Enc += '}';
45206c3fb27SDimitry Andric   TSC.addIfComplete(ID, Enc.substr(Start), false);
45306c3fb27SDimitry Andric   return true;
45406c3fb27SDimitry Andric }
45506c3fb27SDimitry Andric 
45606c3fb27SDimitry Andric /// Appends type's qualifier to Enc.
45706c3fb27SDimitry Andric /// This is done prior to appending the type's encoding.
45806c3fb27SDimitry Andric static void appendQualifier(SmallStringEnc &Enc, QualType QT) {
45906c3fb27SDimitry Andric   // Qualifiers are emitted in alphabetical order.
46006c3fb27SDimitry Andric   static const char *const Table[]={"","c:","r:","cr:","v:","cv:","rv:","crv:"};
46106c3fb27SDimitry Andric   int Lookup = 0;
46206c3fb27SDimitry Andric   if (QT.isConstQualified())
46306c3fb27SDimitry Andric     Lookup += 1<<0;
46406c3fb27SDimitry Andric   if (QT.isRestrictQualified())
46506c3fb27SDimitry Andric     Lookup += 1<<1;
46606c3fb27SDimitry Andric   if (QT.isVolatileQualified())
46706c3fb27SDimitry Andric     Lookup += 1<<2;
46806c3fb27SDimitry Andric   Enc += Table[Lookup];
46906c3fb27SDimitry Andric }
47006c3fb27SDimitry Andric 
47106c3fb27SDimitry Andric /// Appends built-in types to Enc.
47206c3fb27SDimitry Andric static bool appendBuiltinType(SmallStringEnc &Enc, const BuiltinType *BT) {
47306c3fb27SDimitry Andric   const char *EncType;
47406c3fb27SDimitry Andric   switch (BT->getKind()) {
47506c3fb27SDimitry Andric     case BuiltinType::Void:
47606c3fb27SDimitry Andric       EncType = "0";
47706c3fb27SDimitry Andric       break;
47806c3fb27SDimitry Andric     case BuiltinType::Bool:
47906c3fb27SDimitry Andric       EncType = "b";
48006c3fb27SDimitry Andric       break;
48106c3fb27SDimitry Andric     case BuiltinType::Char_U:
48206c3fb27SDimitry Andric       EncType = "uc";
48306c3fb27SDimitry Andric       break;
48406c3fb27SDimitry Andric     case BuiltinType::UChar:
48506c3fb27SDimitry Andric       EncType = "uc";
48606c3fb27SDimitry Andric       break;
48706c3fb27SDimitry Andric     case BuiltinType::SChar:
48806c3fb27SDimitry Andric       EncType = "sc";
48906c3fb27SDimitry Andric       break;
49006c3fb27SDimitry Andric     case BuiltinType::UShort:
49106c3fb27SDimitry Andric       EncType = "us";
49206c3fb27SDimitry Andric       break;
49306c3fb27SDimitry Andric     case BuiltinType::Short:
49406c3fb27SDimitry Andric       EncType = "ss";
49506c3fb27SDimitry Andric       break;
49606c3fb27SDimitry Andric     case BuiltinType::UInt:
49706c3fb27SDimitry Andric       EncType = "ui";
49806c3fb27SDimitry Andric       break;
49906c3fb27SDimitry Andric     case BuiltinType::Int:
50006c3fb27SDimitry Andric       EncType = "si";
50106c3fb27SDimitry Andric       break;
50206c3fb27SDimitry Andric     case BuiltinType::ULong:
50306c3fb27SDimitry Andric       EncType = "ul";
50406c3fb27SDimitry Andric       break;
50506c3fb27SDimitry Andric     case BuiltinType::Long:
50606c3fb27SDimitry Andric       EncType = "sl";
50706c3fb27SDimitry Andric       break;
50806c3fb27SDimitry Andric     case BuiltinType::ULongLong:
50906c3fb27SDimitry Andric       EncType = "ull";
51006c3fb27SDimitry Andric       break;
51106c3fb27SDimitry Andric     case BuiltinType::LongLong:
51206c3fb27SDimitry Andric       EncType = "sll";
51306c3fb27SDimitry Andric       break;
51406c3fb27SDimitry Andric     case BuiltinType::Float:
51506c3fb27SDimitry Andric       EncType = "ft";
51606c3fb27SDimitry Andric       break;
51706c3fb27SDimitry Andric     case BuiltinType::Double:
51806c3fb27SDimitry Andric       EncType = "d";
51906c3fb27SDimitry Andric       break;
52006c3fb27SDimitry Andric     case BuiltinType::LongDouble:
52106c3fb27SDimitry Andric       EncType = "ld";
52206c3fb27SDimitry Andric       break;
52306c3fb27SDimitry Andric     default:
52406c3fb27SDimitry Andric       return false;
52506c3fb27SDimitry Andric   }
52606c3fb27SDimitry Andric   Enc += EncType;
52706c3fb27SDimitry Andric   return true;
52806c3fb27SDimitry Andric }
52906c3fb27SDimitry Andric 
53006c3fb27SDimitry Andric /// Appends a pointer encoding to Enc before calling appendType for the pointee.
53106c3fb27SDimitry Andric static bool appendPointerType(SmallStringEnc &Enc, const PointerType *PT,
53206c3fb27SDimitry Andric                               const CodeGen::CodeGenModule &CGM,
53306c3fb27SDimitry Andric                               TypeStringCache &TSC) {
53406c3fb27SDimitry Andric   Enc += "p(";
53506c3fb27SDimitry Andric   if (!appendType(Enc, PT->getPointeeType(), CGM, TSC))
53606c3fb27SDimitry Andric     return false;
53706c3fb27SDimitry Andric   Enc += ')';
53806c3fb27SDimitry Andric   return true;
53906c3fb27SDimitry Andric }
54006c3fb27SDimitry Andric 
54106c3fb27SDimitry Andric /// Appends array encoding to Enc before calling appendType for the element.
54206c3fb27SDimitry Andric static bool appendArrayType(SmallStringEnc &Enc, QualType QT,
54306c3fb27SDimitry Andric                             const ArrayType *AT,
54406c3fb27SDimitry Andric                             const CodeGen::CodeGenModule &CGM,
54506c3fb27SDimitry Andric                             TypeStringCache &TSC, StringRef NoSizeEnc) {
5465f757f3fSDimitry Andric   if (AT->getSizeModifier() != ArraySizeModifier::Normal)
54706c3fb27SDimitry Andric     return false;
54806c3fb27SDimitry Andric   Enc += "a(";
54906c3fb27SDimitry Andric   if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(AT))
55006c3fb27SDimitry Andric     CAT->getSize().toStringUnsigned(Enc);
55106c3fb27SDimitry Andric   else
55206c3fb27SDimitry Andric     Enc += NoSizeEnc; // Global arrays use "*", otherwise it is "".
55306c3fb27SDimitry Andric   Enc += ':';
55406c3fb27SDimitry Andric   // The Qualifiers should be attached to the type rather than the array.
55506c3fb27SDimitry Andric   appendQualifier(Enc, QT);
55606c3fb27SDimitry Andric   if (!appendType(Enc, AT->getElementType(), CGM, TSC))
55706c3fb27SDimitry Andric     return false;
55806c3fb27SDimitry Andric   Enc += ')';
55906c3fb27SDimitry Andric   return true;
56006c3fb27SDimitry Andric }
56106c3fb27SDimitry Andric 
56206c3fb27SDimitry Andric /// Appends a function encoding to Enc, calling appendType for the return type
56306c3fb27SDimitry Andric /// and the arguments.
56406c3fb27SDimitry Andric static bool appendFunctionType(SmallStringEnc &Enc, const FunctionType *FT,
56506c3fb27SDimitry Andric                              const CodeGen::CodeGenModule &CGM,
56606c3fb27SDimitry Andric                              TypeStringCache &TSC) {
56706c3fb27SDimitry Andric   Enc += "f{";
56806c3fb27SDimitry Andric   if (!appendType(Enc, FT->getReturnType(), CGM, TSC))
56906c3fb27SDimitry Andric     return false;
57006c3fb27SDimitry Andric   Enc += "}(";
57106c3fb27SDimitry Andric   if (const FunctionProtoType *FPT = FT->getAs<FunctionProtoType>()) {
57206c3fb27SDimitry Andric     // N.B. we are only interested in the adjusted param types.
57306c3fb27SDimitry Andric     auto I = FPT->param_type_begin();
57406c3fb27SDimitry Andric     auto E = FPT->param_type_end();
57506c3fb27SDimitry Andric     if (I != E) {
57606c3fb27SDimitry Andric       do {
57706c3fb27SDimitry Andric         if (!appendType(Enc, *I, CGM, TSC))
57806c3fb27SDimitry Andric           return false;
57906c3fb27SDimitry Andric         ++I;
58006c3fb27SDimitry Andric         if (I != E)
58106c3fb27SDimitry Andric           Enc += ',';
58206c3fb27SDimitry Andric       } while (I != E);
58306c3fb27SDimitry Andric       if (FPT->isVariadic())
58406c3fb27SDimitry Andric         Enc += ",va";
58506c3fb27SDimitry Andric     } else {
58606c3fb27SDimitry Andric       if (FPT->isVariadic())
58706c3fb27SDimitry Andric         Enc += "va";
58806c3fb27SDimitry Andric       else
58906c3fb27SDimitry Andric         Enc += '0';
59006c3fb27SDimitry Andric     }
59106c3fb27SDimitry Andric   }
59206c3fb27SDimitry Andric   Enc += ')';
59306c3fb27SDimitry Andric   return true;
59406c3fb27SDimitry Andric }
59506c3fb27SDimitry Andric 
59606c3fb27SDimitry Andric /// Handles the type's qualifier before dispatching a call to handle specific
59706c3fb27SDimitry Andric /// type encodings.
59806c3fb27SDimitry Andric static bool appendType(SmallStringEnc &Enc, QualType QType,
59906c3fb27SDimitry Andric                        const CodeGen::CodeGenModule &CGM,
60006c3fb27SDimitry Andric                        TypeStringCache &TSC) {
60106c3fb27SDimitry Andric 
60206c3fb27SDimitry Andric   QualType QT = QType.getCanonicalType();
60306c3fb27SDimitry Andric 
60406c3fb27SDimitry Andric   if (const ArrayType *AT = QT->getAsArrayTypeUnsafe())
60506c3fb27SDimitry Andric     // The Qualifiers should be attached to the type rather than the array.
60606c3fb27SDimitry Andric     // Thus we don't call appendQualifier() here.
60706c3fb27SDimitry Andric     return appendArrayType(Enc, QT, AT, CGM, TSC, "");
60806c3fb27SDimitry Andric 
60906c3fb27SDimitry Andric   appendQualifier(Enc, QT);
61006c3fb27SDimitry Andric 
61106c3fb27SDimitry Andric   if (const BuiltinType *BT = QT->getAs<BuiltinType>())
61206c3fb27SDimitry Andric     return appendBuiltinType(Enc, BT);
61306c3fb27SDimitry Andric 
61406c3fb27SDimitry Andric   if (const PointerType *PT = QT->getAs<PointerType>())
61506c3fb27SDimitry Andric     return appendPointerType(Enc, PT, CGM, TSC);
61606c3fb27SDimitry Andric 
61706c3fb27SDimitry Andric   if (const EnumType *ET = QT->getAs<EnumType>())
61806c3fb27SDimitry Andric     return appendEnumType(Enc, ET, TSC, QT.getBaseTypeIdentifier());
61906c3fb27SDimitry Andric 
62006c3fb27SDimitry Andric   if (const RecordType *RT = QT->getAsStructureType())
62106c3fb27SDimitry Andric     return appendRecordType(Enc, RT, CGM, TSC, QT.getBaseTypeIdentifier());
62206c3fb27SDimitry Andric 
62306c3fb27SDimitry Andric   if (const RecordType *RT = QT->getAsUnionType())
62406c3fb27SDimitry Andric     return appendRecordType(Enc, RT, CGM, TSC, QT.getBaseTypeIdentifier());
62506c3fb27SDimitry Andric 
62606c3fb27SDimitry Andric   if (const FunctionType *FT = QT->getAs<FunctionType>())
62706c3fb27SDimitry Andric     return appendFunctionType(Enc, FT, CGM, TSC);
62806c3fb27SDimitry Andric 
62906c3fb27SDimitry Andric   return false;
63006c3fb27SDimitry Andric }
63106c3fb27SDimitry Andric 
63206c3fb27SDimitry Andric static bool getTypeString(SmallStringEnc &Enc, const Decl *D,
63306c3fb27SDimitry Andric                           const CodeGen::CodeGenModule &CGM,
63406c3fb27SDimitry Andric                           TypeStringCache &TSC) {
63506c3fb27SDimitry Andric   if (!D)
63606c3fb27SDimitry Andric     return false;
63706c3fb27SDimitry Andric 
63806c3fb27SDimitry Andric   if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
63906c3fb27SDimitry Andric     if (FD->getLanguageLinkage() != CLanguageLinkage)
64006c3fb27SDimitry Andric       return false;
64106c3fb27SDimitry Andric     return appendType(Enc, FD->getType(), CGM, TSC);
64206c3fb27SDimitry Andric   }
64306c3fb27SDimitry Andric 
64406c3fb27SDimitry Andric   if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
64506c3fb27SDimitry Andric     if (VD->getLanguageLinkage() != CLanguageLinkage)
64606c3fb27SDimitry Andric       return false;
64706c3fb27SDimitry Andric     QualType QT = VD->getType().getCanonicalType();
64806c3fb27SDimitry Andric     if (const ArrayType *AT = QT->getAsArrayTypeUnsafe()) {
64906c3fb27SDimitry Andric       // Global ArrayTypes are given a size of '*' if the size is unknown.
65006c3fb27SDimitry Andric       // The Qualifiers should be attached to the type rather than the array.
65106c3fb27SDimitry Andric       // Thus we don't call appendQualifier() here.
65206c3fb27SDimitry Andric       return appendArrayType(Enc, QT, AT, CGM, TSC, "*");
65306c3fb27SDimitry Andric     }
65406c3fb27SDimitry Andric     return appendType(Enc, QT, CGM, TSC);
65506c3fb27SDimitry Andric   }
65606c3fb27SDimitry Andric   return false;
65706c3fb27SDimitry Andric }
65806c3fb27SDimitry Andric 
65906c3fb27SDimitry Andric std::unique_ptr<TargetCodeGenInfo>
66006c3fb27SDimitry Andric CodeGen::createXCoreTargetCodeGenInfo(CodeGenModule &CGM) {
66106c3fb27SDimitry Andric   return std::make_unique<XCoreTargetCodeGenInfo>(CGM.getTypes());
66206c3fb27SDimitry Andric }
663