diff --git a/llvm/include/llvm/Bitcode/LLVMBitCodes.h b/llvm/include/llvm/Bitcode/LLVMBitCodes.h index 84991585c67b..be35428fa05e 100644 --- a/llvm/include/llvm/Bitcode/LLVMBitCodes.h +++ b/llvm/include/llvm/Bitcode/LLVMBitCodes.h @@ -154,7 +154,8 @@ namespace bitc { 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] + METADATA_COMPILE_UNIT = 20 // [distinct, ...] }; // The constants block (CONSTANTS_BLOCK_ID) describes emission for each diff --git a/llvm/include/llvm/IR/DebugInfoMetadata.h b/llvm/include/llvm/IR/DebugInfoMetadata.h index 9a0546ae17b1..6c47f755827b 100644 --- a/llvm/include/llvm/IR/DebugInfoMetadata.h +++ b/llvm/include/llvm/IR/DebugInfoMetadata.h @@ -844,6 +844,12 @@ public: Metadata *getGlobalVariables() const { return getOperand(7); } Metadata *getImportedEntities() const { return getOperand(8); } + MDString *getRawProducer() const { return getOperandAs(1); } + MDString *getRawFlags() const { return getOperandAs(2); } + MDString *getRawSplitDebugFilename() const { + return getOperandAs(3); + } + static bool classof(const Metadata *MD) { return MD->getMetadataID() == MDCompileUnitKind; } diff --git a/llvm/lib/AsmParser/LLParser.cpp b/llvm/lib/AsmParser/LLParser.cpp index 24442ef127bd..d7bf205ce000 100644 --- a/llvm/lib/AsmParser/LLParser.cpp +++ b/llvm/lib/AsmParser/LLParser.cpp @@ -3352,9 +3352,39 @@ bool LLParser::ParseMDFile(MDNode *&Result, bool IsDistinct) { return false; } +/// ParseMDCompileUnit: +/// ::= !MDCompileUnit(language: DW_LANG_C99, file: !0, producer: "clang", +/// isOptimized: true, flags: "-O2", runtimeVersion: 1, +/// splitDebugFilename: "abc.debug", emissionKind: 1, +/// enums: !1, retainedTypes: !2, subprograms: !3, +/// globals: !4, imports: !5) bool LLParser::ParseMDCompileUnit(MDNode *&Result, bool IsDistinct) { - return TokError("unimplemented parser"); +#define VISIT_MD_FIELDS(OPTIONAL, REQUIRED) \ + REQUIRED(language, DwarfLangField, ); \ + REQUIRED(file, MDField, ); \ + OPTIONAL(producer, MDStringField, ); \ + OPTIONAL(isOptimized, MDBoolField, ); \ + OPTIONAL(flags, MDStringField, ); \ + OPTIONAL(runtimeVersion, MDUnsignedField, (0, UINT32_MAX)); \ + OPTIONAL(splitDebugFilename, MDStringField, ); \ + OPTIONAL(emissionKind, MDUnsignedField, (0, UINT32_MAX)); \ + OPTIONAL(enums, MDField, ); \ + OPTIONAL(retainedTypes, MDField, ); \ + OPTIONAL(subprograms, MDField, ); \ + OPTIONAL(globals, MDField, ); \ + OPTIONAL(imports, MDField, ); + PARSE_MD_FIELDS(); +#undef VISIT_MD_FIELDS + + Result = GET_OR_DISTINCT(MDCompileUnit, + (Context, language.Val, file.Val, producer.Val, + isOptimized.Val, flags.Val, runtimeVersion.Val, + splitDebugFilename.Val, emissionKind.Val, enums.Val, + retainedTypes.Val, subprograms.Val, globals.Val, + imports.Val)); + return false; } + bool LLParser::ParseMDSubprogram(MDNode *&Result, bool IsDistinct) { return TokError("unimplemented parser"); } diff --git a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp index 5fc758a93cc9..d1c122f70ab7 100644 --- a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp +++ b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp @@ -1437,6 +1437,21 @@ std::error_code BitcodeReader::ParseMetadata() { NextMDValueNo++); break; } + case bitc::METADATA_COMPILE_UNIT: { + if (Record.size() != 14) + return Error("Invalid record"); + + MDValueList.AssignValue( + GET_OR_DISTINCT( + MDCompileUnit, Record[0], + (Context, Record[1], getMD(Record[2]), getMDString(Record[3]), + Record[4], getMDString(Record[5]), Record[6], + getMDString(Record[7]), Record[8], getMDOrNull(Record[9]), + getMDOrNull(Record[10]), getMDOrNull(Record[11]), + getMDOrNull(Record[12]), getMDOrNull(Record[13]))), + NextMDValueNo++); + break; + } case bitc::METADATA_STRING: { std::string String(Record.begin(), Record.end()); llvm::UpgradeMDStringConstant(String); diff --git a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp index 6f275ab79620..5e27f30a48d8 100644 --- a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp +++ b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp @@ -925,11 +925,30 @@ static void WriteMDFile(const MDFile *N, const ValueEnumerator &VE, Record.clear(); } -static void WriteMDCompileUnit(const MDCompileUnit *, const ValueEnumerator &, - BitstreamWriter &, SmallVectorImpl &, - unsigned) { - llvm_unreachable("write not implemented"); +static void WriteMDCompileUnit(const MDCompileUnit *N, + const ValueEnumerator &VE, + BitstreamWriter &Stream, + SmallVectorImpl &Record, + unsigned Abbrev) { + Record.push_back(N->isDistinct()); + Record.push_back(N->getSourceLanguage()); + Record.push_back(VE.getMetadataID(N->getFile())); + Record.push_back(VE.getMetadataOrNullID(N->getRawProducer())); + Record.push_back(N->isOptimized()); + Record.push_back(VE.getMetadataOrNullID(N->getRawFlags())); + Record.push_back(N->getRuntimeVersion()); + Record.push_back(VE.getMetadataOrNullID(N->getRawSplitDebugFilename())); + Record.push_back(N->getEmissionKind()); + Record.push_back(VE.getMetadataOrNullID(N->getEnumTypes())); + Record.push_back(VE.getMetadataOrNullID(N->getRetainedTypes())); + Record.push_back(VE.getMetadataOrNullID(N->getSubprograms())); + Record.push_back(VE.getMetadataOrNullID(N->getGlobalVariables())); + Record.push_back(VE.getMetadataOrNullID(N->getImportedEntities())); + + Stream.EmitRecord(bitc::METADATA_COMPILE_UNIT, Record, Abbrev); + Record.clear(); } + static void WriteMDSubprogram(const MDSubprogram *, const ValueEnumerator &, BitstreamWriter &, SmallVectorImpl &, unsigned) { diff --git a/llvm/lib/IR/AsmWriter.cpp b/llvm/lib/IR/AsmWriter.cpp index b2205a198664..cf002e4d7f9c 100644 --- a/llvm/lib/IR/AsmWriter.cpp +++ b/llvm/lib/IR/AsmWriter.cpp @@ -1505,10 +1505,58 @@ static void writeMDFile(raw_ostream &Out, const MDFile *N, TypePrinting *, Out << ")"; } -static void writeMDCompileUnit(raw_ostream &, const MDCompileUnit *, - TypePrinting *, SlotTracker *, const Module *) { - llvm_unreachable("write not implemented"); +static void writeMDCompileUnit(raw_ostream &Out, const MDCompileUnit *N, + TypePrinting *TypePrinter, SlotTracker *Machine, + const Module *Context) { + Out << "!MDCompileUnit("; + FieldSeparator FS; + Out << FS << "language: "; + if (const char *Lang = dwarf::LanguageString(N->getSourceLanguage())) + Out << Lang; + else + Out << N->getSourceLanguage(); + if (N->getFile()) { + Out << FS << "file: "; + writeMetadataAsOperand(Out, N->getFile(), TypePrinter, Machine, + Context); + } + if (!N->getProducer().empty()) + Out << FS << "producer: \"" << N->getProducer() << "\""; + Out << FS << "isOptimized: " << (N->isOptimized() ? "true" : "false"); + if (!N->getFlags().empty()) + Out << FS << "flags: \"" << N->getFlags() << "\""; + Out << FS << "runtimeVersion: " << N->getRuntimeVersion(); + if (!N->getSplitDebugFilename().empty()) + Out << FS << "splitDebugFilename: \"" << N->getSplitDebugFilename() << "\""; + Out << FS << "emissionKind: " << N->getEmissionKind(); + if (N->getEnumTypes()) { + Out << FS << "enums: "; + writeMetadataAsOperand(Out, N->getEnumTypes(), TypePrinter, Machine, + Context); + } + if (N->getRetainedTypes()) { + Out << FS << "retainedTypes: "; + writeMetadataAsOperand(Out, N->getRetainedTypes(), TypePrinter, Machine, + Context); + } + if (N->getSubprograms()) { + Out << FS << "subprograms: "; + writeMetadataAsOperand(Out, N->getSubprograms(), TypePrinter, Machine, + Context); + } + if (N->getGlobalVariables()) { + Out << FS << "globals: "; + writeMetadataAsOperand(Out, N->getGlobalVariables(), TypePrinter, Machine, + Context); + } + if (N->getImportedEntities()) { + Out << FS << "imports: "; + writeMetadataAsOperand(Out, N->getImportedEntities(), TypePrinter, Machine, + Context); + } + Out << ")"; } + static void writeMDSubprogram(raw_ostream &, const MDSubprogram *, TypePrinting *, SlotTracker *, const Module *) { llvm_unreachable("write not implemented"); diff --git a/llvm/test/Assembler/invalid-mdcompileunit-language-bad.ll b/llvm/test/Assembler/invalid-mdcompileunit-language-bad.ll new file mode 100644 index 000000000000..cf2da20061c9 --- /dev/null +++ b/llvm/test/Assembler/invalid-mdcompileunit-language-bad.ll @@ -0,0 +1,5 @@ +; RUN: not llvm-as < %s -disable-output 2>&1 | FileCheck %s + +; CHECK: :[[@LINE+1]]:31: error: invalid DWARF language 'DW_LANG_NoSuchLanguage' +!0 = !MDCompileUnit(language: DW_LANG_NoSuchLanguage, + file: !MDFile(filename: "a", directory: "b")) diff --git a/llvm/test/Assembler/invalid-mdcompileunit-language-overflow.ll b/llvm/test/Assembler/invalid-mdcompileunit-language-overflow.ll new file mode 100644 index 000000000000..14dab17868fc --- /dev/null +++ b/llvm/test/Assembler/invalid-mdcompileunit-language-overflow.ll @@ -0,0 +1,9 @@ +; RUN: not llvm-as < %s -disable-output 2>&1 | FileCheck %s + +; CHECK-NOT: error +!0 = !MDCompileUnit(language: 65535, + file: !MDFile(filename: "a", directory: "b")) + +; CHECK: :[[@LINE+1]]:31: error: value for 'language' too large, limit is 65535 +!1 = !MDCompileUnit(language: 65536, + file: !MDFile(filename: "a", directory: "b")) diff --git a/llvm/test/Assembler/invalid-mdcompileunit-missing-language.ll b/llvm/test/Assembler/invalid-mdcompileunit-missing-language.ll new file mode 100644 index 000000000000..57a9a3efb664 --- /dev/null +++ b/llvm/test/Assembler/invalid-mdcompileunit-missing-language.ll @@ -0,0 +1,4 @@ +; RUN: not llvm-as < %s -disable-output 2>&1 | FileCheck %s + +; CHECK: :[[@LINE+1]]:65: error: missing required field 'language' +!0 = !MDCompileUnit(file: !MDFile(filename: "a", directory: "b")) diff --git a/llvm/test/Assembler/mdcompileunit.ll b/llvm/test/Assembler/mdcompileunit.ll new file mode 100644 index 000000000000..ec2b35e36f57 --- /dev/null +++ b/llvm/test/Assembler/mdcompileunit.ll @@ -0,0 +1,31 @@ +; 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, !7, !8, !8} +!named = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9, !10} + +!0 = !{!"path/to/file", !"/path/to/dir"} +!1 = !MDFile(filename: "path/to/file", directory: "/path/to/dir") +!2 = distinct !{} +!3 = distinct !{} +!4 = distinct !{} +!5 = distinct !{} +!6 = distinct !{} + +; CHECK: !7 = !MDCompileUnit(language: DW_LANG_C99, file: !1, producer: "clang", isOptimized: true, flags: "-O2", runtimeVersion: 2, splitDebugFilename: "abc.debug", emissionKind: 3, enums: !2, retainedTypes: !3, subprograms: !4, globals: !5, imports: !6) +!7 = !MDCompileUnit(language: DW_LANG_C99, file: !1, producer: "clang", + isOptimized: true, flags: "-O2", runtimeVersion: 2, + splitDebugFilename: "abc.debug", emissionKind: 3, + enums: !2, retainedTypes: !3, subprograms: !4, + globals: !5, imports: !6) +!8 = !MDCompileUnit(language: 12, file: !1, producer: "clang", + isOptimized: true, flags: "-O2", runtimeVersion: 2, + splitDebugFilename: "abc.debug", emissionKind: 3, + enums: !2, retainedTypes: !3, subprograms: !4, + globals: !5, imports: !6) + +; CHECK: !8 = !MDCompileUnit(language: DW_LANG_C99, file: !1, isOptimized: false, runtimeVersion: 0, emissionKind: 0) +!9 = !MDCompileUnit(language: 12, file: !1, producer: "", + isOptimized: false, flags: "", runtimeVersion: 0, + splitDebugFilename: "", emissionKind: 0) +!10 = !MDCompileUnit(language: 12, file: !1)