1992cb984SSergei Barannikov //===- XCore.cpp ----------------------------------------------------------===// 2992cb984SSergei Barannikov // 3992cb984SSergei Barannikov // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4992cb984SSergei Barannikov // See https://llvm.org/LICENSE.txt for license information. 5992cb984SSergei Barannikov // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6992cb984SSergei Barannikov // 7992cb984SSergei Barannikov //===----------------------------------------------------------------------===// 8992cb984SSergei Barannikov 9992cb984SSergei Barannikov #include "ABIInfoImpl.h" 10992cb984SSergei Barannikov #include "TargetInfo.h" 11992cb984SSergei Barannikov 12992cb984SSergei Barannikov using namespace clang; 13992cb984SSergei Barannikov using namespace clang::CodeGen; 14992cb984SSergei Barannikov 15992cb984SSergei Barannikov //===----------------------------------------------------------------------===// 16992cb984SSergei Barannikov // XCore ABI Implementation 17992cb984SSergei Barannikov //===----------------------------------------------------------------------===// 18992cb984SSergei Barannikov 19992cb984SSergei Barannikov namespace { 20992cb984SSergei Barannikov 21992cb984SSergei Barannikov /// A SmallStringEnc instance is used to build up the TypeString by passing 22992cb984SSergei Barannikov /// it by reference between functions that append to it. 23992cb984SSergei Barannikov typedef llvm::SmallString<128> SmallStringEnc; 24992cb984SSergei Barannikov 25992cb984SSergei Barannikov /// TypeStringCache caches the meta encodings of Types. 26992cb984SSergei Barannikov /// 27992cb984SSergei Barannikov /// The reason for caching TypeStrings is two fold: 28992cb984SSergei Barannikov /// 1. To cache a type's encoding for later uses; 29992cb984SSergei Barannikov /// 2. As a means to break recursive member type inclusion. 30992cb984SSergei Barannikov /// 31992cb984SSergei Barannikov /// A cache Entry can have a Status of: 32992cb984SSergei Barannikov /// NonRecursive: The type encoding is not recursive; 33992cb984SSergei Barannikov /// Recursive: The type encoding is recursive; 34992cb984SSergei Barannikov /// Incomplete: An incomplete TypeString; 35992cb984SSergei Barannikov /// IncompleteUsed: An incomplete TypeString that has been used in a 36992cb984SSergei Barannikov /// Recursive type encoding. 37992cb984SSergei Barannikov /// 38992cb984SSergei Barannikov /// A NonRecursive entry will have all of its sub-members expanded as fully 39992cb984SSergei Barannikov /// as possible. Whilst it may contain types which are recursive, the type 40992cb984SSergei Barannikov /// itself is not recursive and thus its encoding may be safely used whenever 41992cb984SSergei Barannikov /// the type is encountered. 42992cb984SSergei Barannikov /// 43992cb984SSergei Barannikov /// A Recursive entry will have all of its sub-members expanded as fully as 44992cb984SSergei Barannikov /// possible. The type itself is recursive and it may contain other types which 45992cb984SSergei Barannikov /// are recursive. The Recursive encoding must not be used during the expansion 46992cb984SSergei Barannikov /// of a recursive type's recursive branch. For simplicity the code uses 47992cb984SSergei Barannikov /// IncompleteCount to reject all usage of Recursive encodings for member types. 48992cb984SSergei Barannikov /// 49992cb984SSergei Barannikov /// An Incomplete entry is always a RecordType and only encodes its 50992cb984SSergei Barannikov /// identifier e.g. "s(S){}". Incomplete 'StubEnc' entries are ephemeral and 51992cb984SSergei Barannikov /// are placed into the cache during type expansion as a means to identify and 52992cb984SSergei Barannikov /// handle recursive inclusion of types as sub-members. If there is recursion 53992cb984SSergei Barannikov /// the entry becomes IncompleteUsed. 54992cb984SSergei Barannikov /// 55992cb984SSergei Barannikov /// During the expansion of a RecordType's members: 56992cb984SSergei Barannikov /// 57992cb984SSergei Barannikov /// If the cache contains a NonRecursive encoding for the member type, the 58992cb984SSergei Barannikov /// cached encoding is used; 59992cb984SSergei Barannikov /// 60992cb984SSergei Barannikov /// If the cache contains a Recursive encoding for the member type, the 61992cb984SSergei Barannikov /// cached encoding is 'Swapped' out, as it may be incorrect, and... 62992cb984SSergei Barannikov /// 63992cb984SSergei Barannikov /// If the member is a RecordType, an Incomplete encoding is placed into the 64992cb984SSergei Barannikov /// cache to break potential recursive inclusion of itself as a sub-member; 65992cb984SSergei Barannikov /// 66992cb984SSergei Barannikov /// Once a member RecordType has been expanded, its temporary incomplete 67992cb984SSergei Barannikov /// entry is removed from the cache. If a Recursive encoding was swapped out 68992cb984SSergei Barannikov /// it is swapped back in; 69992cb984SSergei Barannikov /// 70992cb984SSergei Barannikov /// If an incomplete entry is used to expand a sub-member, the incomplete 71992cb984SSergei Barannikov /// entry is marked as IncompleteUsed. The cache keeps count of how many 72992cb984SSergei Barannikov /// IncompleteUsed entries it currently contains in IncompleteUsedCount; 73992cb984SSergei Barannikov /// 74992cb984SSergei Barannikov /// If a member's encoding is found to be a NonRecursive or Recursive viz: 75992cb984SSergei Barannikov /// IncompleteUsedCount==0, the member's encoding is added to the cache. 76992cb984SSergei Barannikov /// Else the member is part of a recursive type and thus the recursion has 77992cb984SSergei Barannikov /// been exited too soon for the encoding to be correct for the member. 78992cb984SSergei Barannikov /// 79992cb984SSergei Barannikov class TypeStringCache { 80992cb984SSergei Barannikov enum Status {NonRecursive, Recursive, Incomplete, IncompleteUsed}; 81992cb984SSergei Barannikov struct Entry { 82992cb984SSergei Barannikov std::string Str; // The encoded TypeString for the type. 83992cb984SSergei Barannikov enum Status State; // Information about the encoding in 'Str'. 84992cb984SSergei Barannikov std::string Swapped; // A temporary place holder for a Recursive encoding 85992cb984SSergei Barannikov // during the expansion of RecordType's members. 86992cb984SSergei Barannikov }; 87992cb984SSergei Barannikov std::map<const IdentifierInfo *, struct Entry> Map; 88992cb984SSergei Barannikov unsigned IncompleteCount; // Number of Incomplete entries in the Map. 89992cb984SSergei Barannikov unsigned IncompleteUsedCount; // Number of IncompleteUsed entries in the Map. 90992cb984SSergei Barannikov public: 91992cb984SSergei Barannikov TypeStringCache() : IncompleteCount(0), IncompleteUsedCount(0) {} 92992cb984SSergei Barannikov void addIncomplete(const IdentifierInfo *ID, std::string StubEnc); 93992cb984SSergei Barannikov bool removeIncomplete(const IdentifierInfo *ID); 94992cb984SSergei Barannikov void addIfComplete(const IdentifierInfo *ID, StringRef Str, 95992cb984SSergei Barannikov bool IsRecursive); 96992cb984SSergei Barannikov StringRef lookupStr(const IdentifierInfo *ID); 97992cb984SSergei Barannikov }; 98992cb984SSergei Barannikov 99992cb984SSergei Barannikov /// TypeString encodings for enum & union fields must be order. 100992cb984SSergei Barannikov /// FieldEncoding is a helper for this ordering process. 101992cb984SSergei Barannikov class FieldEncoding { 102992cb984SSergei Barannikov bool HasName; 103992cb984SSergei Barannikov std::string Enc; 104992cb984SSergei Barannikov public: 105992cb984SSergei Barannikov FieldEncoding(bool b, SmallStringEnc &e) : HasName(b), Enc(e.c_str()) {} 106992cb984SSergei Barannikov StringRef str() { return Enc; } 107992cb984SSergei Barannikov bool operator<(const FieldEncoding &rhs) const { 108992cb984SSergei Barannikov if (HasName != rhs.HasName) return HasName; 109992cb984SSergei Barannikov return Enc < rhs.Enc; 110992cb984SSergei Barannikov } 111992cb984SSergei Barannikov }; 112992cb984SSergei Barannikov 113992cb984SSergei Barannikov class XCoreABIInfo : public DefaultABIInfo { 114992cb984SSergei Barannikov public: 115992cb984SSergei Barannikov XCoreABIInfo(CodeGen::CodeGenTypes &CGT) : DefaultABIInfo(CGT) {} 1166d973b45SMariya Podchishchaeva RValue EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty, 1176d973b45SMariya Podchishchaeva AggValueSlot Slot) const override; 118992cb984SSergei Barannikov }; 119992cb984SSergei Barannikov 120992cb984SSergei Barannikov class XCoreTargetCodeGenInfo : public TargetCodeGenInfo { 121992cb984SSergei Barannikov mutable TypeStringCache TSC; 122992cb984SSergei Barannikov void emitTargetMD(const Decl *D, llvm::GlobalValue *GV, 123992cb984SSergei Barannikov const CodeGen::CodeGenModule &M) const; 124992cb984SSergei Barannikov 125992cb984SSergei Barannikov public: 126992cb984SSergei Barannikov XCoreTargetCodeGenInfo(CodeGenTypes &CGT) 127992cb984SSergei Barannikov : TargetCodeGenInfo(std::make_unique<XCoreABIInfo>(CGT)) {} 128992cb984SSergei Barannikov void emitTargetMetadata(CodeGen::CodeGenModule &CGM, 129992cb984SSergei Barannikov const llvm::MapVector<GlobalDecl, StringRef> 130992cb984SSergei Barannikov &MangledDeclNames) const override; 131992cb984SSergei Barannikov }; 132992cb984SSergei Barannikov 133992cb984SSergei Barannikov } // End anonymous namespace. 134992cb984SSergei Barannikov 135992cb984SSergei Barannikov // TODO: this implementation is likely now redundant with the default 136992cb984SSergei Barannikov // EmitVAArg. 1376d973b45SMariya Podchishchaeva RValue XCoreABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, 1386d973b45SMariya Podchishchaeva QualType Ty, AggValueSlot Slot) const { 139992cb984SSergei Barannikov CGBuilderTy &Builder = CGF.Builder; 140992cb984SSergei Barannikov 141992cb984SSergei Barannikov // Get the VAList. 142992cb984SSergei Barannikov CharUnits SlotSize = CharUnits::fromQuantity(4); 143992cb984SSergei Barannikov Address AP = Address(Builder.CreateLoad(VAListAddr), 144992cb984SSergei Barannikov getVAListElementType(CGF), SlotSize); 145992cb984SSergei Barannikov 146992cb984SSergei Barannikov // Handle the argument. 147992cb984SSergei Barannikov ABIArgInfo AI = classifyArgumentType(Ty); 148992cb984SSergei Barannikov CharUnits TypeAlign = getContext().getTypeAlignInChars(Ty); 149992cb984SSergei Barannikov llvm::Type *ArgTy = CGT.ConvertType(Ty); 150992cb984SSergei Barannikov if (AI.canHaveCoerceToType() && !AI.getCoerceToType()) 151992cb984SSergei Barannikov AI.setCoerceToType(ArgTy); 152992cb984SSergei Barannikov llvm::Type *ArgPtrTy = llvm::PointerType::getUnqual(ArgTy); 153992cb984SSergei Barannikov 154992cb984SSergei Barannikov Address Val = Address::invalid(); 155992cb984SSergei Barannikov CharUnits ArgSize = CharUnits::Zero(); 156992cb984SSergei Barannikov switch (AI.getKind()) { 157992cb984SSergei Barannikov case ABIArgInfo::Expand: 158992cb984SSergei Barannikov case ABIArgInfo::CoerceAndExpand: 159992cb984SSergei Barannikov case ABIArgInfo::InAlloca: 160992cb984SSergei Barannikov llvm_unreachable("Unsupported ABI kind for va_arg"); 161992cb984SSergei Barannikov case ABIArgInfo::Ignore: 162992cb984SSergei Barannikov Val = Address(llvm::UndefValue::get(ArgPtrTy), ArgTy, TypeAlign); 163992cb984SSergei Barannikov ArgSize = CharUnits::Zero(); 164992cb984SSergei Barannikov break; 165992cb984SSergei Barannikov case ABIArgInfo::Extend: 166992cb984SSergei Barannikov case ABIArgInfo::Direct: 1675f32baf1SYoungsuk Kim Val = AP.withElementType(ArgTy); 168992cb984SSergei Barannikov ArgSize = CharUnits::fromQuantity( 169992cb984SSergei Barannikov getDataLayout().getTypeAllocSize(AI.getCoerceToType())); 170992cb984SSergei Barannikov ArgSize = ArgSize.alignTo(SlotSize); 171992cb984SSergei Barannikov break; 172992cb984SSergei Barannikov case ABIArgInfo::Indirect: 173992cb984SSergei Barannikov case ABIArgInfo::IndirectAliased: 1745f32baf1SYoungsuk Kim Val = AP.withElementType(ArgPtrTy); 175992cb984SSergei Barannikov Val = Address(Builder.CreateLoad(Val), ArgTy, TypeAlign); 176992cb984SSergei Barannikov ArgSize = SlotSize; 177992cb984SSergei Barannikov break; 178992cb984SSergei Barannikov } 179992cb984SSergei Barannikov 180992cb984SSergei Barannikov // Increment the VAList. 181992cb984SSergei Barannikov if (!ArgSize.isZero()) { 182992cb984SSergei Barannikov Address APN = Builder.CreateConstInBoundsByteGEP(AP, ArgSize); 18384780af4SAkira Hatanaka Builder.CreateStore(APN.emitRawPointer(CGF), VAListAddr); 184992cb984SSergei Barannikov } 185992cb984SSergei Barannikov 1866d973b45SMariya Podchishchaeva return CGF.EmitLoadOfAnyValue(CGF.MakeAddrLValue(Val, Ty), Slot); 187992cb984SSergei Barannikov } 188992cb984SSergei Barannikov 189992cb984SSergei Barannikov /// During the expansion of a RecordType, an incomplete TypeString is placed 190992cb984SSergei Barannikov /// into the cache as a means to identify and break recursion. 191992cb984SSergei Barannikov /// If there is a Recursive encoding in the cache, it is swapped out and will 192992cb984SSergei Barannikov /// be reinserted by removeIncomplete(). 193992cb984SSergei Barannikov /// All other types of encoding should have been used rather than arriving here. 194992cb984SSergei Barannikov void TypeStringCache::addIncomplete(const IdentifierInfo *ID, 195992cb984SSergei Barannikov std::string StubEnc) { 196992cb984SSergei Barannikov if (!ID) 197992cb984SSergei Barannikov return; 198992cb984SSergei Barannikov Entry &E = Map[ID]; 199992cb984SSergei Barannikov assert( (E.Str.empty() || E.State == Recursive) && 200992cb984SSergei Barannikov "Incorrectly use of addIncomplete"); 201992cb984SSergei Barannikov assert(!StubEnc.empty() && "Passing an empty string to addIncomplete()"); 202992cb984SSergei Barannikov E.Swapped.swap(E.Str); // swap out the Recursive 203992cb984SSergei Barannikov E.Str.swap(StubEnc); 204992cb984SSergei Barannikov E.State = Incomplete; 205992cb984SSergei Barannikov ++IncompleteCount; 206992cb984SSergei Barannikov } 207992cb984SSergei Barannikov 208992cb984SSergei Barannikov /// Once the RecordType has been expanded, the temporary incomplete TypeString 209992cb984SSergei Barannikov /// must be removed from the cache. 210992cb984SSergei Barannikov /// If a Recursive was swapped out by addIncomplete(), it will be replaced. 211992cb984SSergei Barannikov /// Returns true if the RecordType was defined recursively. 212992cb984SSergei Barannikov bool TypeStringCache::removeIncomplete(const IdentifierInfo *ID) { 213992cb984SSergei Barannikov if (!ID) 214992cb984SSergei Barannikov return false; 215992cb984SSergei Barannikov auto I = Map.find(ID); 216992cb984SSergei Barannikov assert(I != Map.end() && "Entry not present"); 217992cb984SSergei Barannikov Entry &E = I->second; 218992cb984SSergei Barannikov assert( (E.State == Incomplete || 219992cb984SSergei Barannikov E.State == IncompleteUsed) && 220992cb984SSergei Barannikov "Entry must be an incomplete type"); 221992cb984SSergei Barannikov bool IsRecursive = false; 222992cb984SSergei Barannikov if (E.State == IncompleteUsed) { 223992cb984SSergei Barannikov // We made use of our Incomplete encoding, thus we are recursive. 224992cb984SSergei Barannikov IsRecursive = true; 225992cb984SSergei Barannikov --IncompleteUsedCount; 226992cb984SSergei Barannikov } 227992cb984SSergei Barannikov if (E.Swapped.empty()) 228992cb984SSergei Barannikov Map.erase(I); 229992cb984SSergei Barannikov else { 230992cb984SSergei Barannikov // Swap the Recursive back. 231992cb984SSergei Barannikov E.Swapped.swap(E.Str); 232992cb984SSergei Barannikov E.Swapped.clear(); 233992cb984SSergei Barannikov E.State = Recursive; 234992cb984SSergei Barannikov } 235992cb984SSergei Barannikov --IncompleteCount; 236992cb984SSergei Barannikov return IsRecursive; 237992cb984SSergei Barannikov } 238992cb984SSergei Barannikov 239992cb984SSergei Barannikov /// Add the encoded TypeString to the cache only if it is NonRecursive or 240992cb984SSergei Barannikov /// Recursive (viz: all sub-members were expanded as fully as possible). 241992cb984SSergei Barannikov void TypeStringCache::addIfComplete(const IdentifierInfo *ID, StringRef Str, 242992cb984SSergei Barannikov bool IsRecursive) { 243992cb984SSergei Barannikov if (!ID || IncompleteUsedCount) 244992cb984SSergei Barannikov return; // No key or it is an incomplete sub-type so don't add. 245992cb984SSergei Barannikov Entry &E = Map[ID]; 246992cb984SSergei Barannikov if (IsRecursive && !E.Str.empty()) { 247992cb984SSergei Barannikov assert(E.State==Recursive && E.Str.size() == Str.size() && 248992cb984SSergei Barannikov "This is not the same Recursive entry"); 249992cb984SSergei Barannikov // The parent container was not recursive after all, so we could have used 250992cb984SSergei Barannikov // this Recursive sub-member entry after all, but we assumed the worse when 251992cb984SSergei Barannikov // we started viz: IncompleteCount!=0. 252992cb984SSergei Barannikov return; 253992cb984SSergei Barannikov } 254992cb984SSergei Barannikov assert(E.Str.empty() && "Entry already present"); 255992cb984SSergei Barannikov E.Str = Str.str(); 256992cb984SSergei Barannikov E.State = IsRecursive? Recursive : NonRecursive; 257992cb984SSergei Barannikov } 258992cb984SSergei Barannikov 259992cb984SSergei Barannikov /// Return a cached TypeString encoding for the ID. If there isn't one, or we 260992cb984SSergei Barannikov /// are recursively expanding a type (IncompleteCount != 0) and the cached 261992cb984SSergei Barannikov /// encoding is Recursive, return an empty StringRef. 262992cb984SSergei Barannikov StringRef TypeStringCache::lookupStr(const IdentifierInfo *ID) { 263992cb984SSergei Barannikov if (!ID) 264992cb984SSergei Barannikov return StringRef(); // We have no key. 265992cb984SSergei Barannikov auto I = Map.find(ID); 266992cb984SSergei Barannikov if (I == Map.end()) 267992cb984SSergei Barannikov return StringRef(); // We have no encoding. 268992cb984SSergei Barannikov Entry &E = I->second; 269992cb984SSergei Barannikov if (E.State == Recursive && IncompleteCount) 270992cb984SSergei Barannikov return StringRef(); // We don't use Recursive encodings for member types. 271992cb984SSergei Barannikov 272992cb984SSergei Barannikov if (E.State == Incomplete) { 273992cb984SSergei Barannikov // The incomplete type is being used to break out of recursion. 274992cb984SSergei Barannikov E.State = IncompleteUsed; 275992cb984SSergei Barannikov ++IncompleteUsedCount; 276992cb984SSergei Barannikov } 277992cb984SSergei Barannikov return E.Str; 278992cb984SSergei Barannikov } 279992cb984SSergei Barannikov 280992cb984SSergei Barannikov /// The XCore ABI includes a type information section that communicates symbol 281992cb984SSergei Barannikov /// type information to the linker. The linker uses this information to verify 282992cb984SSergei Barannikov /// safety/correctness of things such as array bound and pointers et al. 283992cb984SSergei Barannikov /// The ABI only requires C (and XC) language modules to emit TypeStrings. 284992cb984SSergei Barannikov /// This type information (TypeString) is emitted into meta data for all global 285992cb984SSergei Barannikov /// symbols: definitions, declarations, functions & variables. 286992cb984SSergei Barannikov /// 287992cb984SSergei Barannikov /// The TypeString carries type, qualifier, name, size & value details. 288992cb984SSergei Barannikov /// Please see 'Tools Development Guide' section 2.16.2 for format details: 289992cb984SSergei Barannikov /// https://www.xmos.com/download/public/Tools-Development-Guide%28X9114A%29.pdf 290992cb984SSergei Barannikov /// The output is tested by test/CodeGen/xcore-stringtype.c. 291992cb984SSergei Barannikov /// 292992cb984SSergei Barannikov static bool getTypeString(SmallStringEnc &Enc, const Decl *D, 293992cb984SSergei Barannikov const CodeGen::CodeGenModule &CGM, 294992cb984SSergei Barannikov TypeStringCache &TSC); 295992cb984SSergei Barannikov 296992cb984SSergei Barannikov /// XCore uses emitTargetMD to emit TypeString metadata for global symbols. 297992cb984SSergei Barannikov void XCoreTargetCodeGenInfo::emitTargetMD( 298992cb984SSergei Barannikov const Decl *D, llvm::GlobalValue *GV, 299992cb984SSergei Barannikov const CodeGen::CodeGenModule &CGM) const { 300992cb984SSergei Barannikov SmallStringEnc Enc; 301992cb984SSergei Barannikov if (getTypeString(Enc, D, CGM, TSC)) { 302992cb984SSergei Barannikov llvm::LLVMContext &Ctx = CGM.getModule().getContext(); 303992cb984SSergei Barannikov llvm::Metadata *MDVals[] = {llvm::ConstantAsMetadata::get(GV), 304992cb984SSergei Barannikov llvm::MDString::get(Ctx, Enc.str())}; 305992cb984SSergei Barannikov llvm::NamedMDNode *MD = 306992cb984SSergei Barannikov CGM.getModule().getOrInsertNamedMetadata("xcore.typestrings"); 307992cb984SSergei Barannikov MD->addOperand(llvm::MDNode::get(Ctx, MDVals)); 308992cb984SSergei Barannikov } 309992cb984SSergei Barannikov } 310992cb984SSergei Barannikov 311992cb984SSergei Barannikov void XCoreTargetCodeGenInfo::emitTargetMetadata( 312992cb984SSergei Barannikov CodeGen::CodeGenModule &CGM, 313992cb984SSergei Barannikov const llvm::MapVector<GlobalDecl, StringRef> &MangledDeclNames) const { 314992cb984SSergei Barannikov // Warning, new MangledDeclNames may be appended within this loop. 315992cb984SSergei Barannikov // We rely on MapVector insertions adding new elements to the end 316992cb984SSergei Barannikov // of the container. 317992cb984SSergei Barannikov for (unsigned I = 0; I != MangledDeclNames.size(); ++I) { 318992cb984SSergei Barannikov auto Val = *(MangledDeclNames.begin() + I); 319992cb984SSergei Barannikov llvm::GlobalValue *GV = CGM.GetGlobalValue(Val.second); 320992cb984SSergei Barannikov if (GV) { 321992cb984SSergei Barannikov const Decl *D = Val.first.getDecl()->getMostRecentDecl(); 322992cb984SSergei Barannikov emitTargetMD(D, GV, CGM); 323992cb984SSergei Barannikov } 324992cb984SSergei Barannikov } 325992cb984SSergei Barannikov } 326992cb984SSergei Barannikov 327992cb984SSergei Barannikov static bool appendType(SmallStringEnc &Enc, QualType QType, 328992cb984SSergei Barannikov const CodeGen::CodeGenModule &CGM, 329992cb984SSergei Barannikov TypeStringCache &TSC); 330992cb984SSergei Barannikov 331992cb984SSergei Barannikov /// Helper function for appendRecordType(). 332992cb984SSergei Barannikov /// Builds a SmallVector containing the encoded field types in declaration 333992cb984SSergei Barannikov /// order. 334992cb984SSergei Barannikov static bool extractFieldType(SmallVectorImpl<FieldEncoding> &FE, 335992cb984SSergei Barannikov const RecordDecl *RD, 336992cb984SSergei Barannikov const CodeGen::CodeGenModule &CGM, 337992cb984SSergei Barannikov TypeStringCache &TSC) { 338992cb984SSergei Barannikov for (const auto *Field : RD->fields()) { 339992cb984SSergei Barannikov SmallStringEnc Enc; 340992cb984SSergei Barannikov Enc += "m("; 341992cb984SSergei Barannikov Enc += Field->getName(); 342992cb984SSergei Barannikov Enc += "){"; 343992cb984SSergei Barannikov if (Field->isBitField()) { 344992cb984SSergei Barannikov Enc += "b("; 345992cb984SSergei Barannikov llvm::raw_svector_ostream OS(Enc); 346*cfe26358STimm Baeder OS << Field->getBitWidthValue(); 347992cb984SSergei Barannikov Enc += ':'; 348992cb984SSergei Barannikov } 349992cb984SSergei Barannikov if (!appendType(Enc, Field->getType(), CGM, TSC)) 350992cb984SSergei Barannikov return false; 351992cb984SSergei Barannikov if (Field->isBitField()) 352992cb984SSergei Barannikov Enc += ')'; 353992cb984SSergei Barannikov Enc += '}'; 354992cb984SSergei Barannikov FE.emplace_back(!Field->getName().empty(), Enc); 355992cb984SSergei Barannikov } 356992cb984SSergei Barannikov return true; 357992cb984SSergei Barannikov } 358992cb984SSergei Barannikov 359992cb984SSergei Barannikov /// Appends structure and union types to Enc and adds encoding to cache. 360992cb984SSergei Barannikov /// Recursively calls appendType (via extractFieldType) for each field. 361992cb984SSergei Barannikov /// Union types have their fields ordered according to the ABI. 362992cb984SSergei Barannikov static bool appendRecordType(SmallStringEnc &Enc, const RecordType *RT, 363992cb984SSergei Barannikov const CodeGen::CodeGenModule &CGM, 364992cb984SSergei Barannikov TypeStringCache &TSC, const IdentifierInfo *ID) { 365992cb984SSergei Barannikov // Append the cached TypeString if we have one. 366992cb984SSergei Barannikov StringRef TypeString = TSC.lookupStr(ID); 367992cb984SSergei Barannikov if (!TypeString.empty()) { 368992cb984SSergei Barannikov Enc += TypeString; 369992cb984SSergei Barannikov return true; 370992cb984SSergei Barannikov } 371992cb984SSergei Barannikov 372992cb984SSergei Barannikov // Start to emit an incomplete TypeString. 373992cb984SSergei Barannikov size_t Start = Enc.size(); 374992cb984SSergei Barannikov Enc += (RT->isUnionType()? 'u' : 's'); 375992cb984SSergei Barannikov Enc += '('; 376992cb984SSergei Barannikov if (ID) 377992cb984SSergei Barannikov Enc += ID->getName(); 378992cb984SSergei Barannikov Enc += "){"; 379992cb984SSergei Barannikov 380992cb984SSergei Barannikov // We collect all encoded fields and order as necessary. 381992cb984SSergei Barannikov bool IsRecursive = false; 382992cb984SSergei Barannikov const RecordDecl *RD = RT->getDecl()->getDefinition(); 383992cb984SSergei Barannikov if (RD && !RD->field_empty()) { 384992cb984SSergei Barannikov // An incomplete TypeString stub is placed in the cache for this RecordType 385992cb984SSergei Barannikov // so that recursive calls to this RecordType will use it whilst building a 386992cb984SSergei Barannikov // complete TypeString for this RecordType. 387992cb984SSergei Barannikov SmallVector<FieldEncoding, 16> FE; 388992cb984SSergei Barannikov std::string StubEnc(Enc.substr(Start).str()); 389992cb984SSergei Barannikov StubEnc += '}'; // StubEnc now holds a valid incomplete TypeString. 390992cb984SSergei Barannikov TSC.addIncomplete(ID, std::move(StubEnc)); 391992cb984SSergei Barannikov if (!extractFieldType(FE, RD, CGM, TSC)) { 392992cb984SSergei Barannikov (void) TSC.removeIncomplete(ID); 393992cb984SSergei Barannikov return false; 394992cb984SSergei Barannikov } 395992cb984SSergei Barannikov IsRecursive = TSC.removeIncomplete(ID); 396992cb984SSergei Barannikov // The ABI requires unions to be sorted but not structures. 397992cb984SSergei Barannikov // See FieldEncoding::operator< for sort algorithm. 398992cb984SSergei Barannikov if (RT->isUnionType()) 399992cb984SSergei Barannikov llvm::sort(FE); 400992cb984SSergei Barannikov // We can now complete the TypeString. 401992cb984SSergei Barannikov unsigned E = FE.size(); 402992cb984SSergei Barannikov for (unsigned I = 0; I != E; ++I) { 403992cb984SSergei Barannikov if (I) 404992cb984SSergei Barannikov Enc += ','; 405992cb984SSergei Barannikov Enc += FE[I].str(); 406992cb984SSergei Barannikov } 407992cb984SSergei Barannikov } 408992cb984SSergei Barannikov Enc += '}'; 409992cb984SSergei Barannikov TSC.addIfComplete(ID, Enc.substr(Start), IsRecursive); 410992cb984SSergei Barannikov return true; 411992cb984SSergei Barannikov } 412992cb984SSergei Barannikov 413992cb984SSergei Barannikov /// Appends enum types to Enc and adds the encoding to the cache. 414992cb984SSergei Barannikov static bool appendEnumType(SmallStringEnc &Enc, const EnumType *ET, 415992cb984SSergei Barannikov TypeStringCache &TSC, 416992cb984SSergei Barannikov const IdentifierInfo *ID) { 417992cb984SSergei Barannikov // Append the cached TypeString if we have one. 418992cb984SSergei Barannikov StringRef TypeString = TSC.lookupStr(ID); 419992cb984SSergei Barannikov if (!TypeString.empty()) { 420992cb984SSergei Barannikov Enc += TypeString; 421992cb984SSergei Barannikov return true; 422992cb984SSergei Barannikov } 423992cb984SSergei Barannikov 424992cb984SSergei Barannikov size_t Start = Enc.size(); 425992cb984SSergei Barannikov Enc += "e("; 426992cb984SSergei Barannikov if (ID) 427992cb984SSergei Barannikov Enc += ID->getName(); 428992cb984SSergei Barannikov Enc += "){"; 429992cb984SSergei Barannikov 430992cb984SSergei Barannikov // We collect all encoded enumerations and order them alphanumerically. 431992cb984SSergei Barannikov if (const EnumDecl *ED = ET->getDecl()->getDefinition()) { 432992cb984SSergei Barannikov SmallVector<FieldEncoding, 16> FE; 433992cb984SSergei Barannikov for (auto I = ED->enumerator_begin(), E = ED->enumerator_end(); I != E; 434992cb984SSergei Barannikov ++I) { 435992cb984SSergei Barannikov SmallStringEnc EnumEnc; 436992cb984SSergei Barannikov EnumEnc += "m("; 437992cb984SSergei Barannikov EnumEnc += I->getName(); 438992cb984SSergei Barannikov EnumEnc += "){"; 439992cb984SSergei Barannikov I->getInitVal().toString(EnumEnc); 440992cb984SSergei Barannikov EnumEnc += '}'; 441992cb984SSergei Barannikov FE.push_back(FieldEncoding(!I->getName().empty(), EnumEnc)); 442992cb984SSergei Barannikov } 443992cb984SSergei Barannikov llvm::sort(FE); 444992cb984SSergei Barannikov unsigned E = FE.size(); 445992cb984SSergei Barannikov for (unsigned I = 0; I != E; ++I) { 446992cb984SSergei Barannikov if (I) 447992cb984SSergei Barannikov Enc += ','; 448992cb984SSergei Barannikov Enc += FE[I].str(); 449992cb984SSergei Barannikov } 450992cb984SSergei Barannikov } 451992cb984SSergei Barannikov Enc += '}'; 452992cb984SSergei Barannikov TSC.addIfComplete(ID, Enc.substr(Start), false); 453992cb984SSergei Barannikov return true; 454992cb984SSergei Barannikov } 455992cb984SSergei Barannikov 456992cb984SSergei Barannikov /// Appends type's qualifier to Enc. 457992cb984SSergei Barannikov /// This is done prior to appending the type's encoding. 458992cb984SSergei Barannikov static void appendQualifier(SmallStringEnc &Enc, QualType QT) { 459992cb984SSergei Barannikov // Qualifiers are emitted in alphabetical order. 460992cb984SSergei Barannikov static const char *const Table[]={"","c:","r:","cr:","v:","cv:","rv:","crv:"}; 461992cb984SSergei Barannikov int Lookup = 0; 462992cb984SSergei Barannikov if (QT.isConstQualified()) 463992cb984SSergei Barannikov Lookup += 1<<0; 464992cb984SSergei Barannikov if (QT.isRestrictQualified()) 465992cb984SSergei Barannikov Lookup += 1<<1; 466992cb984SSergei Barannikov if (QT.isVolatileQualified()) 467992cb984SSergei Barannikov Lookup += 1<<2; 468992cb984SSergei Barannikov Enc += Table[Lookup]; 469992cb984SSergei Barannikov } 470992cb984SSergei Barannikov 471992cb984SSergei Barannikov /// Appends built-in types to Enc. 472992cb984SSergei Barannikov static bool appendBuiltinType(SmallStringEnc &Enc, const BuiltinType *BT) { 473992cb984SSergei Barannikov const char *EncType; 474992cb984SSergei Barannikov switch (BT->getKind()) { 475992cb984SSergei Barannikov case BuiltinType::Void: 476992cb984SSergei Barannikov EncType = "0"; 477992cb984SSergei Barannikov break; 478992cb984SSergei Barannikov case BuiltinType::Bool: 479992cb984SSergei Barannikov EncType = "b"; 480992cb984SSergei Barannikov break; 481992cb984SSergei Barannikov case BuiltinType::Char_U: 482992cb984SSergei Barannikov EncType = "uc"; 483992cb984SSergei Barannikov break; 484992cb984SSergei Barannikov case BuiltinType::UChar: 485992cb984SSergei Barannikov EncType = "uc"; 486992cb984SSergei Barannikov break; 487992cb984SSergei Barannikov case BuiltinType::SChar: 488992cb984SSergei Barannikov EncType = "sc"; 489992cb984SSergei Barannikov break; 490992cb984SSergei Barannikov case BuiltinType::UShort: 491992cb984SSergei Barannikov EncType = "us"; 492992cb984SSergei Barannikov break; 493992cb984SSergei Barannikov case BuiltinType::Short: 494992cb984SSergei Barannikov EncType = "ss"; 495992cb984SSergei Barannikov break; 496992cb984SSergei Barannikov case BuiltinType::UInt: 497992cb984SSergei Barannikov EncType = "ui"; 498992cb984SSergei Barannikov break; 499992cb984SSergei Barannikov case BuiltinType::Int: 500992cb984SSergei Barannikov EncType = "si"; 501992cb984SSergei Barannikov break; 502992cb984SSergei Barannikov case BuiltinType::ULong: 503992cb984SSergei Barannikov EncType = "ul"; 504992cb984SSergei Barannikov break; 505992cb984SSergei Barannikov case BuiltinType::Long: 506992cb984SSergei Barannikov EncType = "sl"; 507992cb984SSergei Barannikov break; 508992cb984SSergei Barannikov case BuiltinType::ULongLong: 509992cb984SSergei Barannikov EncType = "ull"; 510992cb984SSergei Barannikov break; 511992cb984SSergei Barannikov case BuiltinType::LongLong: 512992cb984SSergei Barannikov EncType = "sll"; 513992cb984SSergei Barannikov break; 514992cb984SSergei Barannikov case BuiltinType::Float: 515992cb984SSergei Barannikov EncType = "ft"; 516992cb984SSergei Barannikov break; 517992cb984SSergei Barannikov case BuiltinType::Double: 518992cb984SSergei Barannikov EncType = "d"; 519992cb984SSergei Barannikov break; 520992cb984SSergei Barannikov case BuiltinType::LongDouble: 521992cb984SSergei Barannikov EncType = "ld"; 522992cb984SSergei Barannikov break; 523992cb984SSergei Barannikov default: 524992cb984SSergei Barannikov return false; 525992cb984SSergei Barannikov } 526992cb984SSergei Barannikov Enc += EncType; 527992cb984SSergei Barannikov return true; 528992cb984SSergei Barannikov } 529992cb984SSergei Barannikov 530992cb984SSergei Barannikov /// Appends a pointer encoding to Enc before calling appendType for the pointee. 531992cb984SSergei Barannikov static bool appendPointerType(SmallStringEnc &Enc, const PointerType *PT, 532992cb984SSergei Barannikov const CodeGen::CodeGenModule &CGM, 533992cb984SSergei Barannikov TypeStringCache &TSC) { 534992cb984SSergei Barannikov Enc += "p("; 535992cb984SSergei Barannikov if (!appendType(Enc, PT->getPointeeType(), CGM, TSC)) 536992cb984SSergei Barannikov return false; 537992cb984SSergei Barannikov Enc += ')'; 538992cb984SSergei Barannikov return true; 539992cb984SSergei Barannikov } 540992cb984SSergei Barannikov 541992cb984SSergei Barannikov /// Appends array encoding to Enc before calling appendType for the element. 542992cb984SSergei Barannikov static bool appendArrayType(SmallStringEnc &Enc, QualType QT, 543992cb984SSergei Barannikov const ArrayType *AT, 544992cb984SSergei Barannikov const CodeGen::CodeGenModule &CGM, 545992cb984SSergei Barannikov TypeStringCache &TSC, StringRef NoSizeEnc) { 54649fd28d9SVlad Serebrennikov if (AT->getSizeModifier() != ArraySizeModifier::Normal) 547992cb984SSergei Barannikov return false; 548992cb984SSergei Barannikov Enc += "a("; 549992cb984SSergei Barannikov if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(AT)) 550992cb984SSergei Barannikov CAT->getSize().toStringUnsigned(Enc); 551992cb984SSergei Barannikov else 552992cb984SSergei Barannikov Enc += NoSizeEnc; // Global arrays use "*", otherwise it is "". 553992cb984SSergei Barannikov Enc += ':'; 554992cb984SSergei Barannikov // The Qualifiers should be attached to the type rather than the array. 555992cb984SSergei Barannikov appendQualifier(Enc, QT); 556992cb984SSergei Barannikov if (!appendType(Enc, AT->getElementType(), CGM, TSC)) 557992cb984SSergei Barannikov return false; 558992cb984SSergei Barannikov Enc += ')'; 559992cb984SSergei Barannikov return true; 560992cb984SSergei Barannikov } 561992cb984SSergei Barannikov 562992cb984SSergei Barannikov /// Appends a function encoding to Enc, calling appendType for the return type 563992cb984SSergei Barannikov /// and the arguments. 564992cb984SSergei Barannikov static bool appendFunctionType(SmallStringEnc &Enc, const FunctionType *FT, 565992cb984SSergei Barannikov const CodeGen::CodeGenModule &CGM, 566992cb984SSergei Barannikov TypeStringCache &TSC) { 567992cb984SSergei Barannikov Enc += "f{"; 568992cb984SSergei Barannikov if (!appendType(Enc, FT->getReturnType(), CGM, TSC)) 569992cb984SSergei Barannikov return false; 570992cb984SSergei Barannikov Enc += "}("; 571992cb984SSergei Barannikov if (const FunctionProtoType *FPT = FT->getAs<FunctionProtoType>()) { 572992cb984SSergei Barannikov // N.B. we are only interested in the adjusted param types. 573992cb984SSergei Barannikov auto I = FPT->param_type_begin(); 574992cb984SSergei Barannikov auto E = FPT->param_type_end(); 575992cb984SSergei Barannikov if (I != E) { 576992cb984SSergei Barannikov do { 577992cb984SSergei Barannikov if (!appendType(Enc, *I, CGM, TSC)) 578992cb984SSergei Barannikov return false; 579992cb984SSergei Barannikov ++I; 580992cb984SSergei Barannikov if (I != E) 581992cb984SSergei Barannikov Enc += ','; 582992cb984SSergei Barannikov } while (I != E); 583992cb984SSergei Barannikov if (FPT->isVariadic()) 584992cb984SSergei Barannikov Enc += ",va"; 585992cb984SSergei Barannikov } else { 586992cb984SSergei Barannikov if (FPT->isVariadic()) 587992cb984SSergei Barannikov Enc += "va"; 588992cb984SSergei Barannikov else 589992cb984SSergei Barannikov Enc += '0'; 590992cb984SSergei Barannikov } 591992cb984SSergei Barannikov } 592992cb984SSergei Barannikov Enc += ')'; 593992cb984SSergei Barannikov return true; 594992cb984SSergei Barannikov } 595992cb984SSergei Barannikov 596992cb984SSergei Barannikov /// Handles the type's qualifier before dispatching a call to handle specific 597992cb984SSergei Barannikov /// type encodings. 598992cb984SSergei Barannikov static bool appendType(SmallStringEnc &Enc, QualType QType, 599992cb984SSergei Barannikov const CodeGen::CodeGenModule &CGM, 600992cb984SSergei Barannikov TypeStringCache &TSC) { 601992cb984SSergei Barannikov 602992cb984SSergei Barannikov QualType QT = QType.getCanonicalType(); 603992cb984SSergei Barannikov 604992cb984SSergei Barannikov if (const ArrayType *AT = QT->getAsArrayTypeUnsafe()) 605992cb984SSergei Barannikov // The Qualifiers should be attached to the type rather than the array. 606992cb984SSergei Barannikov // Thus we don't call appendQualifier() here. 607992cb984SSergei Barannikov return appendArrayType(Enc, QT, AT, CGM, TSC, ""); 608992cb984SSergei Barannikov 609992cb984SSergei Barannikov appendQualifier(Enc, QT); 610992cb984SSergei Barannikov 611992cb984SSergei Barannikov if (const BuiltinType *BT = QT->getAs<BuiltinType>()) 612992cb984SSergei Barannikov return appendBuiltinType(Enc, BT); 613992cb984SSergei Barannikov 614992cb984SSergei Barannikov if (const PointerType *PT = QT->getAs<PointerType>()) 615992cb984SSergei Barannikov return appendPointerType(Enc, PT, CGM, TSC); 616992cb984SSergei Barannikov 617992cb984SSergei Barannikov if (const EnumType *ET = QT->getAs<EnumType>()) 618992cb984SSergei Barannikov return appendEnumType(Enc, ET, TSC, QT.getBaseTypeIdentifier()); 619992cb984SSergei Barannikov 620992cb984SSergei Barannikov if (const RecordType *RT = QT->getAsStructureType()) 621992cb984SSergei Barannikov return appendRecordType(Enc, RT, CGM, TSC, QT.getBaseTypeIdentifier()); 622992cb984SSergei Barannikov 623992cb984SSergei Barannikov if (const RecordType *RT = QT->getAsUnionType()) 624992cb984SSergei Barannikov return appendRecordType(Enc, RT, CGM, TSC, QT.getBaseTypeIdentifier()); 625992cb984SSergei Barannikov 626992cb984SSergei Barannikov if (const FunctionType *FT = QT->getAs<FunctionType>()) 627992cb984SSergei Barannikov return appendFunctionType(Enc, FT, CGM, TSC); 628992cb984SSergei Barannikov 629992cb984SSergei Barannikov return false; 630992cb984SSergei Barannikov } 631992cb984SSergei Barannikov 632992cb984SSergei Barannikov static bool getTypeString(SmallStringEnc &Enc, const Decl *D, 633992cb984SSergei Barannikov const CodeGen::CodeGenModule &CGM, 634992cb984SSergei Barannikov TypeStringCache &TSC) { 635992cb984SSergei Barannikov if (!D) 636992cb984SSergei Barannikov return false; 637992cb984SSergei Barannikov 638992cb984SSergei Barannikov if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { 639992cb984SSergei Barannikov if (FD->getLanguageLinkage() != CLanguageLinkage) 640992cb984SSergei Barannikov return false; 641992cb984SSergei Barannikov return appendType(Enc, FD->getType(), CGM, TSC); 642992cb984SSergei Barannikov } 643992cb984SSergei Barannikov 644992cb984SSergei Barannikov if (const VarDecl *VD = dyn_cast<VarDecl>(D)) { 645992cb984SSergei Barannikov if (VD->getLanguageLinkage() != CLanguageLinkage) 646992cb984SSergei Barannikov return false; 647992cb984SSergei Barannikov QualType QT = VD->getType().getCanonicalType(); 648992cb984SSergei Barannikov if (const ArrayType *AT = QT->getAsArrayTypeUnsafe()) { 649992cb984SSergei Barannikov // Global ArrayTypes are given a size of '*' if the size is unknown. 650992cb984SSergei Barannikov // The Qualifiers should be attached to the type rather than the array. 651992cb984SSergei Barannikov // Thus we don't call appendQualifier() here. 652992cb984SSergei Barannikov return appendArrayType(Enc, QT, AT, CGM, TSC, "*"); 653992cb984SSergei Barannikov } 654992cb984SSergei Barannikov return appendType(Enc, QT, CGM, TSC); 655992cb984SSergei Barannikov } 656992cb984SSergei Barannikov return false; 657992cb984SSergei Barannikov } 658992cb984SSergei Barannikov 659992cb984SSergei Barannikov std::unique_ptr<TargetCodeGenInfo> 660992cb984SSergei Barannikov CodeGen::createXCoreTargetCodeGenInfo(CodeGenModule &CGM) { 661992cb984SSergei Barannikov return std::make_unique<XCoreTargetCodeGenInfo>(CGM.getTypes()); 662992cb984SSergei Barannikov } 663