brintos

brintos / llvm-project-archived public Read only

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