Skip to content

Commit

Permalink
Implement -frecord-command-line (-frecord-gcc-switches)
Browse files Browse the repository at this point in the history
Implement options in clang to enable recording the driver command-line
in an ELF section.

Implement a new special named metadata, llvm.commandline, to support
frontends embedding their command-line options in IR/ASM/ELF.

This differs from the GCC implementation in some key ways:

* In GCC there is only one command-line possible per compilation-unit,
  in LLVM it mirrors llvm.ident and multiple are allowed.
* In GCC individual options are separated by NULL bytes, in LLVM entire
  command-lines are separated by NULL bytes. The advantage of the GCC
  approach is to clearly delineate options in the face of embedded
  spaces. The advantage of the LLVM approach is to support merging
  multiple command-lines unambiguously, while handling embedded spaces
  with escaping.

Differential Revision: https://reviews.llvm.org/D54487
Clang Differential Revision: https://reviews.llvm.org/D54489

llvm-svn: 349155
  • Loading branch information
scott-linder committed Dec 14, 2018
1 parent eed7b2e commit de6beb0
Show file tree
Hide file tree
Showing 24 changed files with 222 additions and 10 deletions.
12 changes: 11 additions & 1 deletion clang/docs/ClangCommandLineReference.rst
Expand Up @@ -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
Expand Down Expand Up @@ -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

Expand Down
4 changes: 4 additions & 0 deletions clang/include/clang/Basic/CodeGenOptions.h
Expand Up @@ -148,6 +148,10 @@ class CodeGenOptions : public CodeGenOptionsBase {
/// 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.
Expand Down
2 changes: 2 additions & 0 deletions clang/include/clang/Driver/CC1Options.td
Expand Up @@ -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=">,
Expand Down
13 changes: 11 additions & 2 deletions clang/include/clang/Driver/Options.td
Expand Up @@ -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>,
Expand Down Expand Up @@ -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]>;
Expand Down
13 changes: 13 additions & 0 deletions clang/lib/CodeGen/CodeGenModule.cpp
Expand Up @@ -590,6 +590,9 @@ void CodeGenModule::Release() {
if (getCodeGenOpts().EmitVersionIdentMetadata)
EmitVersionIdentMetadata();

if (!getCodeGenOpts().RecordCommandLine.empty())
EmitCommandLineMetadata();

EmitTargetMetadata();
}

Expand Down Expand Up @@ -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
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/CodeGen/CodeGenModule.h
Expand Up @@ -1408,6 +1408,9 @@ class CodeGenModule : public CodeGenTypeCache {
/// 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();

Expand Down
29 changes: 22 additions & 7 deletions clang/lib/Driver/ToolChains/Clang.cpp
Expand Up @@ -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);
Expand All @@ -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
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Frontend/CompilerInvocation.cpp
Expand Up @@ -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);
Expand Down
15 changes: 15 additions & 0 deletions clang/test/Driver/clang_f_opts.c
Expand Up @@ -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
11 changes: 11 additions & 0 deletions clang/test/Driver/debug-options.c
Expand Up @@ -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
//
Expand Down
2 changes: 2 additions & 0 deletions llvm/include/llvm/CodeGen/AsmPrinter.h
Expand Up @@ -656,6 +656,8 @@ class AsmPrinter : public MachineFunctionPass {
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);

Expand Down
2 changes: 2 additions & 0 deletions llvm/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h
Expand Up @@ -90,6 +90,8 @@ class TargetLoweringObjectFileELF : public TargetLoweringObjectFile {
const MCExpr *lowerRelativeReference(const GlobalValue *LHS,
const GlobalValue *RHS,
const TargetMachine &TM) const override;

MCSection *getSectionForCommandLines() const override;
};

class TargetLoweringObjectFileMachO : public TargetLoweringObjectFile {
Expand Down
6 changes: 6 additions & 0 deletions llvm/include/llvm/Target/TargetLoweringObjectFile.h
Expand Up @@ -201,6 +201,12 @@ class TargetLoweringObjectFile : public MCObjectFileInfo {
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,
Expand Down
26 changes: 26 additions & 0 deletions llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
Expand Up @@ -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;
Expand Down Expand Up @@ -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
//
Expand Down
8 changes: 8 additions & 0 deletions llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
Expand Up @@ -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_;
Expand Down
20 changes: 20 additions & 0 deletions llvm/lib/IR/Verifier.cpp
Expand Up @@ -386,6 +386,7 @@ class Verifier : public InstVisitor<Verifier>, VerifierSupport {

visitModuleFlags(M);
visitModuleIdents(M);
visitModuleCommandLines(M);

verifyCompileUnits();

Expand All @@ -408,6 +409,7 @@ class Verifier : public InstVisitor<Verifier>, VerifierSupport {
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,
Expand Down Expand Up @@ -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;
Expand Down
13 changes: 13 additions & 0 deletions 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"}
3 changes: 3 additions & 0 deletions llvm/test/Linker/Inputs/commandline.a.ll
@@ -0,0 +1,3 @@
!llvm.commandline = !{!0, !1}
!0 = !{!"compiler -v1"}
!1 = !{!"compiler -v2"}
2 changes: 2 additions & 0 deletions llvm/test/Linker/Inputs/commandline.b.ll
@@ -0,0 +1,2 @@
!llvm.commandline = !{!0}
!0 = !{!"compiler -v3"}
8 changes: 8 additions & 0 deletions 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"}
10 changes: 10 additions & 0 deletions 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
10 changes: 10 additions & 0 deletions 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
10 changes: 10 additions & 0 deletions 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

0 comments on commit de6beb0

Please sign in to comment.