r207832 - XCore target: Add TypeString meta data to IR output.

Evgeniy Stepanov eugeni.stepanov at gmail.com
Tue May 6 02:36:03 PDT 2014


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 <robert at xmos.com> 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 [eugeni.stepanov at gmail.com]
> Sent: 06 May 2014 08:30
> To: Robert Lytton
> Cc: cfe-commits at cs.uiuc.edu
> 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 <robert at xmos.com> 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
>> cfe-commits at cs.uiuc.edu
>> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits



More information about the cfe-commits mailing list