Skip to content

Commit 6df2f16

Browse files
author
Tarun Prabhu
committed
[clang][flang][mlir] Support -frecord-command-line option
Add support for the -frecord-command-line option that will produce the llvm.commandline metadata which will eventually be saved in the object file. This behavior is also supported in clang. Some refactoring of the code in flang to handle these command line options was carried out. The corresponding -grecord-command-line option which saves the command line in the debug information has not yet been enabled for flang.
1 parent 3726f9c commit 6df2f16

File tree

24 files changed

+284
-59
lines changed

24 files changed

+284
-59
lines changed

clang/include/clang/Driver/Options.td

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1981,16 +1981,18 @@ def fparse_all_comments : Flag<["-"], "fparse-all-comments">, Group<f_clang_Grou
19811981
Visibility<[ClangOption, CC1Option]>,
19821982
MarshallingInfoFlag<LangOpts<"CommentOpts.ParseAllComments">>;
19831983
def frecord_command_line : Flag<["-"], "frecord-command-line">,
1984-
DocBrief<[{Generate a section named ".GCC.command.line" containing the clang
1984+
DocBrief<[{Generate a section named ".GCC.command.line" containing the
19851985
driver command-line. After linking, the section may contain multiple command
19861986
lines, which will be individually terminated by null bytes. Separate arguments
19871987
within a command line are combined with spaces; spaces and backslashes within an
19881988
argument are escaped with backslashes. This format differs from the format of
19891989
the equivalent section produced by GCC with the -frecord-gcc-switches flag.
19901990
This option is currently only supported on ELF targets.}]>,
1991-
Group<f_clang_Group>;
1991+
Group<f_clang_Group>,
1992+
Visibility<[ClangOption, CLOption, DXCOption, FlangOption]>;
19921993
def fno_record_command_line : Flag<["-"], "fno-record-command-line">,
1993-
Group<f_clang_Group>;
1994+
Group<f_clang_Group>,
1995+
Visibility<[ClangOption, CLOption, DXCOption, FlangOption]>;
19941996
def : Flag<["-"], "frecord-gcc-switches">, Alias<frecord_command_line>;
19951997
def : Flag<["-"], "fno-record-gcc-switches">, Alias<fno_record_command_line>;
19961998
def fcommon : Flag<["-"], "fcommon">, Group<f_Group>,
@@ -7123,6 +7125,9 @@ def mrelocation_model : Separate<["-"], "mrelocation-model">,
71237125
NormalizedValues<["Static", "PIC_", "ROPI", "RWPI", "ROPI_RWPI", "DynamicNoPIC"]>,
71247126
MarshallingInfoEnum<CodeGenOpts<"RelocationModel">, "PIC_">;
71257127
def debug_info_kind_EQ : Joined<["-"], "debug-info-kind=">;
7128+
def record_command_line : Separate<["-"], "record-command-line">,
7129+
HelpText<"The string to embed in the .LLVM.command.line section.">,
7130+
MarshallingInfoString<CodeGenOpts<"RecordCommandLine">>;
71267131

71277132
} // let Visibility = [CC1Option, CC1AsOption, FC1Option]
71287133

@@ -7143,9 +7148,6 @@ def debugger_tuning_EQ : Joined<["-"], "debugger-tuning=">,
71437148
def dwarf_debug_flags : Separate<["-"], "dwarf-debug-flags">,
71447149
HelpText<"The string to embed in the Dwarf debug flags record.">,
71457150
MarshallingInfoString<CodeGenOpts<"DwarfDebugFlags">>;
7146-
def record_command_line : Separate<["-"], "record-command-line">,
7147-
HelpText<"The string to embed in the .LLVM.command.line section.">,
7148-
MarshallingInfoString<CodeGenOpts<"RecordCommandLine">>;
71497151
def compress_debug_sections_EQ : Joined<["-", "--"], "compress-debug-sections=">,
71507152
HelpText<"DWARF debug sections compression type">, Values<"none,zlib,zstd">,
71517153
NormalizedValuesScope<"llvm::DebugCompressionType">, NormalizedValues<["None", "Zlib", "Zstd"]>,

clang/lib/Driver/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ add_clang_library(clangDriver
4848
ToolChains/BareMetal.cpp
4949
ToolChains/Clang.cpp
5050
ToolChains/CommonArgs.cpp
51+
ToolChains/CommonUtils.cpp
5152
ToolChains/CrossWindows.cpp
5253
ToolChains/CSKYToolChain.cpp
5354
ToolChains/Cuda.cpp

clang/lib/Driver/ToolChains/Clang.cpp

Lines changed: 5 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "Arch/VE.h"
2222
#include "Arch/X86.h"
2323
#include "CommonArgs.h"
24+
#include "CommonUtils.h"
2425
#include "Hexagon.h"
2526
#include "MSP430.h"
2627
#include "PS4CPU.h"
@@ -94,24 +95,6 @@ static void CheckCodeGenerationOptions(const Driver &D, const ArgList &Args) {
9495
<< "-static";
9596
}
9697

97-
// Add backslashes to escape spaces and other backslashes.
98-
// This is used for the space-separated argument list specified with
99-
// the -dwarf-debug-flags option.
100-
static void EscapeSpacesAndBackslashes(const char *Arg,
101-
SmallVectorImpl<char> &Res) {
102-
for (; *Arg; ++Arg) {
103-
switch (*Arg) {
104-
default:
105-
break;
106-
case ' ':
107-
case '\\':
108-
Res.push_back('\\');
109-
break;
110-
}
111-
Res.push_back(*Arg);
112-
}
113-
}
114-
11598
/// Apply \a Work on the current tool chain \a RegularToolChain and any other
11699
/// offloading tool chain that is associated with the current action \a JA.
117100
static void
@@ -7700,31 +7683,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
77007683
// Also record command line arguments into the debug info if
77017684
// -grecord-gcc-switches options is set on.
77027685
// By default, -gno-record-gcc-switches is set on and no recording.
7703-
auto GRecordSwitches =
7704-
Args.hasFlag(options::OPT_grecord_command_line,
7705-
options::OPT_gno_record_command_line, false);
7706-
auto FRecordSwitches =
7707-
Args.hasFlag(options::OPT_frecord_command_line,
7708-
options::OPT_fno_record_command_line, false);
7709-
if (FRecordSwitches && !Triple.isOSBinFormatELF() &&
7710-
!Triple.isOSBinFormatXCOFF() && !Triple.isOSBinFormatMachO())
7711-
D.Diag(diag::err_drv_unsupported_opt_for_target)
7712-
<< Args.getLastArg(options::OPT_frecord_command_line)->getAsString(Args)
7713-
<< TripleStr;
7714-
if (TC.UseDwarfDebugFlags() || GRecordSwitches || FRecordSwitches) {
7715-
ArgStringList OriginalArgs;
7716-
for (const auto &Arg : Args)
7717-
Arg->render(Args, OriginalArgs);
7718-
7719-
SmallString<256> Flags;
7720-
EscapeSpacesAndBackslashes(Exec, Flags);
7721-
for (const char *OriginalArg : OriginalArgs) {
7722-
SmallString<128> EscapedArg;
7723-
EscapeSpacesAndBackslashes(OriginalArg, EscapedArg);
7724-
Flags += " ";
7725-
Flags += EscapedArg;
7726-
}
7727-
auto FlagsArgString = Args.MakeArgString(Flags);
7686+
auto GRecordSwitches = false;
7687+
auto FRecordSwitches = false;
7688+
if (ShouldRecordCommandLine(TC, Args, FRecordSwitches, GRecordSwitches)) {
7689+
auto FlagsArgString = RenderEscapedCommandLine(TC, Args);
77287690
if (TC.UseDwarfDebugFlags() || GRecordSwitches) {
77297691
CmdArgs.push_back("-dwarf-debug-flags");
77307692
CmdArgs.push_back(FlagsArgString);
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
//===--- CommonUtils.h - Common utilities for the toolchains ----*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "CommonUtils.h"
10+
#include "clang/Driver/Driver.h"
11+
#include "llvm/ADT/SmallString.h"
12+
13+
using namespace clang::driver;
14+
15+
namespace clang {
16+
17+
void EscapeSpacesAndBackslashes(const char *Arg,
18+
llvm::SmallVectorImpl<char> &Res) {
19+
for (; *Arg; ++Arg) {
20+
switch (*Arg) {
21+
default:
22+
break;
23+
case ' ':
24+
case '\\':
25+
Res.push_back('\\');
26+
break;
27+
}
28+
Res.push_back(*Arg);
29+
}
30+
}
31+
32+
const char *RenderEscapedCommandLine(const ToolChain &TC,
33+
const llvm::opt::ArgList &Args) {
34+
const Driver &D = TC.getDriver();
35+
const char *Exec = D.getClangProgramPath();
36+
37+
llvm::opt::ArgStringList OriginalArgs;
38+
for (const auto &Arg : Args)
39+
Arg->render(Args, OriginalArgs);
40+
41+
llvm::SmallString<256> Flags;
42+
EscapeSpacesAndBackslashes(Exec, Flags);
43+
for (const char *OriginalArg : OriginalArgs) {
44+
llvm::SmallString<128> EscapedArg;
45+
EscapeSpacesAndBackslashes(OriginalArg, EscapedArg);
46+
Flags += " ";
47+
Flags += EscapedArg;
48+
}
49+
50+
return Args.MakeArgString(Flags);
51+
}
52+
53+
bool ShouldRecordCommandLine(const ToolChain &TC,
54+
const llvm::opt::ArgList &Args,
55+
bool &FRecordCommandLine,
56+
bool &GRecordCommandLine) {
57+
const Driver &D = TC.getDriver();
58+
const llvm::Triple &Triple = TC.getEffectiveTriple();
59+
const std::string &TripleStr = Triple.getTriple();
60+
61+
FRecordCommandLine =
62+
Args.hasFlag(options::OPT_frecord_command_line,
63+
options::OPT_fno_record_command_line, false);
64+
GRecordCommandLine =
65+
Args.hasFlag(options::OPT_grecord_command_line,
66+
options::OPT_gno_record_command_line, false);
67+
if (FRecordCommandLine && !Triple.isOSBinFormatELF() &&
68+
!Triple.isOSBinFormatXCOFF() && !Triple.isOSBinFormatMachO())
69+
D.Diag(diag::err_drv_unsupported_opt_for_target)
70+
<< Args.getLastArg(options::OPT_frecord_command_line)->getAsString(Args)
71+
<< TripleStr;
72+
73+
return FRecordCommandLine || TC.UseDwarfDebugFlags() || GRecordCommandLine;
74+
}
75+
76+
} // namespace clang
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
//===--- CommonUtils.h - Common utilities for the toolchains ----*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_COMMONUTILS_H
10+
#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_COMMONUTILS_H
11+
12+
#include "clang/Driver/ToolChain.h"
13+
#include "llvm/ADT/SmallVector.h"
14+
#include "llvm/Option/ArgList.h"
15+
16+
namespace clang {
17+
18+
// Add backslashes to escape spaces and other backslashes.
19+
// This is used for the space-separated argument list specified with
20+
// the -dwarf-debug-flags option.
21+
void EscapeSpacesAndBackslashes(const char *Arg,
22+
llvm::SmallVectorImpl<char> &Res);
23+
24+
/// Join the args in the given ArgList, escape spaces and backslashes and
25+
/// return the joined string. This is used when saving the command line as a
26+
/// result of using either the -frecord-command-line or -grecord-command-line
27+
/// options. The lifetime of the returned c-string will match that of the Args
28+
/// argument.
29+
const char *RenderEscapedCommandLine(const clang::driver::ToolChain &TC,
30+
const llvm::opt::ArgList &Args);
31+
32+
/// Check if the command line should be recorded in the object file. This is
33+
/// done if either -frecord-command-line or -grecord-command-line options have
34+
/// been passed. This also does some error checking since -frecord-command-line
35+
/// is currently only supported on ELF platforms. The last two boolean
36+
/// arguments are out parameters and will be set depending on the command
37+
/// line options that were passed.
38+
bool ShouldRecordCommandLine(const clang::driver::ToolChain &TC,
39+
const llvm::opt::ArgList &Args,
40+
bool &FRecordCommandLine,
41+
bool &GRecordCommandLine);
42+
} // namespace clang
43+
44+
#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_COMMONUTILS_H

clang/lib/Driver/ToolChains/Flang.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include "Flang.h"
1010
#include "Arch/RISCV.h"
1111
#include "CommonArgs.h"
12+
#include "CommonUtils.h"
1213

1314
#include "clang/Basic/CodeGenOptions.h"
1415
#include "clang/Driver/Options.h"
@@ -885,6 +886,20 @@ void Flang::ConstructJob(Compilation &C, const JobAction &JA,
885886

886887
addDashXForInput(Args, Input, CmdArgs);
887888

889+
bool FRecordCmdLine = false;
890+
bool GRecordCmdLine = false;
891+
if (ShouldRecordCommandLine(TC, Args, FRecordCmdLine, GRecordCmdLine)) {
892+
const char *CmdLine = RenderEscapedCommandLine(TC, Args);
893+
if (FRecordCmdLine) {
894+
CmdArgs.push_back("-record-command-line");
895+
CmdArgs.push_back(CmdLine);
896+
}
897+
if (TC.UseDwarfDebugFlags() || GRecordCmdLine) {
898+
CmdArgs.push_back("-dwarf-debug-flags");
899+
CmdArgs.push_back(CmdLine);
900+
}
901+
}
902+
888903
CmdArgs.push_back(Input.getFilename());
889904

890905
// TODO: Replace flang-new with flang once the new driver replaces the

flang/include/flang/Frontend/CodeGenOptions.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,9 @@ class CodeGenOptions : public CodeGenOptionsBase {
6363
/// The directory where temp files are stored if specified by -save-temps
6464
std::optional<std::string> SaveTempsDir;
6565

66+
/// The string containing the commandline for the llvm.commandline metadata.
67+
std::optional<std::string> RecordCommandLine;
68+
6669
/// The name of the file to which the backend should save YAML optimization
6770
/// records.
6871
std::string OptRecordFile;

flang/include/flang/Lower/Bridge.h

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
#define FORTRAN_LOWER_BRIDGE_H
1515

1616
#include "flang/Common/Fortran.h"
17+
#include "flang/Frontend/CodeGenOptions.h"
18+
#include "flang/Frontend/TargetOptions.h"
1719
#include "flang/Lower/AbstractConverter.h"
1820
#include "flang/Lower/EnvironmentDefault.h"
1921
#include "flang/Lower/LoweringOptions.h"
@@ -65,11 +67,13 @@ class LoweringBridge {
6567
const Fortran::lower::LoweringOptions &loweringOptions,
6668
const std::vector<Fortran::lower::EnvironmentDefault> &envDefaults,
6769
const Fortran::common::LanguageFeatureControl &languageFeatures,
68-
const llvm::TargetMachine &targetMachine, llvm::StringRef tuneCPU) {
70+
const llvm::TargetMachine &targetMachine,
71+
const Fortran::frontend::TargetOptions &targetOptions,
72+
const Fortran::frontend::CodeGenOptions &codeGenOptions) {
6973
return LoweringBridge(ctx, semanticsContext, defaultKinds, intrinsics,
7074
targetCharacteristics, allCooked, triple, kindMap,
7175
loweringOptions, envDefaults, languageFeatures,
72-
targetMachine, tuneCPU);
76+
targetMachine, targetOptions, codeGenOptions);
7377
}
7478

7579
//===--------------------------------------------------------------------===//
@@ -148,7 +152,9 @@ class LoweringBridge {
148152
const Fortran::lower::LoweringOptions &loweringOptions,
149153
const std::vector<Fortran::lower::EnvironmentDefault> &envDefaults,
150154
const Fortran::common::LanguageFeatureControl &languageFeatures,
151-
const llvm::TargetMachine &targetMachine, const llvm::StringRef tuneCPU);
155+
const llvm::TargetMachine &targetMachine,
156+
const Fortran::frontend::TargetOptions &targetOptions,
157+
const Fortran::frontend::CodeGenOptions &codeGenOptions);
152158
LoweringBridge() = delete;
153159
LoweringBridge(const LoweringBridge &) = delete;
154160

flang/include/flang/Optimizer/Dialect/Support/FIRContext.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,12 @@ void setIdent(mlir::ModuleOp mod, llvm::StringRef ident);
7777
/// Get the compiler identifier from the Module.
7878
llvm::StringRef getIdent(mlir::ModuleOp mod);
7979

80+
/// Set the command line used in this invocation.
81+
void setCommandline(mlir::ModuleOp mod, llvm::StringRef cmdLine);
82+
83+
/// Get the command line used in this invocation.
84+
llvm::StringRef getCommandline(mlir::ModuleOp mod);
85+
8086
/// Helper for determining the target from the host, etc. Tools may use this
8187
/// function to provide a consistent interpretation of the `--target=<string>`
8288
/// command-line option.

flang/lib/Frontend/CompilerInvocation.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -348,6 +348,12 @@ static void parseCodeGenArgs(Fortran::frontend::CodeGenOptions &opts,
348348
if (auto *a = args.getLastArg(clang::driver::options::OPT_save_temps_EQ))
349349
opts.SaveTempsDir = a->getValue();
350350

351+
// -record-command-line option.
352+
if (const llvm::opt::Arg *a =
353+
args.getLastArg(clang::driver::options::OPT_record_command_line)) {
354+
opts.RecordCommandLine = a->getValue();
355+
}
356+
351357
// -mlink-builtin-bitcode
352358
for (auto *a :
353359
args.filtered(clang::driver::options::OPT_mlink_builtin_bitcode))

flang/lib/Frontend/FrontendActions.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -302,7 +302,7 @@ bool CodeGenAction::beginSourceFileAction() {
302302
kindMap, ci.getInvocation().getLoweringOpts(),
303303
ci.getInvocation().getFrontendOpts().envDefaults,
304304
ci.getInvocation().getFrontendOpts().features, targetMachine,
305-
ci.getInvocation().getTargetOpts().cpuToTuneFor);
305+
ci.getInvocation().getTargetOpts(), ci.getInvocation().getCodeGenOpts());
306306

307307
// Fetch module from lb, so we can set
308308
mlirModule = std::make_unique<mlir::ModuleOp>(lb.getModule());

flang/lib/Lower/Bridge.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6070,7 +6070,9 @@ Fortran::lower::LoweringBridge::LoweringBridge(
60706070
const Fortran::lower::LoweringOptions &loweringOptions,
60716071
const std::vector<Fortran::lower::EnvironmentDefault> &envDefaults,
60726072
const Fortran::common::LanguageFeatureControl &languageFeatures,
6073-
const llvm::TargetMachine &targetMachine, const llvm::StringRef tuneCPU)
6073+
const llvm::TargetMachine &targetMachine,
6074+
const Fortran::frontend::TargetOptions &targetOpts,
6075+
const Fortran::frontend::CodeGenOptions &cgOpts)
60746076
: semanticsContext{semanticsContext}, defaultKinds{defaultKinds},
60756077
intrinsics{intrinsics}, targetCharacteristics{targetCharacteristics},
60766078
cooked{&cooked}, context{context}, kindMap{kindMap},
@@ -6127,11 +6129,13 @@ Fortran::lower::LoweringBridge::LoweringBridge(
61276129
fir::setTargetTriple(*module.get(), triple);
61286130
fir::setKindMapping(*module.get(), kindMap);
61296131
fir::setTargetCPU(*module.get(), targetMachine.getTargetCPU());
6130-
fir::setTuneCPU(*module.get(), tuneCPU);
6132+
fir::setTuneCPU(*module.get(), targetOpts.cpuToTuneFor);
61316133
fir::setTargetFeatures(*module.get(), targetMachine.getTargetFeatureString());
61326134
fir::support::setMLIRDataLayout(*module.get(),
61336135
targetMachine.createDataLayout());
61346136
fir::setIdent(*module.get(), Fortran::common::getFlangFullVersion());
6137+
if (cgOpts.RecordCommandLine)
6138+
fir::setCommandline(*module.get(), *cgOpts.RecordCommandLine);
61356139
}
61366140

61376141
void Fortran::lower::genCleanUpInRegionIfAny(

flang/lib/Optimizer/Dialect/Support/FIRContext.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,22 @@ llvm::StringRef fir::getIdent(mlir::ModuleOp mod) {
130130
return {};
131131
}
132132

133+
void fir::setCommandline(mlir::ModuleOp mod, llvm::StringRef cmdLine) {
134+
if (cmdLine.empty())
135+
return;
136+
137+
mlir::MLIRContext *ctx = mod.getContext();
138+
mod->setAttr(mlir::LLVM::LLVMDialect::getCommandlineAttrName(),
139+
mlir::StringAttr::get(ctx, cmdLine));
140+
}
141+
142+
llvm::StringRef fir::getCommandline(mlir::ModuleOp mod) {
143+
if (auto attr = mod->getAttrOfType<mlir::StringAttr>(
144+
mlir::LLVM::LLVMDialect::getCommandlineAttrName()))
145+
return attr;
146+
return {};
147+
}
148+
133149
std::string fir::determineTargetTriple(llvm::StringRef triple) {
134150
// Treat "" or "default" as stand-ins for the default machine.
135151
if (triple.empty() || triple == "default")

0 commit comments

Comments
 (0)