Thanks. The patch looks good, it's probably best to commit and see if the bot has anything else to say after that.
On Tue, May 6, 2014 at 1:30 PM, Robert Lytton <[email protected]> wrote: > Hi Evgeniy, > > Thank you. > Here is the suggested patch to fix: > > diff --git a/lib/CodeGen/TargetInfo.cpp b/lib/CodeGen/TargetInfo.cpp > index 296a514..76c68f0 100644 > --- a/lib/CodeGen/TargetInfo.cpp > +++ b/lib/CodeGen/TargetInfo.cpp > @@ -6181,6 +6181,7 @@ class TypeStringCache { > 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, > > I have not added a unit test as I am unsure how to - running memorysanitizer > seems the best test. > > Robert > > ________________________________________ > From: Evgeniy Stepanov [[email protected]] > Sent: 06 May 2014 08:30 > To: Robert Lytton > Cc: [email protected] > Subject: Re: r207832 - XCore target: Add TypeString meta data to IR output. > > Hi, > > this change broke MSan bot. > http://lab.llvm.org:8011/builders/sanitizer-x86_64-linux-bootstrap/builds/3242 > > IncompleteUsedCount is never initialized. > > > On Fri, May 2, 2014 at 1:33 PM, Robert Lytton <[email protected]> wrote: >> Author: rlytton >> Date: Fri May 2 04:33:20 2014 >> New Revision: 207832 >> >> URL: http://llvm.org/viewvc/llvm-project?rev=207832&view=rev >> Log: >> XCore target: Add TypeString meta data to IR output. >> >> This includes the addition of the virtual function: >> TargetCodeGenInfo::EmitTargetMD() >> >> Added: >> cfe/trunk/test/CodeGen/xcore-stringtype.c >> Modified: >> cfe/trunk/lib/CodeGen/CodeGenModule.cpp >> cfe/trunk/lib/CodeGen/TargetInfo.cpp >> cfe/trunk/lib/CodeGen/TargetInfo.h >> >> Modified: cfe/trunk/lib/CodeGen/CodeGenModule.cpp >> URL: >> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenModule.cpp?rev=207832&r1=207831&r2=207832&view=diff >> ============================================================================== >> --- cfe/trunk/lib/CodeGen/CodeGenModule.cpp (original) >> +++ cfe/trunk/lib/CodeGen/CodeGenModule.cpp Fri May 2 04:33:20 2014 >> @@ -1463,6 +1463,8 @@ CodeGenModule::GetOrCreateLLVMFunction(S >> } >> } >> >> + getTargetCodeGenInfo().emitTargetMD(D, F, *this); >> + >> // Make sure the result is of the requested type. >> if (!IsIncompleteFunction) { >> assert(F->getType()->getElementType() == Ty); >> @@ -1616,6 +1618,8 @@ CodeGenModule::GetOrCreateLLVMGlobal(Str >> isExternallyVisible(D->getLinkageAndVisibility().getLinkage())) >> GV->setSection(".cp.rodata"); >> >> + getTargetCodeGenInfo().emitTargetMD(D, GV, *this); >> + >> return GV; >> } >> >> >> Modified: cfe/trunk/lib/CodeGen/TargetInfo.cpp >> URL: >> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/TargetInfo.cpp?rev=207832&r1=207831&r2=207832&view=diff >> ============================================================================== >> --- cfe/trunk/lib/CodeGen/TargetInfo.cpp (original) >> +++ cfe/trunk/lib/CodeGen/TargetInfo.cpp Fri May 2 04:33:20 2014 >> @@ -23,6 +23,9 @@ >> #include "llvm/IR/DataLayout.h" >> #include "llvm/IR/Type.h" >> #include "llvm/Support/raw_ostream.h" >> + >> +#include <algorithm> // std::sort >> + >> using namespace clang; >> using namespace CodeGen; >> >> @@ -6105,7 +6108,100 @@ SparcV9TargetCodeGenInfo::initDwarfEHReg >> >> //===----------------------------------------------------------------------===// >> // 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: >> + 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 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.c_str();}; >> + 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) {} >> @@ -6114,10 +6210,14 @@ public: >> }; >> >> class XCoreTargetCodeGenInfo : public TargetCodeGenInfo { >> + mutable TypeStringCache TSC; >> public: >> XCoreTargetCodeGenInfo(CodeGenTypes &CGT) >> :TargetCodeGenInfo(new XCoreABIInfo(CGT)) {} >> + virtual void emitTargetMD(const Decl *D, llvm::GlobalValue *GV, >> + CodeGen::CodeGenModule &M) const; >> }; >> + >> } // End anonymous namespace. >> >> llvm::Value *XCoreABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty, >> @@ -6169,6 +6269,448 @@ llvm::Value *XCoreABIInfo::EmitVAArg(llv >> 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 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.c_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, >> + CodeGen::CodeGenModule &CGM, TypeStringCache >> &TSC); >> + >> +/// XCore uses emitTargetMD to emit TypeString metadata for global symbols. >> +void XCoreTargetCodeGenInfo::emitTargetMD(const Decl *D, llvm::GlobalValue >> *GV, >> + CodeGen::CodeGenModule &CGM) >> const { >> + SmallStringEnc Enc; >> + if (getTypeString(Enc, D, CGM, TSC)) { >> + llvm::LLVMContext &Ctx = CGM.getModule().getContext(); >> + llvm::SmallVector<llvm::Value *, 2> MDVals; >> + MDVals.push_back(GV); >> + MDVals.push_back(llvm::MDString::get(Ctx, Enc.str())); >> + llvm::NamedMDNode *MD = >> + CGM.getModule().getOrInsertNamedMetadata("xcore.typestrings"); >> + MD->addOperand(llvm::MDNode::get(Ctx, MDVals)); >> + } >> +} >> + >> +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 (RecordDecl::field_iterator I = RD->field_begin(), E = >> RD->field_end(); >> + I != E; ++I) { >> + SmallStringEnc Enc; >> + Enc += "m("; >> + Enc += I->getName(); >> + Enc += "){"; >> + if (I->isBitField()) { >> + Enc += "b("; >> + llvm::raw_svector_ostream OS(Enc); >> + OS.resync(); >> + OS << I->getBitWidthValue(CGM.getContext()); >> + OS.flush(); >> + Enc += ':'; >> + } >> + if (!appendType(Enc, I->getType(), CGM, TSC)) >> + return false; >> + if (I->isBitField()) >> + Enc += ')'; >> + Enc += '}'; >> + FE.push_back(FieldEncoding(!I->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; >> + SmallVector<FieldEncoding, 16> FE; >> + 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. >> + 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()) >> + std::sort(FE.begin(), FE.end()); >> + } >> + >> + // We can now complete the TypeString. >> + if (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 += "){"; >> + if (const EnumDecl *ED = ET->getDecl()->getDefinition()) { >> + auto I = ED->enumerator_begin(); >> + auto E = ED->enumerator_end(); >> + while (I != E) { >> + Enc += "m("; >> + Enc += I->getName(); >> + Enc += "){"; >> + I->getInitVal().toString(Enc); >> + Enc += '}'; >> + ++I; >> + if (I != E) >> + Enc += ','; >> + } >> + } >> + 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 *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, const ArrayType *AT, >> + const CodeGen::CodeGenModule &CGM, >> + TypeStringCache &TSC, StringRef NoSizeEnc) { >> + if (AT->getSizeModifier() != ArrayType::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 += ':'; >> + 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(); >> + >> + appendQualifier(Enc, QT); >> + >> + if (const BuiltinType *BT = QT->getAs<BuiltinType>()) >> + return appendBuiltinType(Enc, BT); >> + >> + if (const ArrayType *AT = QT->getAsArrayTypeUnsafe()) >> + return appendArrayType(Enc, AT, CGM, TSC, ""); >> + >> + 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, >> + 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. >> + appendQualifier(Enc, QT); >> + return appendArrayType(Enc, AT, CGM, TSC, "*"); >> + } >> + return appendType(Enc, QT, CGM, TSC); >> + } >> + return false; >> +} >> + >> + >> >> //===----------------------------------------------------------------------===// >> // Driver code >> >> //===----------------------------------------------------------------------===// >> >> Modified: cfe/trunk/lib/CodeGen/TargetInfo.h >> URL: >> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/TargetInfo.h?rev=207832&r1=207831&r2=207832&view=diff >> ============================================================================== >> --- cfe/trunk/lib/CodeGen/TargetInfo.h (original) >> +++ cfe/trunk/lib/CodeGen/TargetInfo.h Fri May 2 04:33:20 2014 >> @@ -56,6 +56,11 @@ namespace clang { >> virtual void SetTargetAttributes(const Decl *D, llvm::GlobalValue *GV, >> CodeGen::CodeGenModule &M) const { } >> >> + /// EmitTargetMD - Provides a convenient hook to handle extra >> + /// target-specific metadata for the given global. >> + virtual void emitTargetMD(const Decl *D, llvm::GlobalValue *GV, >> + CodeGen::CodeGenModule &M) const { } >> + >> /// Determines the size of struct _Unwind_Exception on this platform, >> /// in 8-bit units. The Itanium ABI defines this as: >> /// struct _Unwind_Exception { >> >> Added: cfe/trunk/test/CodeGen/xcore-stringtype.c >> URL: >> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/xcore-stringtype.c?rev=207832&view=auto >> ============================================================================== >> --- cfe/trunk/test/CodeGen/xcore-stringtype.c (added) >> +++ cfe/trunk/test/CodeGen/xcore-stringtype.c Fri May 2 04:33:20 2014 >> @@ -0,0 +1,169 @@ >> +// REQUIRES: xcore-registered-target >> +// RUN: %clang_cc1 -triple xcore-unknown-unknown -fno-signed-char >> -fno-common -emit-llvm -o - %s | FileCheck %s >> + >> +// CHECK: target triple = "xcore-unknown-unknown" >> + >> +// In the tests below, some types are not supported by the ABI (_Complex, >> +// variable length arrays) and will thus emit no meta data. >> +// The 33 tests that do emit typstrings are gathered into >> '!xcore.typestrings' >> +// Please see 'Tools Developement Guide' section 2.16.2 for format details: >> +// >> <https://www.xmos.com/download/public/Tools-Development-Guide%28X9114A%29.pdf> >> + >> +// CHECK: !xcore.typestrings = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9, >> !10, >> +// CHECK: !11, !12, !13, !14, !15, !16, !17, !18, !19, !20, !21, !22, !23, >> +// CHECK: !24, !25, !26, !27, !28, !29, !30, !31, !32, !33, !34} >> + >> + >> +// test BuiltinType >> +// CHECK: !0 = metadata !{void (i1, i8, i8, i8, i16, i16, i16, i32, i32, >> i32, >> +// CHECK: i32, i32, i32, i64, i64, i64, float, double, double)* >> +// CHECK: @builtinType, metadata >> !"f{0}(b,uc,uc,sc,ss,us,ss,si,ui,si,sl, >> +// CHECK: ul,sl,sll,ull,sll,ft,d,ld)"} >> +void builtinType(_Bool B, char C, unsigned char UC, signed char SC, short S, >> + unsigned short US, signed short SS, int I, unsigned int UI, >> + signed int SI, long L, unsigned long UL, signed long SL, >> + long long LL, unsigned long long ULL, signed long long SLL, >> + float F, double D, long double LD) {} >> +double _Complex Complex; // not supported >> + >> + >> +// test FunctionType & Qualifiers >> +// CHECK: !1 = metadata !{void ()* @gI, metadata !"f{0}()"} >> +// CHECK: !2 = metadata !{void (...)* @eI, metadata !"f{0}()"} >> +// CHECK: !3 = metadata !{void ()* @gV, metadata !"f{0}(0)"} >> +// CHECK: !4 = metadata !{void ()* @eV, metadata !"f{0}(0)"} >> +// CHECK: !5 = metadata !{void (i32, ...)* @gVA, metadata !"f{0}(si,va)"} >> +// CHECK: !6 = metadata !{void (i32, ...)* @eVA, metadata !"f{0}(si,va)"} >> +// CHECK: !7 = metadata !{i32* (i32*)* @gQ, metadata >> !"f{crv:p(cv:si)}(p(cv:si))"} >> +// CHECK: !8 = metadata !{i32* (i32*)* @eQ, metadata >> !"f{crv:p(cv:si)}(p(cv:si))"} >> +extern void eI(); >> +void gI() {eI();}; >> +extern void eV(void); >> +void gV(void) {eV();} >> +extern void eVA(int, ...); >> +void gVA(int i, ...) {eVA(i);} >> +extern const volatile int* volatile restrict const >> + eQ(const volatile int * volatile restrict const); >> +const volatile int* volatile restrict const >> + gQ(const volatile int * volatile restrict const i) {return eQ(i);} >> + >> + >> +// test PointerType >> +// CHECK: !9 = metadata !{i32* (i32*, i32* (i32*)*)* >> +// CHECK: @pointerType, metadata !"f{p(si)}(p(si),p(f{p(si)}(p(si))))"} >> +// CHECK: !10 = metadata !{i32** @EP, metadata !"p(si)"} >> +// CHECK: !11 = metadata !{i32** @GP, metadata !"p(si)"} >> +extern int* EP; >> +int* GP; >> +int* pointerType(int *I, int * (*FP)(int *)) { >> + return I? EP : GP; >> +} >> + >> + >> +// test ArrayType >> +// CHECK: !12 = metadata !{[2 x i32]* (i32*, i32*, [2 x i32]*, [2 x i32]*, >> i32*)* >> +// CHECK: @arrayType, metadata !"f{p(a(2:si))}(p(si),p(si),p(a(2:si)), >> +// CHECK: p(a(2:si)),p(si))"} >> +// CHECK: !13 = metadata !{[0 x i32]* @EA1, metadata !"a(*:si)"} >> +// CHECK: !14 = metadata !{[2 x i32]* @EA2, metadata !"a(2:si)"} >> +// CHECK: !15 = metadata !{[0 x [2 x i32]]* @EA3, metadata !"a(*:a(2:si))"} >> +// CHECK: !16 = metadata !{[3 x [2 x i32]]* @EA4, metadata !"a(3:a(2:si))"} >> +// CHECK: !17 = metadata !{[2 x i32]* @GA1, metadata !"a(2:si)"} >> +// CHECK: !18 = metadata !{void ([2 x i32]*)* @arrayTypeVariable1, >> +// CHECK: metadata !"f{0}(p(a(2:si)))"} >> +// CHECK: !19 = metadata !{void (void ([2 x i32]*)*)* @arrayTypeVariable2, >> +// CHECK: metadata !"f{0}(p(f{0}(p(a(2:si)))))"} >> +// CHECK: !20 = metadata !{[3 x [2 x i32]]* @GA2, metadata !"a(3:a(2:si))"} >> +extern int EA1[]; >> +extern int EA2[2]; >> +extern int EA3[][2]; >> +extern int EA4[3][2]; >> +int GA1[2]; >> +int GA2[3][2]; >> +extern void arrayTypeVariable1(int[*][2]); >> +extern void arrayTypeVariable2( void(*fp)(int[*][2]) ); >> +extern void arrayTypeVariable3(int[3][*]); // not supported >> +extern void arrayTypeVariable4( void(*fp)(int[3][*]) ); // not supported >> +typedef int RetType[2]; >> +RetType* arrayType(int A1[], int A2[2], int A3[][2], int A4[3][2], >> + int A5[const volatile restrict static 2]) { >> + if (A1) return &EA1; >> + if (A2) return &EA2; >> + if (A3) return EA3; >> + if (A4) return EA4; >> + if (A5) return &GA1; >> + arrayTypeVariable1(EA4); >> + arrayTypeVariable2(arrayTypeVariable1); >> + arrayTypeVariable3(EA4); >> + arrayTypeVariable4(arrayTypeVariable3); >> + return GA2; >> +} >> + >> + >> +// test StructureType >> +// CHECK: !21 = metadata !{void (%struct.S1*)* @structureType1, metadata >> +// CHECK: >> !"f{0}(s(S1){m(ps2){p(s(S2){m(ps3){p(s(S3){m(s1){s(S1){}}})}})}})"} >> +// CHECK: !22 = metadata !{void (%struct.S2*)* @structureType2, metadata >> +// CHECK: >> !"f{0}(s(S2){m(ps3){p(s(S3){m(s1){s(S1){m(ps2){p(s(S2){})}}}})}})"} >> +// CHECK: !23 = metadata !{void (%struct.S3*)* @structureType3, metadata >> +// CHECK: >> !"f{0}(s(S3){m(s1){s(S1){m(ps2){p(s(S2){m(ps3){p(s(S3){})}})}}}})"} >> +// CHECK: !24 = metadata !{void (%struct.S4*)* @structureType4, metadata >> +// CHECK: >> !"f{0}(s(S4){m(s1){s(S1){m(ps2){p(s(S2){m(ps3){p(s(S3){m(s1){s(S1){}}})}})}}}})"} >> +// CHECK: !25 = metadata !{%struct.anon* @StructAnon, metadata >> !"s(){m(A){si}}"} >> +// CHECK: !26 = metadata !{i32 (%struct.SB*)* @structureTypeB, metadata >> +// CHECK: !"f{si}(s(SB){m(){b(4:si)},m(){b(2:si)},m(N4){b(4:si)}, >> +// CHECK: m(N2){b(2:si)},m(){b(4:ui)},m(){b(4:si)},m(){b(4:c:si)}, >> +// CHECK: m(){b(4:c:si)},m(){b(4:cv:si)}})"} >> +struct S2; >> +struct S1{struct S2 *ps2;}; >> +struct S3; >> +struct S2{struct S3 *ps3;}; >> +struct S3{struct S1 s1;}; >> +struct S4{struct S1 s1;}; >> +void structureType1(struct S1 s1){} >> +void structureType2(struct S2 s2){} >> +void structureType3(struct S3 s3){} >> +void structureType4(struct S4 s4){} >> +struct {int A;} StructAnon = {1}; >> +struct SB{int:4; int:2; int N4:4; int N2:2; unsigned int:4; signed int:4; >> + const int:4; int const :4; volatile const int:4;}; >> +int structureTypeB(struct SB sb){return StructAnon.A;} >> + >> + >> +// test UnionType >> +// CHECK: !27 = metadata !{void (%union.U1*)* @unionType1, metadata >> +// CHECK: >> !"f{0}(u(U1){m(pu2){p(u(U2){m(pu3){p(u(U3){m(u1){u(U1){}}})}})}})"} >> +// CHECK: !28 = metadata !{void (%union.U2*)* @unionType2, metadata >> +// CHECK: >> !"f{0}(u(U2){m(pu3){p(u(U3){m(u1){u(U1){m(pu2){p(u(U2){})}}}})}})"} >> +// CHECK: !29 = metadata !{void (%union.U3*)* @unionType3, metadata >> +// CHECK: >> !"f{0}(u(U3){m(u1){u(U1){m(pu2){p(u(U2){m(pu3){p(u(U3){})}})}}}})"} >> +// CHECK: !30 = metadata !{void (%union.U4*)* @unionType4, metadata >> +// CHECK: >> !"f{0}(u(U4){m(u1){u(U1){m(pu2){p(u(U2){m(pu3){p(u(U3){m(u1){u(U1){}}})}})}}}})"} >> +// CHECK: !31 = metadata !{%union.anon* @UnionAnon, metadata >> !"u(){m(A){si}}"} >> +// CHECK: !32 = metadata !{i32 (%union.UB*)* @unionTypeB, metadata >> +// CHECK: !"f{si}(u(UB){m(N2){b(2:si)},m(N4){b(4:si)},m(){b(2:si)}, >> +// CHECK: m(){b(4:c:si)},m(){b(4:c:si)},m(){b(4:cv:si)},m(){b(4:si)}, >> +// CHECK: m(){b(4:si)},m(){b(4:ui)}})"} >> +union U2; >> +union U1{union U2 *pu2;}; >> +union U3; >> +union U2{union U3 *pu3;}; >> +union U3{union U1 u1;}; >> +union U4{union U1 u1;}; >> +void unionType1(union U1 u1) {} >> +void unionType2(union U2 u2) {} >> +void unionType3(union U3 u3) {} >> +void unionType4(union U4 u4) {} >> +union UB{int:4; int:2; int N4:4; int N2:2; unsigned int:4; signed int:4; >> + const int:4; int const :4; volatile const int:4;}; >> +union {int A;} UnionAnon = {1}; >> +int unionTypeB(union UB ub) {return UnionAnon.A;} >> + >> + >> +// test EnumType >> +// CHECK: !33 = metadata !{i32* @EnumAnon, metadata !"e(){m(EA){3}}"} >> +// CHECK: !34 = metadata !{i32 (i32)* @enumType, metadata >> +// CHECK: !"f{si}(e(E){m(A){0},m(B){1},m(C){5},m(D){6}})"} >> +enum E {A, B, C=5, D}; >> +enum {EA=3} EnumAnon = EA; >> +int enumType(enum E e) {return EnumAnon;} >> >> >> _______________________________________________ >> cfe-commits mailing list >> [email protected] >> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits _______________________________________________ cfe-commits mailing list [email protected] http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
