Index: include/llvm/CodeGen/AsmPrinter.h =================================================================== --- include/llvm/CodeGen/AsmPrinter.h +++ include/llvm/CodeGen/AsmPrinter.h @@ -652,6 +652,8 @@ void EmitLLVMUsedList(const ConstantArray *InitList); /// Emit llvm.ident metadata in an '.ident' directive. void EmitModuleIdents(Module &M); + /// Emit llvm.commandline metadata in a '.commandline' directive. + void EmitModuleCommandLines(Module &M); void EmitXXStructorList(const DataLayout &DL, const Constant *List, bool isCtor); Index: include/llvm/MC/MCAsmInfo.h =================================================================== --- include/llvm/MC/MCAsmInfo.h +++ include/llvm/MC/MCAsmInfo.h @@ -286,6 +286,10 @@ /// Defaults to false. bool HasIdentDirective = false; + /// True if the target has a .commandline directive, this is true for ELF + /// targets. Defaults to false. + bool HasCommandLineDirective = false; + /// True if this target supports the MachO .no_dead_strip directive. Defaults /// to false. bool HasNoDeadStrip = false; @@ -539,6 +543,7 @@ bool hasDotTypeDotSizeDirective() const { return HasDotTypeDotSizeDirective; } bool hasSingleParameterDotFile() const { return HasSingleParameterDotFile; } bool hasIdentDirective() const { return HasIdentDirective; } + bool hasCommandLineDirective() const { return HasCommandLineDirective; } bool hasNoDeadStrip() const { return HasNoDeadStrip; } bool hasAltEntry() const { return HasAltEntry; } const char *getWeakDirective() const { return WeakDirective; } Index: include/llvm/MC/MCELFStreamer.h =================================================================== --- include/llvm/MC/MCELFStreamer.h +++ include/llvm/MC/MCELFStreamer.h @@ -32,6 +32,7 @@ /// state management void reset() override { SeenIdent = false; + SeenCommandLine = false; BundleGroups.clear(); MCObjectStreamer::reset(); } @@ -67,6 +68,7 @@ SMLoc Loc = SMLoc()) override; void EmitIdent(StringRef IdentString) override; + void EmitCommandLine(StringRef CommandLineString) override; void EmitValueToAlignment(unsigned, int64_t, unsigned, unsigned) override; @@ -92,6 +94,7 @@ void mergeFragment(MCDataFragment *, MCDataFragment *); bool SeenIdent = false; + bool SeenCommandLine = false; /// BundleGroups - The stack of fragments holding the bundle-locked /// instructions. Index: include/llvm/MC/MCStreamer.h =================================================================== --- include/llvm/MC/MCStreamer.h +++ include/llvm/MC/MCStreamer.h @@ -774,6 +774,10 @@ /// '.ident "version foo"' assembler directive. virtual void EmitIdent(StringRef IdentString) {} + /// Emit the "commandlines" directive. This implements the + /// '.commandline "compiler -flags"' assembler directive. + virtual void EmitCommandLine(StringRef CommandLineString) {} + /// Associate a filename with a specified logical file number. This /// implements the DWARF2 '.file 4 "foo.c"' assembler directive. unsigned EmitDwarfFileDirective(unsigned FileNo, StringRef Directory, Index: lib/CodeGen/AsmPrinter/AsmPrinter.cpp =================================================================== --- lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -1499,6 +1499,9 @@ // Emit llvm.ident metadata in an '.ident' directive. EmitModuleIdents(M); + // Emit llvm.commandline metadata in an '.commandline' directive. + EmitModuleCommandLines(M); + // Emit __morestack address if needed for indirect calls. if (MMI->usesMorestackAddr()) { unsigned Align = 1; @@ -2008,6 +2011,21 @@ } } +void AsmPrinter::EmitModuleCommandLines(Module &M) { + if (!MAI->hasCommandLineDirective()) + return; + + if (const NamedMDNode *NMD = M.getNamedMetadata("llvm.commandline")) { + for (unsigned i = 0, e = NMD->getNumOperands(); i != e; ++i) { + const MDNode *N = NMD->getOperand(i); + assert(N->getNumOperands() == 1 && + "llvm.commandline metadata entry can have only one operand"); + const MDString *S = cast(N->getOperand(0)); + OutStreamer->EmitCommandLine(S->getString()); + } + } +} + //===--------------------------------------------------------------------===// // Emission and print routines // Index: lib/IR/Verifier.cpp =================================================================== --- lib/IR/Verifier.cpp +++ lib/IR/Verifier.cpp @@ -383,6 +383,7 @@ visitModuleFlags(M); visitModuleIdents(M); + visitModuleCommandLines(M); verifyCompileUnits(); @@ -405,6 +406,7 @@ void visitValueAsMetadata(const ValueAsMetadata &MD, Function *F); void visitComdat(const Comdat &C); void visitModuleIdents(const Module &M); + void visitModuleCommandLines(const Module &M); void visitModuleFlags(const Module &M); void visitModuleFlag(const MDNode *Op, DenseMap &SeenIDs, @@ -1302,6 +1304,24 @@ } } +void Verifier::visitModuleCommandLines(const Module &M) { + const NamedMDNode *CommandLines = M.getNamedMetadata("llvm.commandline"); + if (!CommandLines) + return; + + // llvm.commandline takes a list of metadata entry. Each entry has only one + // string. Scan each llvm.commandline entry and make sure that this + // requirement is met. + for (const MDNode *N : CommandLines->operands()) { + Assert(N->getNumOperands() == 1, + "incorrect number of operands in llvm.commandline metadata", N); + Assert(dyn_cast_or_null(N->getOperand(0)), + ("invalid value for llvm.commandline metadata entry operand" + "(the operand should be a string)"), + N->getOperand(0)); + } +} + void Verifier::visitModuleFlags(const Module &M) { const NamedMDNode *Flags = M.getModuleFlagsMetadata(); if (!Flags) return; Index: lib/MC/MCAsmInfoELF.cpp =================================================================== --- lib/MC/MCAsmInfoELF.cpp +++ lib/MC/MCAsmInfoELF.cpp @@ -29,6 +29,7 @@ MCAsmInfoELF::MCAsmInfoELF() { HasIdentDirective = true; + HasCommandLineDirective = true; WeakRefDirective = "\t.weak\t"; PrivateGlobalPrefix = ".L"; PrivateLabelPrefix = ".L"; Index: lib/MC/MCAsmStreamer.cpp =================================================================== --- lib/MC/MCAsmStreamer.cpp +++ lib/MC/MCAsmStreamer.cpp @@ -266,6 +266,7 @@ void EmitCVFPOData(const MCSymbol *ProcSym, SMLoc L) override; void EmitIdent(StringRef IdentString) override; + void EmitCommandLine(StringRef CommandLineString) override; void EmitCFISections(bool EH, bool Debug) override; void EmitCFIDefCfa(int64_t Register, int64_t Offset) override; void EmitCFIDefCfaOffset(int64_t Offset) override; @@ -1393,6 +1394,14 @@ EmitEOL(); } +void MCAsmStreamer::EmitCommandLine(StringRef CommandLineString) { + assert(MAI->hasCommandLineDirective() && + ".commandline directive not supported"); + OS << "\t.commandline\t"; + PrintQuotedString(CommandLineString, OS); + EmitEOL(); +} + void MCAsmStreamer::EmitCFISections(bool EH, bool Debug) { MCStreamer::EmitCFISections(EH, Debug); OS << "\t.cfi_sections "; Index: lib/MC/MCELFStreamer.cpp =================================================================== --- lib/MC/MCELFStreamer.cpp +++ lib/MC/MCELFStreamer.cpp @@ -376,6 +376,21 @@ PopSection(); } +void MCELFStreamer::EmitCommandLine(StringRef CommandLineString) { + MCSection *CommandLine = getAssembler().getContext().getELFSection( + ".LLVM.command.line", ELF::SHT_PROGBITS, + ELF::SHF_MERGE | ELF::SHF_STRINGS, 1, ""); + PushSection(); + SwitchSection(CommandLine); + if (!SeenCommandLine) { + EmitIntValue(0, 1); + SeenCommandLine = true; + } + EmitBytes(CommandLineString); + EmitIntValue(0, 1); + PopSection(); +} + void MCELFStreamer::fixSymbolsInTLSFixups(const MCExpr *expr) { switch (expr->getKind()) { case MCExpr::Target: Index: lib/MC/MCParser/ELFAsmParser.cpp =================================================================== --- lib/MC/MCParser/ELFAsmParser.cpp +++ lib/MC/MCParser/ELFAsmParser.cpp @@ -73,6 +73,7 @@ addDirectiveHandler<&ELFAsmParser::ParseDirectivePrevious>(".previous"); addDirectiveHandler<&ELFAsmParser::ParseDirectiveType>(".type"); addDirectiveHandler<&ELFAsmParser::ParseDirectiveIdent>(".ident"); + addDirectiveHandler<&ELFAsmParser::ParseDirectiveCommandLine>(".commandline"); addDirectiveHandler<&ELFAsmParser::ParseDirectiveSymver>(".symver"); addDirectiveHandler<&ELFAsmParser::ParseDirectiveVersion>(".version"); addDirectiveHandler<&ELFAsmParser::ParseDirectiveWeakref>(".weakref"); @@ -145,6 +146,7 @@ bool ParseDirectivePrevious(StringRef, SMLoc); bool ParseDirectiveType(StringRef, SMLoc); bool ParseDirectiveIdent(StringRef, SMLoc); + bool ParseDirectiveCommandLine(StringRef, SMLoc); bool ParseDirectiveSymver(StringRef, SMLoc); bool ParseDirectiveVersion(StringRef, SMLoc); bool ParseDirectiveWeakref(StringRef, SMLoc); @@ -749,6 +751,24 @@ return false; } +/// ParseDirectiveCommandLine +/// ::= .commandline string +bool ELFAsmParser::ParseDirectiveCommandLine(StringRef, SMLoc) { + if (getLexer().isNot(AsmToken::String)) + return TokError("unexpected token in '.commandline' directive"); + + StringRef Data = getTok().getIdentifier(); + + Lex(); + + if (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in '.commandline' directive"); + Lex(); + + getStreamer().EmitCommandLine(Data); + return false; +} + /// ParseDirectiveSymver /// ::= .symver foo, bar2@zed bool ELFAsmParser::ParseDirectiveSymver(StringRef, SMLoc) { Index: test/CodeGen/X86/commandline-metadata.ll =================================================================== --- /dev/null +++ test/CodeGen/X86/commandline-metadata.ll @@ -0,0 +1,9 @@ +; RUN: llc -mtriple=x86_64-linux < %s | FileCheck %s +; Verify that llvm.commandline metadata is emitted as .commandline +; directives in assembly files. + +; CHECK: .commandline "clang -command -line" +; CHECK-NEXT: .commandline "something else" +!llvm.commandline = !{!0, !1} +!0 = !{!"clang -command -line"} +!1 = !{!"something else"} Index: test/Linker/Inputs/commandline.a.ll =================================================================== --- /dev/null +++ test/Linker/Inputs/commandline.a.ll @@ -0,0 +1,3 @@ +!llvm.commandline = !{!0, !1} +!0 = !{!"compiler -v1"} +!1 = !{!"compiler -v2"} Index: test/Linker/Inputs/commandline.b.ll =================================================================== --- /dev/null +++ test/Linker/Inputs/commandline.b.ll @@ -0,0 +1,2 @@ +!llvm.commandline = !{!0} +!0 = !{!"compiler -v3"} Index: test/Linker/commandline.ll =================================================================== --- /dev/null +++ test/Linker/commandline.ll @@ -0,0 +1,9 @@ +; RUN: llvm-link %S/Inputs/commandline.a.ll %S/Inputs/commandline.b.ll -S | FileCheck %s + +; Verify that multiple input llvm.commandline metadata are linked together. + +; CHECK-DAG: !llvm.commandline = !{!0, !1, !2} +; CHECK-DAG: "compiler -v1" +; CHECK-DAG: "compiler -v2" +; CHECK-DAG: "compiler -v3" + Index: test/MC/ELF/commandline.s =================================================================== --- /dev/null +++ test/MC/ELF/commandline.s @@ -0,0 +1,24 @@ +// RUN: llvm-mc -filetype=obj -triple x86_64-pc-linux-gnu %s -o - | llvm-readobj -s -sd | FileCheck %s + +// CHECK: Section { +// CHECK: Name: .LLVM.command.line +// CHECK-NEXT: Type: SHT_PROGBITS +// CHECK-NEXT: Flags [ +// CHECK-NEXT: SHF_MERGE +// CHECK-NEXT: SHF_STRINGS +// CHECK-NEXT: ] +// CHECK-NEXT: Address: 0x0 +// CHECK-NEXT: Offset: 0x40 +// CHECK-NEXT: Size: 13 +// CHECK-NEXT: Link: 0 +// CHECK-NEXT: Info: 0 +// CHECK-NEXT: AddressAlignment: 1 +// CHECK-NEXT: EntrySize: 1 +// CHECK-NEXT: SectionData ( +// CHECK-NEXT: 0000: 00666F6F 00626172 007A6564 00 +// CHECK-NEXT: ) +// CHECK-NEXT: } + + .commandline "foo" + .commandline "bar" + .commandline "zed" Index: test/Verifier/commandline-meta1.ll =================================================================== --- /dev/null +++ test/Verifier/commandline-meta1.ll @@ -0,0 +1,12 @@ +; RUN: not llvm-as < %s -o /dev/null 2>&1 | FileCheck %s +; Verify that llvm.commandline is properly structured. +; llvm.commandline takes a list of metadata entries. +; Each metadata entry can have only one string. + +!llvm.commandline = !{!0, !1} +!0 = !{!"commandline string"} +!1 = !{!"string1", !"string2"} +; CHECK: assembly parsed, but does not verify as correct! +; CHECK-NEXT: incorrect number of operands in llvm.commandline metadata +; CHECK-NEXT: !1 + Index: test/Verifier/commandline-meta2.ll =================================================================== --- /dev/null +++ test/Verifier/commandline-meta2.ll @@ -0,0 +1,13 @@ +; RUN: not llvm-as < %s -o /dev/null 2>&1 | FileCheck %s +; Verify that llvm.commandline is properly structured. +; llvm.commandline takes a list of metadata entries. +; Each metadata entry can contain one string only. + +!llvm.commandline = !{!0, !1, !2, !3} +!0 = !{!"str1"} +!1 = !{!"str2"} +!2 = !{!"str3"} +!3 = !{i32 1} +; CHECK: assembly parsed, but does not verify as correct! +; CHECK-NEXT: invalid value for llvm.commandline metadata entry operand(the operand should be a string) +; CHECK-NEXT: i32 1 Index: test/Verifier/commandline-meta3.ll =================================================================== --- /dev/null +++ test/Verifier/commandline-meta3.ll @@ -0,0 +1,10 @@ +; RUN: not llvm-as < %s -o /dev/null 2>&1 | FileCheck %s +; Verify that llvm.commandline is properly structured. +; llvm.commandline takes a list of metadata entries. +; Each metadata entry can contain one string only. + +!llvm.commandline = !{!0} +!0 = !{!{!"nested metadata"}} +; CHECK: assembly parsed, but does not verify as correct! +; CHECK-NEXT: invalid value for llvm.commandline metadata entry operand(the operand should be a string) +; CHECK-NEXT: !1 Index: test/Verifier/commandline-meta4.ll =================================================================== --- /dev/null +++ test/Verifier/commandline-meta4.ll @@ -0,0 +1,9 @@ +; RUN: not llvm-as < %s -o /dev/null 2>&1 | FileCheck %s +; Verify that llvm.commandline is properly structured. +; llvm.commandline takes a list of metadata entries. +; Each metadata entry can contain one string only. + +!llvm.commandline = !{!0} +!0 = !{null} +; CHECK: assembly parsed, but does not verify as correct! +; CHECK-NEXT: invalid value for llvm.commandline metadata entry operand(the operand should be a string)