| //===- XCore.cpp ----------------------------------------------------------===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "ABIInfoImpl.h" |
| #include "TargetInfo.h" |
| |
| using namespace clang; |
| using namespace clang::CodeGen; |
| |
| //===----------------------------------------------------------------------===// |
| // XCore ABI Implementation |
| //===----------------------------------------------------------------------===// |
| |
| namespace { |
| |
| /// A SmallStringEnc instance is used to build up the TypeString by passing |
| /// it by reference between functions that append to it. |
| typedef llvm::SmallString<128> SmallStringEnc; |
| |
| /// TypeStringCache caches the meta encodings of Types. |
| /// |
| /// The reason for caching TypeStrings is two fold: |
| /// 1. To cache a type's encoding for later uses; |
| /// 2. As a means to break recursive member type inclusion. |
| /// |
| /// A cache Entry can have a Status of: |
| /// NonRecursive: The type encoding is not recursive; |
| /// Recursive: The type encoding is recursive; |
| /// Incomplete: An incomplete TypeString; |
| /// IncompleteUsed: An incomplete TypeString that has been used in a |
| /// Recursive type encoding. |
| /// |
| /// A NonRecursive entry will have all of its sub-members expanded as fully |
| /// as possible. Whilst it may contain types which are recursive, the type |
| /// itself is not recursive and thus its encoding may be safely used whenever |
| /// the type is encountered. |
| /// |
| /// A Recursive entry will have all of its sub-members expanded as fully as |
| /// possible. The type itself is recursive and it may contain other types which |
| /// are recursive. The Recursive encoding must not be used during the expansion |
| /// of a recursive type's recursive branch. For simplicity the code uses |
| /// IncompleteCount to reject all usage of Recursive encodings for member types. |
| /// |
| /// An Incomplete entry is always a RecordType and only encodes its |
| /// identifier e.g. "s(S){}". Incomplete 'StubEnc' entries are ephemeral and |
| /// are placed into the cache during type expansion as a means to identify and |
| /// handle recursive inclusion of types as sub-members. If there is recursion |
| /// the entry becomes IncompleteUsed. |
| /// |
| /// During the expansion of a RecordType's members: |
| /// |
| /// If the cache contains a NonRecursive encoding for the member type, the |
| /// cached encoding is used; |
| /// |
| /// If the cache contains a Recursive encoding for the member type, the |
| /// cached encoding is 'Swapped' out, as it may be incorrect, and... |
| /// |
| /// If the member is a RecordType, an Incomplete encoding is placed into the |
| /// cache to break potential recursive inclusion of itself as a sub-member; |
| /// |
| /// Once a member RecordType has been expanded, its temporary incomplete |
| /// entry is removed from the cache. If a Recursive encoding was swapped out |
| /// it is swapped back in; |
| /// |
| /// If an incomplete entry is used to expand a sub-member, the incomplete |
| /// entry is marked as IncompleteUsed. The cache keeps count of how many |
| /// IncompleteUsed entries it currently contains in IncompleteUsedCount; |
| /// |
| /// If a member's encoding is found to be a NonRecursive or Recursive viz: |
| /// IncompleteUsedCount==0, the member's encoding is added to the cache. |
| /// Else the member is part of a recursive type and thus the recursion has |
| /// been exited too soon for the encoding to be correct for the member. |
| /// |
| class TypeStringCache { |
| enum Status {NonRecursive, Recursive, Incomplete, IncompleteUsed}; |
| struct Entry { |
| std::string Str; // The encoded TypeString for the type. |
| enum Status State; // Information about the encoding in 'Str'. |
| std::string Swapped; // A temporary place holder for a Recursive encoding |
| // during the expansion of RecordType's members. |
| }; |
| std::map<const IdentifierInfo *, struct Entry> Map; |
| unsigned IncompleteCount; // Number of Incomplete entries in the Map. |
| unsigned IncompleteUsedCount; // Number of IncompleteUsed entries in the Map. |
| public: |
| TypeStringCache() : IncompleteCount(0), IncompleteUsedCount(0) {} |
| void addIncomplete(const IdentifierInfo *ID, std::string StubEnc); |
| bool removeIncomplete(const IdentifierInfo *ID); |
| void addIfComplete(const IdentifierInfo *ID, StringRef Str, |
| bool IsRecursive); |
| StringRef lookupStr(const IdentifierInfo *ID); |
| }; |
| |
| /// TypeString encodings for enum & union fields must be order. |
| /// FieldEncoding is a helper for this ordering process. |
| class FieldEncoding { |
| bool HasName; |
| std::string Enc; |
| public: |
| FieldEncoding(bool b, SmallStringEnc &e) : HasName(b), Enc(e.c_str()) {} |
| StringRef str() { return Enc; } |
| bool operator<(const FieldEncoding &rhs) const { |
| if (HasName != rhs.HasName) return HasName; |
| return Enc < rhs.Enc; |
| } |
| }; |
| |
| class XCoreABIInfo : public DefaultABIInfo { |
| public: |
| XCoreABIInfo(CodeGen::CodeGenTypes &CGT) : DefaultABIInfo(CGT) {} |
| Address EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, |
| QualType Ty) const override; |
| }; |
| |
| class XCoreTargetCodeGenInfo : public TargetCodeGenInfo { |
| mutable TypeStringCache TSC; |
| void emitTargetMD(const Decl *D, llvm::GlobalValue *GV, |
| const CodeGen::CodeGenModule &M) const; |
| |
| public: |
| XCoreTargetCodeGenInfo(CodeGenTypes &CGT) |
| : TargetCodeGenInfo(std::make_unique<XCoreABIInfo>(CGT)) {} |
| void emitTargetMetadata(CodeGen::CodeGenModule &CGM, |
| const llvm::MapVector<GlobalDecl, StringRef> |
| &MangledDeclNames) const override; |
| }; |
| |
| } // End anonymous namespace. |
| |
| // TODO: this implementation is likely now redundant with the default |
| // EmitVAArg. |
| Address XCoreABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, |
| QualType Ty) const { |
| CGBuilderTy &Builder = CGF.Builder; |
| |
| // Get the VAList. |
| CharUnits SlotSize = CharUnits::fromQuantity(4); |
| Address AP = Address(Builder.CreateLoad(VAListAddr), |
| getVAListElementType(CGF), SlotSize); |
| |
| // Handle the argument. |
| ABIArgInfo AI = classifyArgumentType(Ty); |
| CharUnits TypeAlign = getContext().getTypeAlignInChars(Ty); |
| llvm::Type *ArgTy = CGT.ConvertType(Ty); |
| if (AI.canHaveCoerceToType() && !AI.getCoerceToType()) |
| AI.setCoerceToType(ArgTy); |
| llvm::Type *ArgPtrTy = llvm::PointerType::getUnqual(ArgTy); |
| |
| Address Val = Address::invalid(); |
| CharUnits ArgSize = CharUnits::Zero(); |
| switch (AI.getKind()) { |
| case ABIArgInfo::Expand: |
| case ABIArgInfo::CoerceAndExpand: |
| case ABIArgInfo::InAlloca: |
| llvm_unreachable("Unsupported ABI kind for va_arg"); |
| case ABIArgInfo::Ignore: |
| Val = Address(llvm::UndefValue::get(ArgPtrTy), ArgTy, TypeAlign); |
| ArgSize = CharUnits::Zero(); |
| break; |
| case ABIArgInfo::Extend: |
| case ABIArgInfo::Direct: |
| Val = AP.withElementType(ArgTy); |
| ArgSize = CharUnits::fromQuantity( |
| getDataLayout().getTypeAllocSize(AI.getCoerceToType())); |
| ArgSize = ArgSize.alignTo(SlotSize); |
| break; |
| case ABIArgInfo::Indirect: |
| case ABIArgInfo::IndirectAliased: |
| Val = AP.withElementType(ArgPtrTy); |
| Val = Address(Builder.CreateLoad(Val), ArgTy, TypeAlign); |
| ArgSize = SlotSize; |
| break; |
| } |
| |
| // Increment the VAList. |
| if (!ArgSize.isZero()) { |
| Address APN = Builder.CreateConstInBoundsByteGEP(AP, ArgSize); |
| Builder.CreateStore(APN.getPointer(), VAListAddr); |
| } |
| |
| return Val; |
| } |
| |
| /// During the expansion of a RecordType, an incomplete TypeString is placed |
| /// into the cache as a means to identify and break recursion. |
| /// If there is a Recursive encoding in the cache, it is swapped out and will |
| /// be reinserted by removeIncomplete(). |
| /// All other types of encoding should have been used rather than arriving here. |
| void TypeStringCache::addIncomplete(const IdentifierInfo *ID, |
| std::string StubEnc) { |
| if (!ID) |
| return; |
| Entry &E = Map[ID]; |
| assert( (E.Str.empty() || E.State == Recursive) && |
| "Incorrectly use of addIncomplete"); |
| assert(!StubEnc.empty() && "Passing an empty string to addIncomplete()"); |
| E.Swapped.swap(E.Str); // swap out the Recursive |
| E.Str.swap(StubEnc); |
| E.State = Incomplete; |
| ++IncompleteCount; |
| } |
| |
| /// Once the RecordType has been expanded, the temporary incomplete TypeString |
| /// must be removed from the cache. |
| /// If a Recursive was swapped out by addIncomplete(), it will be replaced. |
| /// Returns true if the RecordType was defined recursively. |
| bool TypeStringCache::removeIncomplete(const IdentifierInfo *ID) { |
| if (!ID) |
| return false; |
| auto I = Map.find(ID); |
| assert(I != Map.end() && "Entry not present"); |
| Entry &E = I->second; |
| assert( (E.State == Incomplete || |
| E.State == IncompleteUsed) && |
| "Entry must be an incomplete type"); |
| bool IsRecursive = false; |
| if (E.State == IncompleteUsed) { |
| // We made use of our Incomplete encoding, thus we are recursive. |
| IsRecursive = true; |
| --IncompleteUsedCount; |
| } |
| if (E.Swapped.empty()) |
| Map.erase(I); |
| else { |
| // Swap the Recursive back. |
| E.Swapped.swap(E.Str); |
| E.Swapped.clear(); |
| E.State = Recursive; |
| } |
| --IncompleteCount; |
| return IsRecursive; |
| } |
| |
| /// Add the encoded TypeString to the cache only if it is NonRecursive or |
| /// Recursive (viz: all sub-members were expanded as fully as possible). |
| void TypeStringCache::addIfComplete(const IdentifierInfo *ID, StringRef Str, |
| bool IsRecursive) { |
| if (!ID || IncompleteUsedCount) |
| return; // No key or it is an incomplete sub-type so don't add. |
| Entry &E = Map[ID]; |
| if (IsRecursive && !E.Str.empty()) { |
| assert(E.State==Recursive && E.Str.size() == Str.size() && |
| "This is not the same Recursive entry"); |
| // The parent container was not recursive after all, so we could have used |
| // this Recursive sub-member entry after all, but we assumed the worse when |
| // we started viz: IncompleteCount!=0. |
| return; |
| } |
| assert(E.Str.empty() && "Entry already present"); |
| E.Str = Str.str(); |
| E.State = IsRecursive? Recursive : NonRecursive; |
| } |
| |
| /// Return a cached TypeString encoding for the ID. If there isn't one, or we |
| /// are recursively expanding a type (IncompleteCount != 0) and the cached |
| /// encoding is Recursive, return an empty StringRef. |
| StringRef TypeStringCache::lookupStr(const IdentifierInfo *ID) { |
| if (!ID) |
| return StringRef(); // We have no key. |
| auto I = Map.find(ID); |
| if (I == Map.end()) |
| return StringRef(); // We have no encoding. |
| Entry &E = I->second; |
| if (E.State == Recursive && IncompleteCount) |
| return StringRef(); // We don't use Recursive encodings for member types. |
| |
| if (E.State == Incomplete) { |
| // The incomplete type is being used to break out of recursion. |
| E.State = IncompleteUsed; |
| ++IncompleteUsedCount; |
| } |
| return E.Str; |
| } |
| |
| /// The XCore ABI includes a type information section that communicates symbol |
| /// type information to the linker. The linker uses this information to verify |
| /// safety/correctness of things such as array bound and pointers et al. |
| /// The ABI only requires C (and XC) language modules to emit TypeStrings. |
| /// This type information (TypeString) is emitted into meta data for all global |
| /// symbols: definitions, declarations, functions & variables. |
| /// |
| /// The TypeString carries type, qualifier, name, size & value details. |
| /// Please see 'Tools Development Guide' section 2.16.2 for format details: |
| /// https://www.xmos.com/download/public/Tools-Development-Guide%28X9114A%29.pdf |
| /// The output is tested by test/CodeGen/xcore-stringtype.c. |
| /// |
| static bool getTypeString(SmallStringEnc &Enc, const Decl *D, |
| const CodeGen::CodeGenModule &CGM, |
| TypeStringCache &TSC); |
| |
| /// XCore uses emitTargetMD to emit TypeString metadata for global symbols. |
| void XCoreTargetCodeGenInfo::emitTargetMD( |
| const Decl *D, llvm::GlobalValue *GV, |
| const CodeGen::CodeGenModule &CGM) const { |
| SmallStringEnc Enc; |
| if (getTypeString(Enc, D, CGM, TSC)) { |
| llvm::LLVMContext &Ctx = CGM.getModule().getContext(); |
| llvm::Metadata *MDVals[] = {llvm::ConstantAsMetadata::get(GV), |
| llvm::MDString::get(Ctx, Enc.str())}; |
| llvm::NamedMDNode *MD = |
| CGM.getModule().getOrInsertNamedMetadata("xcore.typestrings"); |
| MD->addOperand(llvm::MDNode::get(Ctx, MDVals)); |
| } |
| } |
| |
| void XCoreTargetCodeGenInfo::emitTargetMetadata( |
| CodeGen::CodeGenModule &CGM, |
| const llvm::MapVector<GlobalDecl, StringRef> &MangledDeclNames) const { |
| // Warning, new MangledDeclNames may be appended within this loop. |
| // We rely on MapVector insertions adding new elements to the end |
| // of the container. |
| for (unsigned I = 0; I != MangledDeclNames.size(); ++I) { |
| auto Val = *(MangledDeclNames.begin() + I); |
| llvm::GlobalValue *GV = CGM.GetGlobalValue(Val.second); |
| if (GV) { |
| const Decl *D = Val.first.getDecl()->getMostRecentDecl(); |
| emitTargetMD(D, GV, CGM); |
| } |
| } |
| } |
| |
| static bool appendType(SmallStringEnc &Enc, QualType QType, |
| const CodeGen::CodeGenModule &CGM, |
| TypeStringCache &TSC); |
| |
| /// Helper function for appendRecordType(). |
| /// Builds a SmallVector containing the encoded field types in declaration |
| /// order. |
| static bool extractFieldType(SmallVectorImpl<FieldEncoding> &FE, |
| const RecordDecl *RD, |
| const CodeGen::CodeGenModule &CGM, |
| TypeStringCache &TSC) { |
| for (const auto *Field : RD->fields()) { |
| SmallStringEnc Enc; |
| Enc += "m("; |
| Enc += Field->getName(); |
| Enc += "){"; |
| if (Field->isBitField()) { |
| Enc += "b("; |
| llvm::raw_svector_ostream OS(Enc); |
| OS << Field->getBitWidthValue(CGM.getContext()); |
| Enc += ':'; |
| } |
| if (!appendType(Enc, Field->getType(), CGM, TSC)) |
| return false; |
| if (Field->isBitField()) |
| Enc += ')'; |
| Enc += '}'; |
| FE.emplace_back(!Field->getName().empty(), Enc); |
| } |
| return true; |
| } |
| |
| /// Appends structure and union types to Enc and adds encoding to cache. |
| /// Recursively calls appendType (via extractFieldType) for each field. |
| /// Union types have their fields ordered according to the ABI. |
| static bool appendRecordType(SmallStringEnc &Enc, const RecordType *RT, |
| const CodeGen::CodeGenModule &CGM, |
| TypeStringCache &TSC, const IdentifierInfo *ID) { |
| // Append the cached TypeString if we have one. |
| StringRef TypeString = TSC.lookupStr(ID); |
| if (!TypeString.empty()) { |
| Enc += TypeString; |
| return true; |
| } |
| |
| // Start to emit an incomplete TypeString. |
| size_t Start = Enc.size(); |
| Enc += (RT->isUnionType()? 'u' : 's'); |
| Enc += '('; |
| if (ID) |
| Enc += ID->getName(); |
| Enc += "){"; |
| |
| // We collect all encoded fields and order as necessary. |
| bool IsRecursive = false; |
| const RecordDecl *RD = RT->getDecl()->getDefinition(); |
| if (RD && !RD->field_empty()) { |
| // An incomplete TypeString stub is placed in the cache for this RecordType |
| // so that recursive calls to this RecordType will use it whilst building a |
| // complete TypeString for this RecordType. |
| SmallVector<FieldEncoding, 16> FE; |
| std::string StubEnc(Enc.substr(Start).str()); |
| StubEnc += '}'; // StubEnc now holds a valid incomplete TypeString. |
| TSC.addIncomplete(ID, std::move(StubEnc)); |
| if (!extractFieldType(FE, RD, CGM, TSC)) { |
| (void) TSC.removeIncomplete(ID); |
| return false; |
| } |
| IsRecursive = TSC.removeIncomplete(ID); |
| // The ABI requires unions to be sorted but not structures. |
| // See FieldEncoding::operator< for sort algorithm. |
| if (RT->isUnionType()) |
| llvm::sort(FE); |
| // We can now complete the TypeString. |
| unsigned E = FE.size(); |
| for (unsigned I = 0; I != E; ++I) { |
| if (I) |
| Enc += ','; |
| Enc += FE[I].str(); |
| } |
| } |
| Enc += '}'; |
| TSC.addIfComplete(ID, Enc.substr(Start), IsRecursive); |
| return true; |
| } |
| |
| /// Appends enum types to Enc and adds the encoding to the cache. |
| static bool appendEnumType(SmallStringEnc &Enc, const EnumType *ET, |
| TypeStringCache &TSC, |
| const IdentifierInfo *ID) { |
| // Append the cached TypeString if we have one. |
| StringRef TypeString = TSC.lookupStr(ID); |
| if (!TypeString.empty()) { |
| Enc += TypeString; |
| return true; |
| } |
| |
| size_t Start = Enc.size(); |
| Enc += "e("; |
| if (ID) |
| Enc += ID->getName(); |
| Enc += "){"; |
| |
| // We collect all encoded enumerations and order them alphanumerically. |
| if (const EnumDecl *ED = ET->getDecl()->getDefinition()) { |
| SmallVector<FieldEncoding, 16> FE; |
| for (auto I = ED->enumerator_begin(), E = ED->enumerator_end(); I != E; |
| ++I) { |
| SmallStringEnc EnumEnc; |
| EnumEnc += "m("; |
| EnumEnc += I->getName(); |
| EnumEnc += "){"; |
| I->getInitVal().toString(EnumEnc); |
| EnumEnc += '}'; |
| FE.push_back(FieldEncoding(!I->getName().empty(), EnumEnc)); |
| } |
| llvm::sort(FE); |
| unsigned E = FE.size(); |
| for (unsigned I = 0; I != E; ++I) { |
| if (I) |
| Enc += ','; |
| Enc += FE[I].str(); |
| } |
| } |
| Enc += '}'; |
| TSC.addIfComplete(ID, Enc.substr(Start), false); |
| return true; |
| } |
| |
| /// Appends type's qualifier to Enc. |
| /// This is done prior to appending the type's encoding. |
| static void appendQualifier(SmallStringEnc &Enc, QualType QT) { |
| // Qualifiers are emitted in alphabetical order. |
| static const char *const Table[]={"","c:","r:","cr:","v:","cv:","rv:","crv:"}; |
| int Lookup = 0; |
| if (QT.isConstQualified()) |
| Lookup += 1<<0; |
| if (QT.isRestrictQualified()) |
| Lookup += 1<<1; |
| if (QT.isVolatileQualified()) |
| Lookup += 1<<2; |
| Enc += Table[Lookup]; |
| } |
| |
| /// Appends built-in types to Enc. |
| static bool appendBuiltinType(SmallStringEnc &Enc, const BuiltinType *BT) { |
| const char *EncType; |
| switch (BT->getKind()) { |
| case BuiltinType::Void: |
| EncType = "0"; |
| break; |
| case BuiltinType::Bool: |
| EncType = "b"; |
| break; |
| case BuiltinType::Char_U: |
| EncType = "uc"; |
| break; |
| case BuiltinType::UChar: |
| EncType = "uc"; |
| break; |
| case BuiltinType::SChar: |
| EncType = "sc"; |
| break; |
| case BuiltinType::UShort: |
| EncType = "us"; |
| break; |
| case BuiltinType::Short: |
| EncType = "ss"; |
| break; |
| case BuiltinType::UInt: |
| EncType = "ui"; |
| break; |
| case BuiltinType::Int: |
| EncType = "si"; |
| break; |
| case BuiltinType::ULong: |
| EncType = "ul"; |
| break; |
| case BuiltinType::Long: |
| EncType = "sl"; |
| break; |
| case BuiltinType::ULongLong: |
| EncType = "ull"; |
| break; |
| case BuiltinType::LongLong: |
| EncType = "sll"; |
| break; |
| case BuiltinType::Float: |
| EncType = "ft"; |
| break; |
| case BuiltinType::Double: |
| EncType = "d"; |
| break; |
| case BuiltinType::LongDouble: |
| EncType = "ld"; |
| break; |
| default: |
| return false; |
| } |
| Enc += EncType; |
| return true; |
| } |
| |
| /// Appends a pointer encoding to Enc before calling appendType for the pointee. |
| static bool appendPointerType(SmallStringEnc &Enc, const PointerType *PT, |
| const CodeGen::CodeGenModule &CGM, |
| TypeStringCache &TSC) { |
| Enc += "p("; |
| if (!appendType(Enc, PT->getPointeeType(), CGM, TSC)) |
| return false; |
| Enc += ')'; |
| return true; |
| } |
| |
| /// Appends array encoding to Enc before calling appendType for the element. |
| static bool appendArrayType(SmallStringEnc &Enc, QualType QT, |
| const ArrayType *AT, |
| const CodeGen::CodeGenModule &CGM, |
| TypeStringCache &TSC, StringRef NoSizeEnc) { |
| if (AT->getSizeModifier() != ArraySizeModifier::Normal) |
| return false; |
| Enc += "a("; |
| if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(AT)) |
| CAT->getSize().toStringUnsigned(Enc); |
| else |
| Enc += NoSizeEnc; // Global arrays use "*", otherwise it is "". |
| Enc += ':'; |
| // The Qualifiers should be attached to the type rather than the array. |
| appendQualifier(Enc, QT); |
| if (!appendType(Enc, AT->getElementType(), CGM, TSC)) |
| return false; |
| Enc += ')'; |
| return true; |
| } |
| |
| /// Appends a function encoding to Enc, calling appendType for the return type |
| /// and the arguments. |
| static bool appendFunctionType(SmallStringEnc &Enc, const FunctionType *FT, |
| const CodeGen::CodeGenModule &CGM, |
| TypeStringCache &TSC) { |
| Enc += "f{"; |
| if (!appendType(Enc, FT->getReturnType(), CGM, TSC)) |
| return false; |
| Enc += "}("; |
| if (const FunctionProtoType *FPT = FT->getAs<FunctionProtoType>()) { |
| // N.B. we are only interested in the adjusted param types. |
| auto I = FPT->param_type_begin(); |
| auto E = FPT->param_type_end(); |
| if (I != E) { |
| do { |
| if (!appendType(Enc, *I, CGM, TSC)) |
| return false; |
| ++I; |
| if (I != E) |
| Enc += ','; |
| } while (I != E); |
| if (FPT->isVariadic()) |
| Enc += ",va"; |
| } else { |
| if (FPT->isVariadic()) |
| Enc += "va"; |
| else |
| Enc += '0'; |
| } |
| } |
| Enc += ')'; |
| return true; |
| } |
| |
| /// Handles the type's qualifier before dispatching a call to handle specific |
| /// type encodings. |
| static bool appendType(SmallStringEnc &Enc, QualType QType, |
| const CodeGen::CodeGenModule &CGM, |
| TypeStringCache &TSC) { |
| |
| QualType QT = QType.getCanonicalType(); |
| |
| if (const ArrayType *AT = QT->getAsArrayTypeUnsafe()) |
| // The Qualifiers should be attached to the type rather than the array. |
| // Thus we don't call appendQualifier() here. |
| return appendArrayType(Enc, QT, AT, CGM, TSC, ""); |
| |
| appendQualifier(Enc, QT); |
| |
| if (const BuiltinType *BT = QT->getAs<BuiltinType>()) |
| return appendBuiltinType(Enc, BT); |
| |
| if (const PointerType *PT = QT->getAs<PointerType>()) |
| return appendPointerType(Enc, PT, CGM, TSC); |
| |
| if (const EnumType *ET = QT->getAs<EnumType>()) |
| return appendEnumType(Enc, ET, TSC, QT.getBaseTypeIdentifier()); |
| |
| if (const RecordType *RT = QT->getAsStructureType()) |
| return appendRecordType(Enc, RT, CGM, TSC, QT.getBaseTypeIdentifier()); |
| |
| if (const RecordType *RT = QT->getAsUnionType()) |
| return appendRecordType(Enc, RT, CGM, TSC, QT.getBaseTypeIdentifier()); |
| |
| if (const FunctionType *FT = QT->getAs<FunctionType>()) |
| return appendFunctionType(Enc, FT, CGM, TSC); |
| |
| return false; |
| } |
| |
| static bool getTypeString(SmallStringEnc &Enc, const Decl *D, |
| const CodeGen::CodeGenModule &CGM, |
| TypeStringCache &TSC) { |
| if (!D) |
| return false; |
| |
| if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { |
| if (FD->getLanguageLinkage() != CLanguageLinkage) |
| return false; |
| return appendType(Enc, FD->getType(), CGM, TSC); |
| } |
| |
| if (const VarDecl *VD = dyn_cast<VarDecl>(D)) { |
| if (VD->getLanguageLinkage() != CLanguageLinkage) |
| return false; |
| QualType QT = VD->getType().getCanonicalType(); |
| if (const ArrayType *AT = QT->getAsArrayTypeUnsafe()) { |
| // Global ArrayTypes are given a size of '*' if the size is unknown. |
| // The Qualifiers should be attached to the type rather than the array. |
| // Thus we don't call appendQualifier() here. |
| return appendArrayType(Enc, QT, AT, CGM, TSC, "*"); |
| } |
| return appendType(Enc, QT, CGM, TSC); |
| } |
| return false; |
| } |
| |
| std::unique_ptr<TargetCodeGenInfo> |
| CodeGen::createXCoreTargetCodeGenInfo(CodeGenModule &CGM) { |
| return std::make_unique<XCoreTargetCodeGenInfo>(CGM.getTypes()); |
| } |