Index: include/llvm/Bitcode/LLVMBitCodes.h =================================================================== --- include/llvm/Bitcode/LLVMBitCodes.h +++ include/llvm/Bitcode/LLVMBitCodes.h @@ -243,7 +243,7 @@ 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] Index: include/llvm/IR/DIBuilder.h =================================================================== --- include/llvm/IR/DIBuilder.h +++ include/llvm/IR/DIBuilder.h @@ -374,8 +374,9 @@ /// 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. Index: include/llvm/IR/DebugInfoMetadata.h =================================================================== --- include/llvm/IR/DebugInfoMetadata.h +++ include/llvm/IR/DebugInfoMetadata.h @@ -920,35 +920,44 @@ friend class LLVMContextImpl; friend class MDNode; + /// The calling convention used with DW_AT_calling_convention. Actually of + /// type dwarf::CallingConvention. + unsigned CC; + DISubroutineType(LLVMContext &C, StorageType Storage, unsigned Flags, - ArrayRef Ops) + unsigned CC, ArrayRef 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, + unsigned 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, + unsigned 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, unsigned CC, DITypeRefArray TypeArray), + (Flags, CC, TypeArray)) + DEFINE_MDNODE_GET(DISubroutineType, + (unsigned Flags, unsigned CC, Metadata *TypeArray), + (Flags, CC, TypeArray)) TempDISubroutineType clone() const { return cloneImpl(); } + unsigned getCC() const { return CC; } + DITypeRefArray getTypeArray() const { return cast_or_null(getRawTypeArray()); } Index: include/llvm/Support/Dwarf.h =================================================================== --- include/llvm/Support/Dwarf.h +++ include/llvm/Support/Dwarf.h @@ -389,18 +389,9 @@ 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 }; @@ -652,6 +643,7 @@ unsigned getOperationEncoding(StringRef OperationEncodingString); unsigned getVirtuality(StringRef VirtualityString); unsigned getLanguage(StringRef LanguageString); +unsigned getCallingConvention(StringRef LanguageString); unsigned getAttributeEncoding(StringRef EncodingString); unsigned getMacinfo(StringRef MacinfoString); /// @} Index: include/llvm/Support/Dwarf.def =================================================================== --- include/llvm/Support/Dwarf.def +++ include/llvm/Support/Dwarf.def @@ -14,7 +14,7 @@ // 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 @@ -38,6 +38,11 @@ #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) @@ -346,8 +351,23 @@ 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 Index: lib/AsmParser/LLLexer.cpp =================================================================== --- lib/AsmParser/LLLexer.cpp +++ lib/AsmParser/LLLexer.cpp @@ -793,6 +793,7 @@ DWKEYWORD(ATE, DwarfAttEncoding); DWKEYWORD(VIRTUALITY, DwarfVirtuality); DWKEYWORD(LANG, DwarfLang); + DWKEYWORD(CC, DwarfCC); DWKEYWORD(OP, DwarfOp); DWKEYWORD(MACINFO, DwarfMacinfo); #undef DWKEYWORD Index: lib/AsmParser/LLParser.cpp =================================================================== --- lib/AsmParser/LLParser.cpp +++ lib/AsmParser/LLParser.cpp @@ -3341,6 +3341,9 @@ 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) {} }; @@ -3484,6 +3487,24 @@ } template <> +bool LLParser::ParseMDField(LocTy Loc, StringRef Name, DwarfCCField &Result) { + if (Lex.getKind() == lltok::APSInt) + return ParseMDField(Loc, Name, static_cast(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(Result)); @@ -3863,11 +3884,13 @@ 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; } Index: lib/AsmParser/LLToken.h =================================================================== --- lib/AsmParser/LLToken.h +++ lib/AsmParser/LLToken.h @@ -344,6 +344,7 @@ DwarfAttEncoding, // DW_ATE_foo DwarfVirtuality, // DW_VIRTUALITY_foo DwarfLang, // DW_LANG_foo + DwarfCC, // DW_CC_foo EmissionKind, // lineTablesOnly DwarfOp, // DW_OP_foo DIFlag, // DIFlagFoo Index: lib/Bitcode/Reader/BitcodeReader.cpp =================================================================== --- lib/Bitcode/Reader/BitcodeReader.cpp +++ lib/Bitcode/Reader/BitcodeReader.cpp @@ -2409,17 +2409,18 @@ 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; } Index: lib/Bitcode/Writer/BitcodeWriter.cpp =================================================================== --- lib/Bitcode/Writer/BitcodeWriter.cpp +++ lib/Bitcode/Writer/BitcodeWriter.cpp @@ -1467,6 +1467,7 @@ 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(); Index: lib/CodeGen/AsmPrinter/CodeViewDebug.cpp =================================================================== --- lib/CodeGen/AsmPrinter/CodeViewDebug.cpp +++ lib/CodeGen/AsmPrinter/CodeViewDebug.cpp @@ -912,6 +912,18 @@ return TypeTable.writePointer(PR); } +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; @@ -953,13 +965,13 @@ 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. + unsigned DwarfCC = Ty->getCC(); + CallingConvention CC = dwarfCCToCodeView(DwarfCC); + // 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); } Index: lib/CodeGen/AsmPrinter/DwarfUnit.cpp =================================================================== --- lib/CodeGen/AsmPrinter/DwarfUnit.cpp +++ lib/CodeGen/AsmPrinter/DwarfUnit.cpp @@ -901,6 +901,11 @@ 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); @@ -1207,9 +1212,16 @@ 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. Index: lib/IR/AsmWriter.cpp =================================================================== --- lib/IR/AsmWriter.cpp +++ lib/IR/AsmWriter.cpp @@ -1659,6 +1659,7 @@ 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 << ")"; Index: lib/IR/DIBuilder.cpp =================================================================== --- lib/IR/DIBuilder.cpp +++ lib/IR/DIBuilder.cpp @@ -420,8 +420,8 @@ } 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, Index: lib/IR/DebugInfoMetadata.cpp =================================================================== --- lib/IR/DebugInfoMetadata.cpp +++ lib/IR/DebugInfoMetadata.cpp @@ -327,12 +327,13 @@ } DISubroutineType *DISubroutineType::getImpl(LLVMContext &Context, - unsigned Flags, Metadata *TypeArray, + unsigned Flags, unsigned 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, Index: lib/IR/LLVMContextImpl.h =================================================================== --- lib/IR/LLVMContextImpl.h +++ lib/IR/LLVMContextImpl.h @@ -484,17 +484,19 @@ template <> struct MDNodeKeyImpl { unsigned Flags; + unsigned CC; Metadata *TypeArray; - MDNodeKeyImpl(int64_t Flags, Metadata *TypeArray) - : Flags(Flags), TypeArray(TypeArray) {} + MDNodeKeyImpl(int64_t Flags, unsigned 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 { Index: lib/Support/Dwarf.cpp =================================================================== --- lib/Support/Dwarf.cpp +++ lib/Support/Dwarf.cpp @@ -384,23 +384,22 @@ 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(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) { Index: test/Assembler/disubroutinetype.ll =================================================================== --- test/Assembler/disubroutinetype.ll +++ test/Assembler/disubroutinetype.ll @@ -1,8 +1,8 @@ ; 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} @@ -21,3 +21,12 @@ ; 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) Index: test/DebugInfo/COFF/types-calling-conv.ll =================================================================== --- /dev/null +++ test/DebugInfo/COFF/types-calling-conv.ll @@ -0,0 +1,212 @@ +; 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) Index: test/DebugInfo/X86/DW_AT_calling-convention.ll =================================================================== --- /dev/null +++ test/DebugInfo/X86/DW_AT_calling-convention.ll @@ -0,0 +1,86 @@ +; 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) Index: unittests/IR/MetadataTest.cpp =================================================================== --- unittests/IR/MetadataTest.cpp +++ unittests/IR/MetadataTest.cpp @@ -80,7 +80,7 @@ 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, @@ -969,14 +969,14 @@ 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()); @@ -1254,14 +1254,29 @@ 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())); + + // Different CC should hash differently. + 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)));