METADATA_FILE = 16, // [distinct, filename, directory]
METADATA_DERIVED_TYPE = 17, // [distinct, ...]
METADATA_COMPOSITE_TYPE = 18, // [distinct, ...]
- METADATA_SUBROUTINE_TYPE = 19, // [distinct, flags, types]
+ METADATA_SUBROUTINE_TYPE = 19, // [distinct, flags, types, cc]
METADATA_COMPILE_UNIT = 20, // [distinct, ...]
METADATA_SUBPROGRAM = 21, // [distinct, ...]
METADATA_LEXICAL_BLOCK = 22, // [distinct, scope, file, line, column]
/// includes return type at 0th index.
/// \param Flags E.g.: LValueReference.
/// These flags are used to emit dwarf attributes.
+ /// \param CC Calling convention, e.g. dwarf::DW_CC_normal
DISubroutineType *createSubroutineType(DITypeRefArray ParameterTypes,
- unsigned Flags = 0);
+ unsigned Flags = 0, unsigned CC = 0);
/// Create an external type reference.
/// \param Tag Dwarf TAG.
friend class LLVMContextImpl;
friend class MDNode;
+ /// The calling convention used with DW_AT_calling_convention. Actually of
+ /// type dwarf::CallingConvention.
+ uint8_t CC;
+
DISubroutineType(LLVMContext &C, StorageType Storage, unsigned Flags,
- ArrayRef<Metadata *> Ops)
+ uint8_t CC, ArrayRef<Metadata *> Ops)
: DIType(C, DISubroutineTypeKind, Storage, dwarf::DW_TAG_subroutine_type,
- 0, 0, 0, 0, Flags, Ops) {}
+ 0, 0, 0, 0, Flags, Ops),
+ CC(CC) {}
~DISubroutineType() = default;
static DISubroutineType *getImpl(LLVMContext &Context, unsigned Flags,
- DITypeRefArray TypeArray,
+ uint8_t CC, DITypeRefArray TypeArray,
StorageType Storage,
bool ShouldCreate = true) {
- return getImpl(Context, Flags, TypeArray.get(), Storage, ShouldCreate);
+ return getImpl(Context, Flags, CC, TypeArray.get(), Storage, ShouldCreate);
}
static DISubroutineType *getImpl(LLVMContext &Context, unsigned Flags,
- Metadata *TypeArray, StorageType Storage,
+ uint8_t CC, Metadata *TypeArray,
+ StorageType Storage,
bool ShouldCreate = true);
TempDISubroutineType cloneImpl() const {
- return getTemporary(getContext(), getFlags(), getTypeArray());
+ return getTemporary(getContext(), getFlags(), getCC(), getTypeArray());
}
public:
DEFINE_MDNODE_GET(DISubroutineType,
- (unsigned Flags, DITypeRefArray TypeArray),
- (Flags, TypeArray))
- DEFINE_MDNODE_GET(DISubroutineType, (unsigned Flags, Metadata *TypeArray),
- (Flags, TypeArray))
+ (unsigned Flags, uint8_t CC, DITypeRefArray TypeArray),
+ (Flags, CC, TypeArray))
+ DEFINE_MDNODE_GET(DISubroutineType,
+ (unsigned Flags, uint8_t CC, Metadata *TypeArray),
+ (Flags, CC, TypeArray))
TempDISubroutineType clone() const { return cloneImpl(); }
+ uint8_t getCC() const { return CC; }
+
DITypeRefArray getTypeArray() const {
return cast_or_null<MDTuple>(getRawTypeArray());
}
// TODO: Add other DW-based macros.
#if !(defined HANDLE_DW_TAG || defined HANDLE_DW_OP || \
defined HANDLE_DW_LANG || defined HANDLE_DW_ATE || \
- defined HANDLE_DW_VIRTUALITY)
+ defined HANDLE_DW_VIRTUALITY || defined HANDLE_DW_CC)
#error "Missing macro definition of HANDLE_DW*"
#endif
#define HANDLE_DW_VIRTUALITY(ID, NAME)
#endif
+#ifndef HANDLE_DW_CC
+#define HANDLE_DW_CC(ID, NAME)
+#endif
+
+
HANDLE_DW_TAG(0x0001, array_type)
HANDLE_DW_TAG(0x0002, class_type)
HANDLE_DW_TAG(0x0003, entry_point)
HANDLE_DW_VIRTUALITY(0x01, virtual)
HANDLE_DW_VIRTUALITY(0x02, pure_virtual)
+// DWARF calling convention codes.
+HANDLE_DW_CC(0x01, normal)
+HANDLE_DW_CC(0x02, program)
+HANDLE_DW_CC(0x03, nocall)
+HANDLE_DW_CC(0x41, GNU_borland_fastcall_i386)
+HANDLE_DW_CC(0xb0, BORLAND_safecall)
+HANDLE_DW_CC(0xb1, BORLAND_stdcall)
+HANDLE_DW_CC(0xb2, BORLAND_pascal)
+HANDLE_DW_CC(0xb3, BORLAND_msfastcall)
+HANDLE_DW_CC(0xb4, BORLAND_msreturn)
+HANDLE_DW_CC(0xb5, BORLAND_thiscall)
+HANDLE_DW_CC(0xb6, BORLAND_fastcall)
+HANDLE_DW_CC(0xc0, LLVM_vectorcall)
+
#undef HANDLE_DW_TAG
#undef HANDLE_DW_OP
#undef HANDLE_DW_LANG
#undef HANDLE_DW_ATE
#undef HANDLE_DW_VIRTUALITY
+#undef HANDLE_DW_CC
enum CallingConvention {
// Calling convention codes
- DW_CC_normal = 0x01,
- DW_CC_program = 0x02,
- DW_CC_nocall = 0x03,
+#define HANDLE_DW_CC(ID, NAME) DW_CC_##NAME = ID,
+#include "llvm/Support/Dwarf.def"
DW_CC_lo_user = 0x40,
- DW_CC_GNU_borland_fastcall_i386 = 0x41,
- DW_CC_BORLAND_safecall = 0xb0,
- DW_CC_BORLAND_stdcall = 0xb1,
- DW_CC_BORLAND_pascal = 0xb2,
- DW_CC_BORLAND_msfastcall = 0xb3,
- DW_CC_BORLAND_msreturn = 0xb4,
- DW_CC_BORLAND_thiscall = 0xb5,
- DW_CC_BORLAND_fastcall = 0xb6,
DW_CC_hi_user = 0xff
};
unsigned getOperationEncoding(StringRef OperationEncodingString);
unsigned getVirtuality(StringRef VirtualityString);
unsigned getLanguage(StringRef LanguageString);
+unsigned getCallingConvention(StringRef LanguageString);
unsigned getAttributeEncoding(StringRef EncodingString);
unsigned getMacinfo(StringRef MacinfoString);
/// @}
DWKEYWORD(ATE, DwarfAttEncoding);
DWKEYWORD(VIRTUALITY, DwarfVirtuality);
DWKEYWORD(LANG, DwarfLang);
+ DWKEYWORD(CC, DwarfCC);
DWKEYWORD(OP, DwarfOp);
DWKEYWORD(MACINFO, DwarfMacinfo);
#undef DWKEYWORD
struct DwarfLangField : public MDUnsignedField {
DwarfLangField() : MDUnsignedField(0, dwarf::DW_LANG_hi_user) {}
};
+struct DwarfCCField : public MDUnsignedField {
+ DwarfCCField() : MDUnsignedField(0, dwarf::DW_CC_hi_user) {}
+};
struct EmissionKindField : public MDUnsignedField {
EmissionKindField() : MDUnsignedField(0, DICompileUnit::LastEmissionKind) {}
};
}
template <>
+bool LLParser::ParseMDField(LocTy Loc, StringRef Name, DwarfCCField &Result) {
+ if (Lex.getKind() == lltok::APSInt)
+ return ParseMDField(Loc, Name, static_cast<MDUnsignedField &>(Result));
+
+ if (Lex.getKind() != lltok::DwarfCC)
+ return TokError("expected DWARF calling convention");
+
+ unsigned CC = dwarf::getCallingConvention(Lex.getStrVal());
+ if (!CC)
+ return TokError("invalid DWARF calling convention" + Twine(" '") + Lex.getStrVal() +
+ "'");
+ assert(CC <= Result.Max && "Expected valid DWARF calling convention");
+ Result.assign(CC);
+ Lex.Lex();
+ return false;
+}
+
+template <>
bool LLParser::ParseMDField(LocTy Loc, StringRef Name, EmissionKindField &Result) {
if (Lex.getKind() == lltok::APSInt)
return ParseMDField(Loc, Name, static_cast<MDUnsignedField &>(Result));
bool LLParser::ParseDISubroutineType(MDNode *&Result, bool IsDistinct) {
#define VISIT_MD_FIELDS(OPTIONAL, REQUIRED) \
OPTIONAL(flags, DIFlagField, ); \
+ OPTIONAL(cc, DwarfCCField, ); \
REQUIRED(types, MDField, );
PARSE_MD_FIELDS();
#undef VISIT_MD_FIELDS
- Result = GET_OR_DISTINCT(DISubroutineType, (Context, flags.Val, types.Val));
+ Result = GET_OR_DISTINCT(DISubroutineType,
+ (Context, flags.Val, cc.Val, types.Val));
return false;
}
DwarfAttEncoding, // DW_ATE_foo
DwarfVirtuality, // DW_VIRTUALITY_foo
DwarfLang, // DW_LANG_foo
+ DwarfCC, // DW_CC_foo
EmissionKind, // lineTablesOnly
DwarfOp, // DW_OP_foo
DIFlag, // DIFlagFoo
break;
}
case bitc::METADATA_SUBROUTINE_TYPE: {
- if (Record.size() != 3)
+ if (Record.size() < 3 || Record.size() > 4)
return error("Invalid record");
+ bool IsOldTypeRefArray = Record[0] < 2;
+ unsigned CC = (Record.size() > 3) ? Record[3] : 0;
IsDistinct = Record[0] & 0x1;
- bool IsOldTypeRefArray = Record[0] < 2;
Metadata *Types = getMDOrNull(Record[2]);
if (LLVM_UNLIKELY(IsOldTypeRefArray))
Types = MetadataList.upgradeTypeRefArray(Types);
MetadataList.assignValue(
- GET_OR_DISTINCT(DISubroutineType, (Context, Record[1], Types)),
+ GET_OR_DISTINCT(DISubroutineType, (Context, Record[1], CC, Types)),
NextMetadataNo++);
break;
}
Record.push_back(HasNoOldTypeRefs | (unsigned)N->isDistinct());
Record.push_back(N->getFlags());
Record.push_back(VE.getMetadataOrNullID(N->getTypeArray().get()));
+ Record.push_back(N->getCC());
Stream.EmitRecord(bitc::METADATA_SUBROUTINE_TYPE, Record, Abbrev);
Record.clear();
return TypeTable.writePointer(PR);
}
+/// Given a DWARF calling convention, get the CodeView equivalent. If we don't
+/// have a translation, use the NearC convention.
+static CallingConvention dwarfCCToCodeView(unsigned DwarfCC) {
+ switch (DwarfCC) {
+ case dwarf::DW_CC_normal: return CallingConvention::NearC;
+ case dwarf::DW_CC_BORLAND_msfastcall: return CallingConvention::NearFast;
+ case dwarf::DW_CC_BORLAND_thiscall: return CallingConvention::ThisCall;
+ case dwarf::DW_CC_BORLAND_stdcall: return CallingConvention::NearStdCall;
+ case dwarf::DW_CC_BORLAND_pascal: return CallingConvention::NearPascal;
+ case dwarf::DW_CC_LLVM_vectorcall: return CallingConvention::NearVector;
+ }
+ return CallingConvention::NearC;
+}
+
TypeIndex CodeViewDebug::lowerTypeModifier(const DIDerivedType *Ty) {
ModifierOptions Mods = ModifierOptions::None;
bool IsModifier = true;
ArgListRecord ArgListRec(TypeRecordKind::ArgList, ArgTypeIndices);
TypeIndex ArgListIndex = TypeTable.writeArgList(ArgListRec);
- // TODO: We should use DW_AT_calling_convention to determine what CC this
- // procedure record should have.
+ CallingConvention CC = dwarfCCToCodeView(Ty->getCC());
+
// TODO: Some functions are member functions, we should use a more appropriate
// record for those.
- ProcedureRecord Procedure(ReturnTypeIndex, CallingConvention::NearC,
- FunctionOptions::None, ArgTypeIndices.size(),
- ArgListIndex);
+ ProcedureRecord Procedure(ReturnTypeIndex, CC, FunctionOptions::None,
+ ArgTypeIndices.size(), ArgListIndex);
return TypeTable.writeProcedure(Procedure);
}
Language == dwarf::DW_LANG_ObjC))
addFlag(Buffer, dwarf::DW_AT_prototyped);
+ // Add a DW_AT_calling_convention if this has an explicit convention.
+ if (CTy->getCC() && CTy->getCC() != dwarf::DW_CC_normal)
+ addUInt(Buffer, dwarf::DW_AT_calling_convention, dwarf::DW_FORM_data1,
+ CTy->getCC());
+
if (CTy->isLValueReference())
addFlag(Buffer, dwarf::DW_AT_reference);
Language == dwarf::DW_LANG_ObjC))
addFlag(SPDie, dwarf::DW_AT_prototyped);
+ unsigned CC = 0;
DITypeRefArray Args;
- if (const DISubroutineType *SPTy = SP->getType())
+ if (const DISubroutineType *SPTy = SP->getType()) {
Args = SPTy->getTypeArray();
+ CC = SPTy->getCC();
+ }
+
+ // Add a DW_AT_calling_convention if this has an explicit convention.
+ if (CC && CC != dwarf::DW_CC_normal)
+ addUInt(SPDie, dwarf::DW_AT_calling_convention, dwarf::DW_FORM_data1, CC);
// Add a return type. If this is a type like a C/C++ void type we don't add a
// return type.
Out << "!DISubroutineType(";
MDFieldPrinter Printer(Out, TypePrinter, Machine, Context);
Printer.printDIFlags("flags", N->getFlags());
+ Printer.printDwarfEnum("cc", N->getCC(), dwarf::ConventionString);
Printer.printMetadata("types", N->getRawTypeArray(),
/* ShouldSkipNull */ false);
Out << ")";
}
DISubroutineType *DIBuilder::createSubroutineType(DITypeRefArray ParameterTypes,
- unsigned Flags) {
- return DISubroutineType::get(VMContext, Flags, ParameterTypes);
+ unsigned Flags, unsigned CC) {
+ return DISubroutineType::get(VMContext, Flags, CC, ParameterTypes);
}
DICompositeType *DIBuilder::createExternalTypeRef(unsigned Tag, DIFile *File,
}
DISubroutineType *DISubroutineType::getImpl(LLVMContext &Context,
- unsigned Flags, Metadata *TypeArray,
+ unsigned Flags, uint8_t CC,
+ Metadata *TypeArray,
StorageType Storage,
bool ShouldCreate) {
- DEFINE_GETIMPL_LOOKUP(DISubroutineType, (Flags, TypeArray));
+ DEFINE_GETIMPL_LOOKUP(DISubroutineType, (Flags, CC, TypeArray));
Metadata *Ops[] = {nullptr, nullptr, nullptr, TypeArray};
- DEFINE_GETIMPL_STORE(DISubroutineType, (Flags), Ops);
+ DEFINE_GETIMPL_STORE(DISubroutineType, (Flags, CC), Ops);
}
DIFile *DIFile::getImpl(LLVMContext &Context, MDString *Filename,
template <> struct MDNodeKeyImpl<DISubroutineType> {
unsigned Flags;
+ uint8_t CC;
Metadata *TypeArray;
- MDNodeKeyImpl(int64_t Flags, Metadata *TypeArray)
- : Flags(Flags), TypeArray(TypeArray) {}
+ MDNodeKeyImpl(unsigned Flags, uint8_t CC, Metadata *TypeArray)
+ : Flags(Flags), CC(CC), TypeArray(TypeArray) {}
MDNodeKeyImpl(const DISubroutineType *N)
- : Flags(N->getFlags()), TypeArray(N->getRawTypeArray()) {}
+ : Flags(N->getFlags()), CC(N->getCC()), TypeArray(N->getRawTypeArray()) {}
bool isKeyOf(const DISubroutineType *RHS) const {
- return Flags == RHS->getFlags() && TypeArray == RHS->getRawTypeArray();
+ return Flags == RHS->getFlags() && CC == RHS->getCC() &&
+ TypeArray == RHS->getRawTypeArray();
}
- unsigned getHashValue() const { return hash_combine(Flags, TypeArray); }
+ unsigned getHashValue() const { return hash_combine(Flags, CC, TypeArray); }
};
template <> struct MDNodeKeyImpl<DIFile> {
return nullptr;
}
-const char *llvm::dwarf::ConventionString(unsigned Convention) {
- switch (Convention) {
- case DW_CC_normal: return "DW_CC_normal";
- case DW_CC_program: return "DW_CC_program";
- case DW_CC_nocall: return "DW_CC_nocall";
- case DW_CC_lo_user: return "DW_CC_lo_user";
- case DW_CC_hi_user: return "DW_CC_hi_user";
- case DW_CC_GNU_borland_fastcall_i386: return "DW_CC_GNU_borland_fastcall_i386";
- case DW_CC_BORLAND_safecall: return "DW_CC_BORLAND_safecall";
- case DW_CC_BORLAND_stdcall: return "DW_CC_BORLAND_stdcall";
- case DW_CC_BORLAND_pascal: return "DW_CC_BORLAND_pascal";
- case DW_CC_BORLAND_msfastcall: return "DW_CC_BORLAND_msfastcall";
- case DW_CC_BORLAND_msreturn: return "DW_CC_BORLAND_msreturn";
- case DW_CC_BORLAND_thiscall: return "DW_CC_BORLAND_thiscall";
- case DW_CC_BORLAND_fastcall: return "DW_CC_BORLAND_fastcall";
+const char *llvm::dwarf::ConventionString(unsigned CC) {
+ switch (CC) {
+ default:
+ return nullptr;
+#define HANDLE_DW_CC(ID, NAME) \
+ case DW_CC_##NAME: \
+ return "DW_CC_" #NAME;
+#include "llvm/Support/Dwarf.def"
}
- return nullptr;
+}
+
+unsigned llvm::dwarf::getCallingConvention(StringRef CCString) {
+ return StringSwitch<unsigned>(CCString)
+#define HANDLE_DW_CC(ID, NAME) .Case("DW_CC_" #NAME, DW_CC_##NAME)
+#include "llvm/Support/Dwarf.def"
+ .Default(0);
}
const char *llvm::dwarf::InlineCodeString(unsigned Code) {
; RUN: llvm-as < %s | llvm-dis | llvm-as | llvm-dis | FileCheck %s
; RUN: verify-uselistorder %s
-; CHECK: !named = !{!0, !1, !2, !3, !4, !5, !6, !7, !8}
-!named = !{!0, !1, !2, !3, !4, !5, !6, !7, !8}
+; CHECK: !named = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9, !10, !11, !12}
+!named = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9, !10, !11, !12}
!0 = !DIBasicType(name: "int", size: 32, align: 32, encoding: DW_ATE_signed)
!1 = !{null}
; CHECK: !8 = !DISubroutineType(types: null)
!8 = !DISubroutineType(types: null)
+
+; CHECK: !9 = !DISubroutineType(cc: DW_CC_normal, types: null)
+; CHECK: !10 = !DISubroutineType(cc: DW_CC_BORLAND_msfastcall, types: null)
+; CHECK: !11 = !DISubroutineType(cc: DW_CC_BORLAND_stdcall, types: null)
+; CHECK: !12 = !DISubroutineType(cc: DW_CC_LLVM_vectorcall, types: null)
+!9 = !DISubroutineType(cc: DW_CC_normal, types: null)
+!10 = !DISubroutineType(cc: DW_CC_BORLAND_msfastcall, types: null)
+!11 = !DISubroutineType(cc: DW_CC_BORLAND_stdcall, types: null)
+!12 = !DISubroutineType(cc: DW_CC_LLVM_vectorcall, types: null)
--- /dev/null
+; RUN: llc < %s -filetype=obj -o - | llvm-readobj - -codeview | FileCheck %s
+
+; C++ source to regenerate:
+; $ cat t.cpp
+; struct A {
+; void thiscallcc();
+; };
+; void A::thiscallcc() {}
+; void cdeclcc() {}
+; void __fastcall fastcallcc() {}
+; void __stdcall stdcallcc() {}
+; void __vectorcall vectorcallcc() {}
+; $ clang -g -gcodeview t.cpp -emit-llvm -S -o t.ll -O1
+
+; CHECK: CodeViewTypes [
+; CHECK: Section: .debug$T (5)
+; CHECK: Magic: 0x4
+; CHECK: Struct (0x1000) {
+; CHECK: TypeLeafKind: LF_STRUCTURE (0x1505)
+; CHECK: MemberCount: 0
+; CHECK: Properties [ (0x80)
+; CHECK: ForwardReference (0x80)
+; CHECK: ]
+; CHECK: FieldList: 0x0
+; CHECK: DerivedFrom: 0x0
+; CHECK: VShape: 0x0
+; CHECK: SizeOf: 0
+; CHECK: Name: A
+; CHECK: }
+; CHECK: Pointer (0x1001) {
+; CHECK: TypeLeafKind: LF_POINTER (0x1002)
+; CHECK: PointeeType: A (0x1000)
+; CHECK: PointerAttributes: 0x800A
+; CHECK: PtrType: Near32 (0xA)
+; CHECK: PtrMode: Pointer (0x0)
+; CHECK: IsFlat: 0
+; CHECK: IsConst: 0
+; CHECK: IsVolatile: 0
+; CHECK: IsUnaligned: 0
+; CHECK: }
+; CHECK: ArgList (0x1002) {
+; CHECK: TypeLeafKind: LF_ARGLIST (0x1201)
+; CHECK: NumArgs: 1
+; CHECK: Arguments [
+; CHECK: ArgType: A* (0x1001)
+; CHECK: ]
+; CHECK: }
+; CHECK: Procedure (0x1003) {
+; CHECK: TypeLeafKind: LF_PROCEDURE (0x1008)
+; CHECK: ReturnType: void (0x3)
+; CHECK: CallingConvention: ThisCall (0xB)
+; CHECK: FunctionOptions [ (0x0)
+; CHECK: ]
+; CHECK: NumParameters: 1
+; CHECK: ArgListType: (A*) (0x1002)
+; CHECK: }
+; CHECK: FuncId (0x1004) {
+; CHECK: TypeLeafKind: LF_FUNC_ID (0x1601)
+; CHECK: ParentScope: 0x0
+; CHECK: FunctionType: void (A*) (0x1003)
+; CHECK: Name: A::thiscallcc
+; CHECK: }
+; CHECK: ArgList (0x1005) {
+; CHECK: TypeLeafKind: LF_ARGLIST (0x1201)
+; CHECK: NumArgs: 0
+; CHECK: Arguments [
+; CHECK: ]
+; CHECK: }
+; CHECK: Procedure (0x1006) {
+; CHECK: TypeLeafKind: LF_PROCEDURE (0x1008)
+; CHECK: ReturnType: void (0x3)
+; CHECK: CallingConvention: NearC (0x0)
+; CHECK: FunctionOptions [ (0x0)
+; CHECK: ]
+; CHECK: NumParameters: 0
+; CHECK: ArgListType: () (0x1005)
+; CHECK: }
+; CHECK: FuncId (0x1007) {
+; CHECK: TypeLeafKind: LF_FUNC_ID (0x1601)
+; CHECK: ParentScope: 0x0
+; CHECK: FunctionType: void () (0x1006)
+; CHECK: Name: cdeclcc
+; CHECK: }
+; CHECK: Procedure (0x1008) {
+; CHECK: TypeLeafKind: LF_PROCEDURE (0x1008)
+; CHECK: ReturnType: void (0x3)
+; CHECK: CallingConvention: NearFast (0x4)
+; CHECK: FunctionOptions [ (0x0)
+; CHECK: ]
+; CHECK: NumParameters: 0
+; CHECK: ArgListType: () (0x1005)
+; CHECK: }
+; CHECK: FuncId (0x1009) {
+; CHECK: TypeLeafKind: LF_FUNC_ID (0x1601)
+; CHECK: ParentScope: 0x0
+; CHECK: FunctionType: void () (0x1008)
+; CHECK: Name: fastcallcc
+; CHECK: }
+; CHECK: Procedure (0x100A) {
+; CHECK: TypeLeafKind: LF_PROCEDURE (0x1008)
+; CHECK: ReturnType: void (0x3)
+; CHECK: CallingConvention: NearStdCall (0x7)
+; CHECK: FunctionOptions [ (0x0)
+; CHECK: ]
+; CHECK: NumParameters: 0
+; CHECK: ArgListType: () (0x1005)
+; CHECK: }
+; CHECK: FuncId (0x100B) {
+; CHECK: TypeLeafKind: LF_FUNC_ID (0x1601)
+; CHECK: ParentScope: 0x0
+; CHECK: FunctionType: void () (0x100A)
+; CHECK: Name: stdcallcc
+; CHECK: }
+; CHECK: Procedure (0x100C) {
+; CHECK: TypeLeafKind: LF_PROCEDURE (0x1008)
+; CHECK: ReturnType: void (0x3)
+; CHECK: CallingConvention: NearVector (0x18)
+; CHECK: FunctionOptions [ (0x0)
+; CHECK: ]
+; CHECK: NumParameters: 0
+; CHECK: ArgListType: () (0x1005)
+; CHECK: }
+; CHECK: FuncId (0x100D) {
+; CHECK: TypeLeafKind: LF_FUNC_ID (0x1601)
+; CHECK: ParentScope: 0x0
+; CHECK: FunctionType: void () (0x100C)
+; CHECK: Name: vectorcallcc
+; CHECK: }
+; CHECK: ]
+
+; ModuleID = 't.cpp'
+source_filename = "t.cpp"
+target datalayout = "e-m:x-p:32:32-i64:64-f80:32-n8:16:32-a:0:32-S32"
+target triple = "i386-pc-windows-msvc19.0.23918"
+
+%struct.A = type { i8 }
+
+; Function Attrs: nounwind readnone
+define x86_thiscallcc void @"\01?thiscallcc@A@@QAEXXZ"(%struct.A* nocapture %this) #0 align 2 !dbg !6 {
+entry:
+ tail call void @llvm.dbg.value(metadata %struct.A* %this, i64 0, metadata !14, metadata !16), !dbg !17
+ ret void, !dbg !18
+}
+
+; Function Attrs: norecurse nounwind readnone
+define void @"\01?cdeclcc@@YAXXZ"() #1 !dbg !19 {
+entry:
+ ret void, !dbg !22
+}
+
+; Function Attrs: norecurse nounwind readnone
+define x86_fastcallcc void @"\01?fastcallcc@@YIXXZ"() #1 !dbg !23 {
+entry:
+ ret void, !dbg !24
+}
+
+; Function Attrs: norecurse nounwind readnone
+define x86_stdcallcc void @"\01?stdcallcc@@YGXXZ"() #1 !dbg !25 {
+entry:
+ ret void, !dbg !26
+}
+
+; Function Attrs: norecurse nounwind readnone
+define x86_vectorcallcc void @"\01?vectorcallcc@@YQXXZ"() #1 !dbg !27 {
+entry:
+ ret void, !dbg !28
+}
+
+; Function Attrs: nounwind readnone
+declare void @llvm.dbg.value(metadata, i64, metadata, metadata) #2
+
+attributes #0 = { nounwind readnone "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="pentium4" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { norecurse nounwind readnone "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="pentium4" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #2 = { nounwind readnone }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!3, !4}
+!llvm.ident = !{!5}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 3.9.0 (trunk 272067)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
+!1 = !DIFile(filename: "t.cpp", directory: "D:\5Csrc\5Cllvm\5Cbuild")
+!2 = !{}
+!3 = !{i32 2, !"CodeView", i32 1}
+!4 = !{i32 2, !"Debug Info Version", i32 3}
+!5 = !{!"clang version 3.9.0 (trunk 272067)"}
+!6 = distinct !DISubprogram(name: "A::thiscallcc", linkageName: "\01?thiscallcc@A@@QAEXXZ", scope: !7, file: !1, line: 4, type: !10, isLocal: false, isDefinition: true, scopeLine: 4, flags: DIFlagPrototyped, isOptimized: true, unit: !0, declaration: !9, variables: !13)
+!7 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "A", file: !1, line: 1, size: 8, align: 8, elements: !8)
+!8 = !{!9}
+!9 = !DISubprogram(name: "A::thiscallcc", linkageName: "\01?thiscallcc@A@@QAEXXZ", scope: !7, file: !1, line: 2, type: !10, isLocal: false, isDefinition: false, scopeLine: 2, flags: DIFlagPrototyped, isOptimized: true)
+!10 = !DISubroutineType(cc: DW_CC_BORLAND_thiscall, types: !11)
+!11 = !{null, !12}
+!12 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !7, size: 32, align: 32, flags: DIFlagArtificial | DIFlagObjectPointer)
+!13 = !{!14}
+!14 = !DILocalVariable(name: "this", arg: 1, scope: !6, type: !15, flags: DIFlagArtificial | DIFlagObjectPointer)
+!15 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !7, size: 32, align: 32)
+!16 = !DIExpression()
+!17 = !DILocation(line: 0, scope: !6)
+!18 = !DILocation(line: 4, column: 23, scope: !6)
+!19 = distinct !DISubprogram(name: "cdeclcc", linkageName: "\01?cdeclcc@@YAXXZ", scope: !1, file: !1, line: 5, type: !20, isLocal: false, isDefinition: true, scopeLine: 5, flags: DIFlagPrototyped, isOptimized: true, unit: !0, variables: !2)
+!21 = !{null}
+!22 = !DILocation(line: 5, column: 17, scope: !19)
+!23 = distinct !DISubprogram(name: "fastcallcc", linkageName: "\01?fastcallcc@@YIXXZ", scope: !1, file: !1, line: 6, type: !29, isLocal: false, isDefinition: true, scopeLine: 6, flags: DIFlagPrototyped, isOptimized: true, unit: !0, variables: !2)
+!24 = !DILocation(line: 6, column: 31, scope: !23)
+!25 = distinct !DISubprogram(name: "stdcallcc", linkageName: "\01?stdcallcc@@YGXXZ", scope: !1, file: !1, line: 7, type: !30, isLocal: false, isDefinition: true, scopeLine: 7, flags: DIFlagPrototyped, isOptimized: true, unit: !0, variables: !2)
+!26 = !DILocation(line: 7, column: 29, scope: !25)
+!27 = distinct !DISubprogram(name: "vectorcallcc", linkageName: "\01?vectorcallcc@@YQXXZ", scope: !1, file: !1, line: 8, type: !31, isLocal: false, isDefinition: true, scopeLine: 8, flags: DIFlagPrototyped, isOptimized: true, unit: !0, variables: !2)
+!28 = !DILocation(line: 8, column: 35, scope: !27)
+
+!20 = !DISubroutineType(cc: DW_CC_normal, types: !21)
+!29 = !DISubroutineType(cc: DW_CC_BORLAND_msfastcall, types: !21)
+!30 = !DISubroutineType(cc: DW_CC_BORLAND_stdcall, types: !21)
+!31 = !DISubroutineType(cc: DW_CC_LLVM_vectorcall, types: !21)
--- /dev/null
+; RUN: llc < %s -filetype=obj -o %t
+; RUN: llvm-dwarfdump %t | FileCheck %s
+
+; C++ source to regenerate:
+; $ cat t.cpp
+; struct A {
+; void thiscallcc();
+; };
+; void A::thiscallcc() {}
+; void cdeclcc() {}
+; void __fastcall fastcallcc() {}
+; void __stdcall stdcallcc() {}
+; void __vectorcall vectorcallcc() {}
+; $ clang -g t.cpp -emit-llvm -S -o t.ll -O1
+
+; CHECK: .debug_abbrev contents:
+
+; CHECK: [[subroutine_abbrev:\[[0-9]+\]]] DW_TAG_subroutine_type DW_CHILDREN_yes
+; CHECK-NEXT: DW_AT_type DW_FORM_ref4
+; CHECK-NEXT: DW_AT_calling_convention DW_FORM_data1
+
+; CHECK: .debug_info contents:
+
+; CHECK: DW_TAG_subroutine_type [[subroutine_abbrev]] *
+; CHECK-NEXT: DW_AT_type [DW_FORM_ref4] {{.*}}
+; CHECK-NEXT: DW_AT_calling_convention [DW_FORM_data1] (DW_CC_BORLAND_msfastcall)
+
+; CHECK: DW_TAG_subprogram [{{.*}}] *
+; CHECK: DW_AT_low_pc
+; CHECK: DW_AT_high_pc
+; CHECK: DW_AT_frame_base
+; CHECK: DW_AT_linkage_name
+; CHECK: DW_AT_name
+; CHECK: DW_AT_decl_file
+; CHECK: DW_AT_decl_line
+; CHECK: DW_AT_calling_convention [DW_FORM_data1] (DW_CC_BORLAND_msfastcall)
+; CHECK: DW_AT_type
+; CHECK: DW_AT_external
+
+; ModuleID = 't.cpp'
+source_filename = "t.cpp"
+target datalayout = "e-m:x-p:32:32-i64:64-f80:32-n8:16:32-a:0:32-S32"
+target triple = "i386-pc-windows-msvc19.0.23918"
+
+@"\01?fptr@@3P6IHHH@ZA" = global i32 (i32, i32)* @"\01?f@@YIHHH@Z", align 4
+
+; Function Attrs: nounwind readnone
+define x86_fastcallcc i32 @"\01?f@@YIHHH@Z"(i32 inreg %a, i32 inreg %b) #0 !dbg !12 {
+entry:
+ tail call void @llvm.dbg.value(metadata i32 %b, i64 0, metadata !14, metadata !16), !dbg !17
+ tail call void @llvm.dbg.value(metadata i32 %a, i64 0, metadata !15, metadata !16), !dbg !18
+ %add = add nsw i32 %b, %a, !dbg !19
+ ret i32 %add, !dbg !20
+}
+
+; Function Attrs: nounwind readnone
+declare void @llvm.dbg.value(metadata, i64, metadata, metadata) #1
+
+attributes #0 = { nounwind readnone "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="pentium4" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { nounwind readnone }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!9, !10}
+!llvm.ident = !{!11}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 3.9.0 (trunk 272067)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, globals: !3)
+!1 = !DIFile(filename: "t.cpp", directory: "D:\5Csrc\5Cllvm\5Cbuild")
+!2 = !{}
+!3 = !{!4}
+!4 = distinct !DIGlobalVariable(name: "fptr", linkageName: "\01?fptr@@3P6IHHH@ZA", scope: !0, file: !1, line: 2, type: !5, isLocal: false, isDefinition: true, variable: i32 (i32, i32)** @"\01?fptr@@3P6IHHH@ZA")
+!5 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !6, size: 32, align: 32)
+!6 = !DISubroutineType(cc: DW_CC_BORLAND_msfastcall, types: !7)
+!7 = !{!8, !8, !8}
+!8 = !DIBasicType(name: "int", size: 32, align: 32, encoding: DW_ATE_signed)
+!9 = !{i32 2, !"Dwarf Version", i32 4}
+!10 = !{i32 2, !"Debug Info Version", i32 3}
+!11 = !{!"clang version 3.9.0 (trunk 272067)"}
+!12 = distinct !DISubprogram(name: "f", linkageName: "\01?f@@YIHHH@Z", scope: !1, file: !1, line: 1, type: !6, isLocal: false, isDefinition: true, scopeLine: 1, flags: DIFlagPrototyped, isOptimized: true, unit: !0, variables: !13)
+!13 = !{!14, !15}
+!14 = !DILocalVariable(name: "b", arg: 2, scope: !12, file: !1, line: 1, type: !8)
+!15 = !DILocalVariable(name: "a", arg: 1, scope: !12, file: !1, line: 1, type: !8)
+!16 = !DIExpression()
+!17 = !DILocation(line: 1, column: 29, scope: !12)
+!18 = !DILocation(line: 1, column: 22, scope: !12)
+!19 = !DILocation(line: 1, column: 43, scope: !12)
+!20 = !DILocation(line: 1, column: 34, scope: !12)
MDTuple *getTuple() { return MDTuple::getDistinct(Context, None); }
DISubroutineType *getSubroutineType() {
- return DISubroutineType::getDistinct(Context, 0, getNode(nullptr));
+ return DISubroutineType::getDistinct(Context, 0, 0, getNode(nullptr));
}
DISubprogram *getSubprogram() {
return DISubprogram::getDistinct(Context, nullptr, "", "", nullptr, 0,
Metadata *TypesOps[] = {nullptr};
Metadata *Types = MDTuple::get(Context, TypesOps);
- DIType *D = DISubroutineType::getDistinct(Context, 0u, Types);
+ DIType *D = DISubroutineType::getDistinct(Context, 0u, 0, Types);
EXPECT_EQ(0u, D->getFlags());
D->setFlags(DINode::FlagRValueReference);
EXPECT_EQ(DINode::FlagRValueReference, D->getFlags());
D->setFlags(0u);
EXPECT_EQ(0u, D->getFlags());
- TempDIType T = DISubroutineType::getTemporary(Context, 0u, Types);
+ TempDIType T = DISubroutineType::getTemporary(Context, 0u, 0, Types);
EXPECT_EQ(0u, T->getFlags());
T->setFlags(DINode::FlagRValueReference);
EXPECT_EQ(DINode::FlagRValueReference, T->getFlags());
unsigned Flags = 1;
MDTuple *TypeArray = getTuple();
- auto *N = DISubroutineType::get(Context, Flags, TypeArray);
+ auto *N = DISubroutineType::get(Context, Flags, 0, TypeArray);
EXPECT_EQ(dwarf::DW_TAG_subroutine_type, N->getTag());
EXPECT_EQ(Flags, N->getFlags());
EXPECT_EQ(TypeArray, N->getTypeArray().get());
- EXPECT_EQ(N, DISubroutineType::get(Context, Flags, TypeArray));
-
- EXPECT_NE(N, DISubroutineType::get(Context, Flags + 1, TypeArray));
- EXPECT_NE(N, DISubroutineType::get(Context, Flags, getTuple()));
+ EXPECT_EQ(N, DISubroutineType::get(Context, Flags, 0, TypeArray));
+
+ EXPECT_NE(N, DISubroutineType::get(Context, Flags + 1, 0, TypeArray));
+ EXPECT_NE(N, DISubroutineType::get(Context, Flags, 0, getTuple()));
+
+ // Test the hashing of calling conventions.
+ auto *Fast = DISubroutineType::get(
+ Context, Flags, dwarf::DW_CC_BORLAND_msfastcall, TypeArray);
+ auto *Std = DISubroutineType::get(Context, Flags,
+ dwarf::DW_CC_BORLAND_stdcall, TypeArray);
+ EXPECT_EQ(Fast,
+ DISubroutineType::get(Context, Flags,
+ dwarf::DW_CC_BORLAND_msfastcall, TypeArray));
+ EXPECT_EQ(Std, DISubroutineType::get(
+ Context, Flags, dwarf::DW_CC_BORLAND_stdcall, TypeArray));
+
+ EXPECT_NE(N, Fast);
+ EXPECT_NE(N, Std);
+ EXPECT_NE(Fast, Std);
TempDISubroutineType Temp = N->clone();
EXPECT_EQ(N, MDNode::replaceWithUniqued(std::move(Temp)));