.. 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
.. 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
/// 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.
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=">,
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>,
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]>;
if (getCodeGenOpts().EmitVersionIdentMetadata)
EmitVersionIdentMetadata();
+ if (!getCodeGenOpts().RecordCommandLine.empty())
+ EmitCommandLineMetadata();
+
EmitTargetMetadata();
}
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
/// 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();
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);
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
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);
// 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
// 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
//
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);
const MCExpr *lowerRelativeReference(const GlobalValue *LHS,
const GlobalValue *RHS,
const TargetMachine &TM) const override;
+
+ MCSection *getSectionForCommandLines() const override;
};
class TargetLoweringObjectFileMachO : public TargetLoweringObjectFile {
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,
// 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;
}
}
+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
//
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_;
visitModuleFlags(M);
visitModuleIdents(M);
+ visitModuleCommandLines(M);
verifyCompileUnits();
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,
}
}
+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;
--- /dev/null
+; 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"}
--- /dev/null
+!llvm.commandline = !{!0, !1}
+!0 = !{!"compiler -v1"}
+!1 = !{!"compiler -v2"}
--- /dev/null
+!llvm.commandline = !{!0}
+!0 = !{!"compiler -v3"}
--- /dev/null
+; 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"}
--- /dev/null
+; 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
--- /dev/null
+; 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
--- /dev/null
+; 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
--- /dev/null
+; 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)