summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--clang/docs/ClangCommandLineReference.rst12
-rw-r--r--clang/include/clang/Basic/CodeGenOptions.h4
-rw-r--r--clang/include/clang/Driver/CC1Options.td2
-rw-r--r--clang/include/clang/Driver/Options.td13
-rw-r--r--clang/lib/CodeGen/CodeGenModule.cpp13
-rw-r--r--clang/lib/CodeGen/CodeGenModule.h3
-rw-r--r--clang/lib/Driver/ToolChains/Clang.cpp29
-rw-r--r--clang/lib/Frontend/CompilerInvocation.cpp1
-rw-r--r--clang/test/Driver/clang_f_opts.c15
-rw-r--r--clang/test/Driver/debug-options.c11
-rw-r--r--llvm/include/llvm/CodeGen/AsmPrinter.h2
-rw-r--r--llvm/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h2
-rw-r--r--llvm/include/llvm/Target/TargetLoweringObjectFile.h6
-rw-r--r--llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp26
-rw-r--r--llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp8
-rw-r--r--llvm/lib/IR/Verifier.cpp20
-rw-r--r--llvm/test/CodeGen/X86/commandline-metadata.ll13
-rw-r--r--llvm/test/Linker/Inputs/commandline.a.ll3
-rw-r--r--llvm/test/Linker/Inputs/commandline.b.ll2
-rw-r--r--llvm/test/Linker/commandline.ll8
-rw-r--r--llvm/test/Verifier/commandline-meta1.ll10
-rw-r--r--llvm/test/Verifier/commandline-meta2.ll10
-rw-r--r--llvm/test/Verifier/commandline-meta3.ll10
-rw-r--r--llvm/test/Verifier/commandline-meta4.ll9
24 files changed, 222 insertions, 10 deletions
diff --git a/clang/docs/ClangCommandLineReference.rst b/clang/docs/ClangCommandLineReference.rst
index 540c8527d28..61abd05e0cc 100644
--- a/clang/docs/ClangCommandLineReference.rst
+++ b/clang/docs/ClangCommandLineReference.rst
@@ -792,6 +792,16 @@ Don't use blacklist file for sanitizers
.. option:: -fparse-all-comments
+.. option:: -frecord-command-line, -frecord-gcc-switches, -fno-record-command-line, -fno-record-gcc-switches
+
+Generate a section named ".GCC.command.line" containing the clang driver
+command-line. After linking, the section may contain multiple command lines,
+which will be individually terminated by null bytes. Separate arguments within
+a command line are combined with spaces; spaces and backslashes within an
+argument are escaped with backslashes. This format differs from the format of
+the equivalent section produced by GCC with the -frecord-gcc-switches flag.
+This option is currently only supported on ELF targets.
+
.. option:: -fsanitize-address-field-padding=<arg>
Level of field padding for AddressSanitizer
@@ -2831,7 +2841,7 @@ Embed source text in DWARF debug sections
.. option:: -gpubnames, -gno-pubnames
-.. option:: -grecord-gcc-switches, -gno-record-gcc-switches
+.. option:: -grecord-command-line, -grecord-gcc-switches, -gno-record-command-line, -gno-record-gcc-switches
.. option:: -gsplit-dwarf
diff --git a/clang/include/clang/Basic/CodeGenOptions.h b/clang/include/clang/Basic/CodeGenOptions.h
index 5f83915225f..a12744ee3d2 100644
--- a/clang/include/clang/Basic/CodeGenOptions.h
+++ b/clang/include/clang/Basic/CodeGenOptions.h
@@ -148,6 +148,10 @@ public:
/// non-empty.
std::string DwarfDebugFlags;
+ /// The string containing the commandline for the llvm.commandline metadata,
+ /// if non-empty.
+ std::string RecordCommandLine;
+
std::map<std::string, std::string> DebugPrefixMap;
/// The ABI to use for passing floating point arguments.
diff --git a/clang/include/clang/Driver/CC1Options.td b/clang/include/clang/Driver/CC1Options.td
index d4e2a03ca59..9d2d2df7d24 100644
--- a/clang/include/clang/Driver/CC1Options.td
+++ b/clang/include/clang/Driver/CC1Options.td
@@ -167,6 +167,8 @@ def fdebug_compilation_dir : Separate<["-"], "fdebug-compilation-dir">,
HelpText<"The compilation directory to embed in the debug info.">;
def dwarf_debug_flags : Separate<["-"], "dwarf-debug-flags">,
HelpText<"The string to embed in the Dwarf debug flags record.">;
+def record_command_line : Separate<["-"], "record-command-line">,
+ HelpText<"The string to embed in the .LLVM.command.line section.">;
def compress_debug_sections : Flag<["-", "--"], "compress-debug-sections">,
HelpText<"DWARF debug sections compression">;
def compress_debug_sections_EQ : Joined<["-"], "compress-debug-sections=">,
diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index 623ab898ecc..acf82c5ab20 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -799,6 +799,12 @@ def fcomment_block_commands : CommaJoined<["-"], "fcomment-block-commands=">, Gr
HelpText<"Treat each comma separated argument in <arg> as a documentation comment block command">,
MetaVarName<"<arg>">;
def fparse_all_comments : Flag<["-"], "fparse-all-comments">, Group<f_clang_Group>, Flags<[CC1Option]>;
+def frecord_command_line : Flag<["-"], "frecord-command-line">,
+ Group<f_clang_Group>;
+def fno_record_command_line : Flag<["-"], "fno-record-command-line">,
+ Group<f_clang_Group>;
+def : Flag<["-"], "frecord-gcc-switches">, Alias<frecord_command_line>;
+def : Flag<["-"], "fno-record-gcc-switches">, Alias<fno_record_command_line>;
def fcommon : Flag<["-"], "fcommon">, Group<f_Group>;
def fcompile_resource_EQ : Joined<["-"], "fcompile-resource=">, Group<f_Group>;
def fcomplete_member_pointers : Flag<["-"], "fcomplete-member-pointers">, Group<f_clang_Group>,
@@ -1854,9 +1860,12 @@ def gcoff : Joined<["-"], "gcoff">, Group<g_Group>, Flags<[Unsupported]>;
def gxcoff : Joined<["-"], "gxcoff">, Group<g_Group>, Flags<[Unsupported]>;
def gvms : Joined<["-"], "gvms">, Group<g_Group>, Flags<[Unsupported]>;
def gtoggle : Flag<["-"], "gtoggle">, Group<g_flags_Group>, Flags<[Unsupported]>;
-def grecord_gcc_switches : Flag<["-"], "grecord-gcc-switches">, Group<g_flags_Group>;
-def gno_record_gcc_switches : Flag<["-"], "gno-record-gcc-switches">,
+def grecord_command_line : Flag<["-"], "grecord-command-line">,
Group<g_flags_Group>;
+def gno_record_command_line : Flag<["-"], "gno-record-command-line">,
+ Group<g_flags_Group>;
+def : Flag<["-"], "grecord-gcc-switches">, Alias<grecord_command_line>;
+def : Flag<["-"], "gno-record-gcc-switches">, Alias<gno_record_command_line>;
def gstrict_dwarf : Flag<["-"], "gstrict-dwarf">, Group<g_flags_Group>;
def gno_strict_dwarf : Flag<["-"], "gno-strict-dwarf">, Group<g_flags_Group>;
def gcolumn_info : Flag<["-"], "gcolumn-info">, Group<g_flags_Group>, Flags<[CoreOption]>;
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index 1b7bb2ce37e..df814d63861 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -590,6 +590,9 @@ void CodeGenModule::Release() {
if (getCodeGenOpts().EmitVersionIdentMetadata)
EmitVersionIdentMetadata();
+ if (!getCodeGenOpts().RecordCommandLine.empty())
+ EmitCommandLineMetadata();
+
EmitTargetMetadata();
}
@@ -5217,6 +5220,16 @@ void CodeGenModule::EmitVersionIdentMetadata() {
IdentMetadata->addOperand(llvm::MDNode::get(Ctx, IdentNode));
}
+void CodeGenModule::EmitCommandLineMetadata() {
+ llvm::NamedMDNode *CommandLineMetadata =
+ TheModule.getOrInsertNamedMetadata("llvm.commandline");
+ std::string CommandLine = getCodeGenOpts().RecordCommandLine;
+ llvm::LLVMContext &Ctx = TheModule.getContext();
+
+ llvm::Metadata *CommandLineNode[] = {llvm::MDString::get(Ctx, CommandLine)};
+ CommandLineMetadata->addOperand(llvm::MDNode::get(Ctx, CommandLineNode));
+}
+
void CodeGenModule::EmitTargetMetadata() {
// Warning, new MangledDeclNames may be appended within this loop.
// We rely on MapVector insertions adding new elements to the end
diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h
index a97cce3a552..0f6c3bec9e7 100644
--- a/clang/lib/CodeGen/CodeGenModule.h
+++ b/clang/lib/CodeGen/CodeGenModule.h
@@ -1408,6 +1408,9 @@ private:
/// Emit the Clang version as llvm.ident metadata.
void EmitVersionIdentMetadata();
+ /// Emit the Clang commandline as llvm.commandline metadata.
+ void EmitCommandLineMetadata();
+
/// Emits target specific Metadata for global declarations.
void EmitTargetMetadata();
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index 614220cba17..e3dfb09c739 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -5063,14 +5063,22 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
const char *Exec = D.getClangProgramPath();
- // Optionally embed the -cc1 level arguments into the debug info, for build
- // analysis.
+ // Optionally embed the -cc1 level arguments into the debug info or a
+ // section, for build analysis.
// Also record command line arguments into the debug info if
// -grecord-gcc-switches options is set on.
// By default, -gno-record-gcc-switches is set on and no recording.
- if (TC.UseDwarfDebugFlags() ||
- Args.hasFlag(options::OPT_grecord_gcc_switches,
- options::OPT_gno_record_gcc_switches, false)) {
+ auto GRecordSwitches =
+ Args.hasFlag(options::OPT_grecord_command_line,
+ options::OPT_gno_record_command_line, false);
+ auto FRecordSwitches =
+ Args.hasFlag(options::OPT_frecord_command_line,
+ options::OPT_fno_record_command_line, false);
+ if (FRecordSwitches && !Triple.isOSBinFormatELF())
+ D.Diag(diag::err_drv_unsupported_opt_for_target)
+ << Args.getLastArg(options::OPT_frecord_command_line)->getAsString(Args)
+ << TripleStr;
+ if (TC.UseDwarfDebugFlags() || GRecordSwitches || FRecordSwitches) {
ArgStringList OriginalArgs;
for (const auto &Arg : Args)
Arg->render(Args, OriginalArgs);
@@ -5083,8 +5091,15 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
Flags += " ";
Flags += EscapedArg;
}
- CmdArgs.push_back("-dwarf-debug-flags");
- CmdArgs.push_back(Args.MakeArgString(Flags));
+ auto FlagsArgString = Args.MakeArgString(Flags);
+ if (TC.UseDwarfDebugFlags() || GRecordSwitches) {
+ CmdArgs.push_back("-dwarf-debug-flags");
+ CmdArgs.push_back(FlagsArgString);
+ }
+ if (FRecordSwitches) {
+ CmdArgs.push_back("-record-command-line");
+ CmdArgs.push_back(FlagsArgString);
+ }
}
// Host-side cuda compilation receives all device-side outputs in a single
diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp
index f87da5a59e6..d491f35769c 100644
--- a/clang/lib/Frontend/CompilerInvocation.cpp
+++ b/clang/lib/Frontend/CompilerInvocation.cpp
@@ -755,6 +755,7 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
Args.hasFlag(OPT_ffine_grained_bitfield_accesses,
OPT_fno_fine_grained_bitfield_accesses, false);
Opts.DwarfDebugFlags = Args.getLastArgValue(OPT_dwarf_debug_flags);
+ Opts.RecordCommandLine = Args.getLastArgValue(OPT_record_command_line);
Opts.MergeAllConstants = Args.hasArg(OPT_fmerge_all_constants);
Opts.NoCommon = Args.hasArg(OPT_fno_common);
Opts.NoImplicitFloat = Args.hasArg(OPT_no_implicit_float);
diff --git a/clang/test/Driver/clang_f_opts.c b/clang/test/Driver/clang_f_opts.c
index 3596aab902f..984244679d0 100644
--- a/clang/test/Driver/clang_f_opts.c
+++ b/clang/test/Driver/clang_f_opts.c
@@ -542,3 +542,18 @@
// RUN: %clang -### -S -fomit-frame-pointer -fno-omit-frame-pointer -pg %s 2>&1 | FileCheck -check-prefix=CHECK-MIX-NO-OMIT-FP-PG %s
// CHECK-NO-MIX-OMIT-FP-PG: '-fomit-frame-pointer' not allowed with '-pg'
// CHECK-MIX-NO-OMIT-FP-PG-NOT: '-fomit-frame-pointer' not allowed with '-pg'
+
+// RUN: %clang -### -S -target x86_64-unknown-linux -frecord-gcc-switches %s 2>&1 | FileCheck -check-prefix=CHECK-RECORD-GCC-SWITCHES %s
+// RUN: %clang -### -S -target x86_64-unknown-linux -fno-record-gcc-switches %s 2>&1 | FileCheck -check-prefix=CHECK-NO-RECORD-GCC-SWITCHES %s
+// RUN: %clang -### -S -target x86_64-unknown-linux -fno-record-gcc-switches -frecord-gcc-switches %s 2>&1 | FileCheck -check-prefix=CHECK-RECORD-GCC-SWITCHES %s
+// RUN: %clang -### -S -target x86_64-unknown-linux -frecord-gcc-switches -fno-record-gcc-switches %s 2>&1 | FileCheck -check-prefix=CHECK-NO-RECORD-GCC-SWITCHES %s
+// RUN: %clang -### -S -target x86_64-unknown-linux -frecord-command-line %s 2>&1 | FileCheck -check-prefix=CHECK-RECORD-GCC-SWITCHES %s
+// RUN: %clang -### -S -target x86_64-unknown-linux -fno-record-command-line %s 2>&1 | FileCheck -check-prefix=CHECK-NO-RECORD-GCC-SWITCHES %s
+// RUN: %clang -### -S -target x86_64-unknown-linux -fno-record-command-line -frecord-command-line %s 2>&1 | FileCheck -check-prefix=CHECK-RECORD-GCC-SWITCHES %s
+// RUN: %clang -### -S -target x86_64-unknown-linux -frecord-command-line -fno-record-command-line %s 2>&1 | FileCheck -check-prefix=CHECK-NO-RECORD-GCC-SWITCHES %s
+// Test with a couple examples of non-ELF object file formats
+// RUN: %clang -### -S -target x86_64-unknown-macosx -frecord-command-line %s 2>&1 | FileCheck -check-prefix=CHECK-RECORD-GCC-SWITCHES-ERROR %s
+// RUN: %clang -### -S -target x86_64-unknown-windows -frecord-command-line %s 2>&1 | FileCheck -check-prefix=CHECK-RECORD-GCC-SWITCHES-ERROR %s
+// CHECK-RECORD-GCC-SWITCHES: "-record-command-line"
+// CHECK-NO-RECORD-GCC-SWITCHES-NOT: "-record-command-line"
+// CHECK-RECORD-GCC-SWITCHES-ERROR: error: unsupported option '-frecord-command-line' for target
diff --git a/clang/test/Driver/debug-options.c b/clang/test/Driver/debug-options.c
index b9f4fea6e5b..58269cbb29b 100644
--- a/clang/test/Driver/debug-options.c
+++ b/clang/test/Driver/debug-options.c
@@ -157,6 +157,17 @@
// RUN: %clang -### -c -O3 -ffunction-sections -grecord-gcc-switches %s 2>&1 \
// | FileCheck -check-prefix=GRECORD_OPT %s
//
+// RUN: %clang -### -c -grecord-command-line %s 2>&1 \
+// | FileCheck -check-prefix=GRECORD %s
+// RUN: %clang -### -c -gno-record-command-line %s 2>&1 \
+// | FileCheck -check-prefix=GNO_RECORD %s
+// RUN: %clang -### -c -grecord-command-line -gno-record-command-line %s 2>&1 \
+// | FileCheck -check-prefix=GNO_RECORD %s/
+// RUN: %clang -### -c -grecord-command-line -o - %s 2>&1 \
+// | FileCheck -check-prefix=GRECORD_O %s
+// RUN: %clang -### -c -O3 -ffunction-sections -grecord-command-line %s 2>&1 \
+// | FileCheck -check-prefix=GRECORD_OPT %s
+//
// RUN: %clang -### -c -gstrict-dwarf -gno-strict-dwarf %s 2>&1 \
// RUN: | FileCheck -check-prefix=GIGNORE %s
//
diff --git a/llvm/include/llvm/CodeGen/AsmPrinter.h b/llvm/include/llvm/CodeGen/AsmPrinter.h
index 0344a82fc13..301688836f7 100644
--- a/llvm/include/llvm/CodeGen/AsmPrinter.h
+++ b/llvm/include/llvm/CodeGen/AsmPrinter.h
@@ -656,6 +656,8 @@ private:
void EmitLLVMUsedList(const ConstantArray *InitList);
/// Emit llvm.ident metadata in an '.ident' directive.
void EmitModuleIdents(Module &M);
+ /// Emit bytes for llvm.commandline metadata.
+ void EmitModuleCommandLines(Module &M);
void EmitXXStructorList(const DataLayout &DL, const Constant *List,
bool isCtor);
diff --git a/llvm/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h b/llvm/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h
index f5c7fc824ab..052d1f8bc68 100644
--- a/llvm/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h
+++ b/llvm/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h
@@ -90,6 +90,8 @@ public:
const MCExpr *lowerRelativeReference(const GlobalValue *LHS,
const GlobalValue *RHS,
const TargetMachine &TM) const override;
+
+ MCSection *getSectionForCommandLines() const override;
};
class TargetLoweringObjectFileMachO : public TargetLoweringObjectFile {
diff --git a/llvm/include/llvm/Target/TargetLoweringObjectFile.h b/llvm/include/llvm/Target/TargetLoweringObjectFile.h
index 40b77c3d94a..e80f2bf82f2 100644
--- a/llvm/include/llvm/Target/TargetLoweringObjectFile.h
+++ b/llvm/include/llvm/Target/TargetLoweringObjectFile.h
@@ -201,6 +201,12 @@ public:
virtual void emitLinkerFlagsForUsed(raw_ostream &OS,
const GlobalValue *GV) const {}
+ /// If supported, return the section to use for the llvm.commandline
+ /// metadata. Otherwise, return nullptr.
+ virtual MCSection *getSectionForCommandLines() const {
+ return nullptr;
+ }
+
protected:
virtual MCSection *SelectSectionForGlobal(const GlobalObject *GO,
SectionKind Kind,
diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
index c38457ff59e..66473466a83 100644
--- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
@@ -1499,6 +1499,9 @@ bool AsmPrinter::doFinalization(Module &M) {
// Emit llvm.ident metadata in an '.ident' directive.
EmitModuleIdents(M);
+ // Emit bytes for llvm.commandline metadata.
+ EmitModuleCommandLines(M);
+
// Emit __morestack address if needed for indirect calls.
if (MMI->usesMorestackAddr()) {
unsigned Align = 1;
@@ -2008,6 +2011,29 @@ void AsmPrinter::EmitModuleIdents(Module &M) {
}
}
+void AsmPrinter::EmitModuleCommandLines(Module &M) {
+ MCSection *CommandLine = getObjFileLowering().getSectionForCommandLines();
+ if (!CommandLine)
+ return;
+
+ const NamedMDNode *NMD = M.getNamedMetadata("llvm.commandline");
+ if (!NMD || !NMD->getNumOperands())
+ return;
+
+ OutStreamer->PushSection();
+ OutStreamer->SwitchSection(CommandLine);
+ OutStreamer->EmitZeros(1);
+ 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<MDString>(N->getOperand(0));
+ OutStreamer->EmitBytes(S->getString());
+ OutStreamer->EmitZeros(1);
+ }
+ OutStreamer->PopSection();
+}
+
//===--------------------------------------------------------------------===//
// Emission and print routines
//
diff --git a/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp b/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
index 394281e3329..cb2fe691d70 100644
--- a/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
+++ b/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
@@ -795,6 +795,14 @@ const MCExpr *TargetLoweringObjectFileELF::lowerRelativeReference(
MCSymbolRefExpr::create(TM.getSymbol(RHS), getContext()), getContext());
}
+MCSection *TargetLoweringObjectFileELF::getSectionForCommandLines() const {
+ // Use ".GCC.command.line" since this feature is to support clang's
+ // -frecord-gcc-switches which in turn attempts to mimic GCC's switch of the
+ // same name.
+ return getContext().getELFSection(".GCC.command.line", ELF::SHT_PROGBITS,
+ ELF::SHF_MERGE | ELF::SHF_STRINGS, 1, "");
+}
+
void
TargetLoweringObjectFileELF::InitializeELF(bool UseInitArray_) {
UseInitArray = UseInitArray_;
diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp
index a31f7cddf6e..7fd6df3e6e0 100644
--- a/llvm/lib/IR/Verifier.cpp
+++ b/llvm/lib/IR/Verifier.cpp
@@ -386,6 +386,7 @@ public:
visitModuleFlags(M);
visitModuleIdents(M);
+ visitModuleCommandLines(M);
verifyCompileUnits();
@@ -408,6 +409,7 @@ private:
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<const MDString *, const MDNode *> &SeenIDs,
@@ -1313,6 +1315,24 @@ void Verifier::visitModuleIdents(const Module &M) {
}
}
+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<MDString>(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;
diff --git a/llvm/test/CodeGen/X86/commandline-metadata.ll b/llvm/test/CodeGen/X86/commandline-metadata.ll
new file mode 100644
index 00000000000..de77dd27b16
--- /dev/null
+++ b/llvm/test/CodeGen/X86/commandline-metadata.ll
@@ -0,0 +1,13 @@
+; RUN: llc -mtriple=x86_64-linux < %s | FileCheck %s
+; Verify that llvm.commandline metadata is emitted to a section named
+; .GCC.command.line with each line separated with null bytes.
+
+; CHECK: .section .GCC.command.line,"MS",@progbits,1
+; CHECK-NEXT: .zero 1
+; CHECK-NEXT: .ascii "clang -command -line"
+; CHECK-NEXT: .zero 1
+; CHECK-NEXT: .ascii "something else"
+; CHECK-NEXT: .zero 1
+!llvm.commandline = !{!0, !1}
+!0 = !{!"clang -command -line"}
+!1 = !{!"something else"}
diff --git a/llvm/test/Linker/Inputs/commandline.a.ll b/llvm/test/Linker/Inputs/commandline.a.ll
new file mode 100644
index 00000000000..445ee74301e
--- /dev/null
+++ b/llvm/test/Linker/Inputs/commandline.a.ll
@@ -0,0 +1,3 @@
+!llvm.commandline = !{!0, !1}
+!0 = !{!"compiler -v1"}
+!1 = !{!"compiler -v2"}
diff --git a/llvm/test/Linker/Inputs/commandline.b.ll b/llvm/test/Linker/Inputs/commandline.b.ll
new file mode 100644
index 00000000000..16011fc4055
--- /dev/null
+++ b/llvm/test/Linker/Inputs/commandline.b.ll
@@ -0,0 +1,2 @@
+!llvm.commandline = !{!0}
+!0 = !{!"compiler -v3"}
diff --git a/llvm/test/Linker/commandline.ll b/llvm/test/Linker/commandline.ll
new file mode 100644
index 00000000000..ba201c82be9
--- /dev/null
+++ b/llvm/test/Linker/commandline.ll
@@ -0,0 +1,8 @@
+; 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: !{{[0-2]}} = !{!"compiler -v1"}
+; CHECK-DAG: !{{[0-2]}} = !{!"compiler -v2"}
+; CHECK-DAG: !{{[0-2]}} = !{!"compiler -v3"}
diff --git a/llvm/test/Verifier/commandline-meta1.ll b/llvm/test/Verifier/commandline-meta1.ll
new file mode 100644
index 00000000000..5c39bbdde6d
--- /dev/null
+++ b/llvm/test/Verifier/commandline-meta1.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 have only one string.
+
+!llvm.commandline = !{!0}
+!0 = !{!"string1", !"string2"}
+; CHECK: assembly parsed, but does not verify as correct!
+; CHECK-NEXT: incorrect number of operands in llvm.commandline metadata
+; CHECK-NEXT: !0
diff --git a/llvm/test/Verifier/commandline-meta2.ll b/llvm/test/Verifier/commandline-meta2.ll
new file mode 100644
index 00000000000..46eeb8cdf4e
--- /dev/null
+++ b/llvm/test/Verifier/commandline-meta2.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 = !{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
diff --git a/llvm/test/Verifier/commandline-meta3.ll b/llvm/test/Verifier/commandline-meta3.ll
new file mode 100644
index 00000000000..f27f7ca5650
--- /dev/null
+++ b/llvm/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
diff --git a/llvm/test/Verifier/commandline-meta4.ll b/llvm/test/Verifier/commandline-meta4.ll
new file mode 100644
index 00000000000..b0d103c4b23
--- /dev/null
+++ b/llvm/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)
OpenPOWER on IntegriCloud