forked from OSchip/llvm-project
XCore target: Add TypeString meta data to IR output.
This includes the addition of the virtual function: TargetCodeGenInfo::EmitTargetMD() llvm-svn: 207832
This commit is contained in:
parent
7229bbf810
commit
844aeeb15a
|
@ -1463,6 +1463,8 @@ CodeGenModule::GetOrCreateLLVMFunction(StringRef MangledName,
|
|||
}
|
||||
}
|
||||
|
||||
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(StringRef MangledName,
|
|||
isExternallyVisible(D->getLinkageAndVisibility().getLinkage()))
|
||||
GV->setSection(".cp.rodata");
|
||||
|
||||
getTargetCodeGenInfo().emitTargetMD(D, GV, *this);
|
||||
|
||||
return GV;
|
||||
}
|
||||
|
||||
|
|
|
@ -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::initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF,
|
|||
//===----------------------------------------------------------------------===//
|
||||
// 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(llvm::Value *VAListAddr, QualType Ty,
|
|||
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
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;}
|
Loading…
Reference in New Issue