Skip to content

Commit

Permalink
[LTO][clang] Teaching Clang to Pass Plugin Options to the AIX Linker
Browse files Browse the repository at this point in the history
This patch teaches `clang` to use the prefix `-bplugin_opt:` (instead of `-plugin-opt`) on AIX, when passing plugin options to the linker. This patch follows https://reviews.llvm.org/D134668.

We put the code that decides what plugin option prefix to use at the top of the function `tools::addLTOOptions`. The plugin option prefix, the mcpu prefix, and the opt level prefix are different on AIX. We thought about choosing the strings in a function that reads the linker name and the target triple, or we could push the logic into different derived `ToolChain` classes. But this logic would not be used anywhere else, so these alternatives looked too complicated for what they did. Therefore we are doing it the current way. That said, I am all ears for suggestions to improve this code!

Subsequent code uses the `PluginOptPrefix` variable consistently instead of the hardcoded `-plugin-opt`.

Reviewed By: MaskRay

Differential Revision: https://reviews.llvm.org/D134820
  • Loading branch information
qiongsiwu committed Oct 12, 2022
1 parent 5f095e4 commit ec94f37
Show file tree
Hide file tree
Showing 5 changed files with 113 additions and 69 deletions.
6 changes: 6 additions & 0 deletions clang/lib/Driver/ToolChains/AIX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,12 @@ void aix::Linker::ConstructJob(Compilation &C, const JobAction &JA,
// Specify linker input file(s).
AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA);

if (D.isUsingLTO()) {
assert(!Inputs.empty() && "Must have at least one input.");
addLTOOptions(ToolChain, Args, CmdArgs, Output, Inputs[0],
D.getLTOMode() == LTOK_Thin);
}

if (Args.hasArg(options::OPT_shared) && !hasExportListLinkerOpts(CmdArgs)) {

const char *CreateExportListExec = Args.MakeArgString(
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Driver/ToolChains/AIX.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ class LLVM_LIBRARY_VISIBILITY AIX : public ToolChain {
return false;
}
bool isPICDefaultForced() const override { return true; }
bool HasNativeLLVMSupport() const override { return true; }

void
AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs,
Expand Down
163 changes: 96 additions & 67 deletions clang/lib/Driver/ToolChains/CommonArgs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,24 +65,26 @@ using namespace clang::driver::tools;
using namespace clang;
using namespace llvm::opt;

static void renderRpassOptions(const ArgList &Args, ArgStringList &CmdArgs) {
static void renderRpassOptions(const ArgList &Args, ArgStringList &CmdArgs,
const StringRef PluginOptPrefix) {
if (const Arg *A = Args.getLastArg(options::OPT_Rpass_EQ))
CmdArgs.push_back(Args.MakeArgString(Twine("-plugin-opt=-pass-remarks=") +
A->getValue()));
CmdArgs.push_back(Args.MakeArgString(Twine(PluginOptPrefix) +
"-pass-remarks=" + A->getValue()));

if (const Arg *A = Args.getLastArg(options::OPT_Rpass_missed_EQ))
CmdArgs.push_back(Args.MakeArgString(
Twine("-plugin-opt=-pass-remarks-missed=") + A->getValue()));
Twine(PluginOptPrefix) + "-pass-remarks-missed=" + A->getValue()));

if (const Arg *A = Args.getLastArg(options::OPT_Rpass_analysis_EQ))
CmdArgs.push_back(Args.MakeArgString(
Twine("-plugin-opt=-pass-remarks-analysis=") + A->getValue()));
Twine(PluginOptPrefix) + "-pass-remarks-analysis=" + A->getValue()));
}

static void renderRemarksOptions(const ArgList &Args, ArgStringList &CmdArgs,
const llvm::Triple &Triple,
const InputInfo &Input,
const InputInfo &Output) {
const InputInfo &Output,
const StringRef PluginOptPrefix) {
StringRef Format = "yaml";
if (const Arg *A = Args.getLastArg(options::OPT_fsave_optimization_record_EQ))
Format = A->getValue();
Expand All @@ -96,29 +98,32 @@ static void renderRemarksOptions(const ArgList &Args, ArgStringList &CmdArgs,

assert(!F.empty() && "Cannot determine remarks output name.");
// Append "opt.ld.<format>" to the end of the file name.
CmdArgs.push_back(
Args.MakeArgString(Twine("-plugin-opt=opt-remarks-filename=") + F +
Twine(".opt.ld.") + Format));
CmdArgs.push_back(Args.MakeArgString(Twine(PluginOptPrefix) +
"opt-remarks-filename=" + F +
".opt.ld." + Format));

if (const Arg *A =
Args.getLastArg(options::OPT_foptimization_record_passes_EQ))
CmdArgs.push_back(Args.MakeArgString(
Twine("-plugin-opt=opt-remarks-passes=") + A->getValue()));
Twine(PluginOptPrefix) + "opt-remarks-passes=" + A->getValue()));

CmdArgs.push_back(Args.MakeArgString(
Twine("-plugin-opt=opt-remarks-format=") + Format.data()));
CmdArgs.push_back(Args.MakeArgString(Twine(PluginOptPrefix) +
"opt-remarks-format=" + Format.data()));
}

static void renderRemarksHotnessOptions(const ArgList &Args,
ArgStringList &CmdArgs) {
ArgStringList &CmdArgs,
const StringRef PluginOptPrefix) {
if (Args.hasFlag(options::OPT_fdiagnostics_show_hotness,
options::OPT_fno_diagnostics_show_hotness, false))
CmdArgs.push_back("-plugin-opt=opt-remarks-with-hotness");
CmdArgs.push_back(Args.MakeArgString(Twine(PluginOptPrefix) +
"opt-remarks-with-hotness"));

if (const Arg *A =
Args.getLastArg(options::OPT_fdiagnostics_hotness_threshold_EQ))
CmdArgs.push_back(Args.MakeArgString(
Twine("-plugin-opt=opt-remarks-hotness-threshold=") + A->getValue()));
CmdArgs.push_back(
Args.MakeArgString(Twine(PluginOptPrefix) +
"opt-remarks-hotness-threshold=" + A->getValue()));
}

void tools::addPathIfExists(const Driver &D, const Twine &Path,
Expand Down Expand Up @@ -484,14 +489,19 @@ bool tools::isUseSeparateSections(const llvm::Triple &Triple) {
void tools::addLTOOptions(const ToolChain &ToolChain, const ArgList &Args,
ArgStringList &CmdArgs, const InputInfo &Output,
const InputInfo &Input, bool IsThinLTO) {
const bool IsOSAIX = ToolChain.getTriple().isOSAIX();
const char *Linker = Args.MakeArgString(ToolChain.GetLinkerPath());
const Driver &D = ToolChain.getDriver();
if (llvm::sys::path::filename(Linker) != "ld.lld" &&
llvm::sys::path::stem(Linker) != "ld.lld") {
// Tell the linker to load the plugin. This has to come before
// AddLinkerInputs as gold requires -plugin to come before any -plugin-opt
// that -Wl might forward.
CmdArgs.push_back("-plugin");
// AddLinkerInputs as gold requires -plugin and AIX ld requires -bplugin to
// come before any -plugin-opt/-bplugin_opt that -Wl might forward.
const char *PluginPrefix = IsOSAIX ? "-bplugin:" : "";
const char *PluginName = IsOSAIX ? "/libLTO" : "/LLVMgold";

if (!IsOSAIX)
CmdArgs.push_back("-plugin");

#if defined(_WIN32)
const char *Suffix = ".dll";
Expand All @@ -502,19 +512,23 @@ void tools::addLTOOptions(const ToolChain &ToolChain, const ArgList &Args,
#endif

SmallString<1024> Plugin;
llvm::sys::path::native(
Twine(D.Dir) + "/../" CLANG_INSTALL_LIBDIR_BASENAME "/LLVMgold" +
Suffix,
Plugin);
CmdArgs.push_back(Args.MakeArgString(Plugin));
llvm::sys::path::native(Twine(D.Dir) +
"/../" CLANG_INSTALL_LIBDIR_BASENAME +
PluginName + Suffix,
Plugin);
CmdArgs.push_back(Args.MakeArgString(Twine(PluginPrefix) + Plugin));
}

const char *PluginOptPrefix = IsOSAIX ? "-bplugin_opt:" : "-plugin-opt=";
const char *mcpuOptPrefix = IsOSAIX ? "-mcpu=" : "mcpu=";
const char *OptLevelPrefix = IsOSAIX ? "-O" : "O";

// Note, this solution is far from perfect, better to encode it into IR
// metadata, but this may not be worth it, since it looks like aranges is on
// the way out.
if (Args.hasArg(options::OPT_gdwarf_aranges)) {
CmdArgs.push_back(
Args.MakeArgString("-plugin-opt=-generate-arange-section"));
CmdArgs.push_back(Args.MakeArgString(Twine(PluginOptPrefix) +
"-generate-arange-section"));
}

// Try to pass driver level flags relevant to LTO code generation down to
Expand All @@ -523,7 +537,8 @@ void tools::addLTOOptions(const ToolChain &ToolChain, const ArgList &Args,
// Handle flags for selecting CPU variants.
std::string CPU = getCPUName(D, Args, ToolChain.getTriple());
if (!CPU.empty())
CmdArgs.push_back(Args.MakeArgString(Twine("-plugin-opt=mcpu=") + CPU));
CmdArgs.push_back(
Args.MakeArgString(Twine(PluginOptPrefix) + mcpuOptPrefix + CPU));

if (Arg *A = Args.getLastArg(options::OPT_O_Group)) {
// The optimization level matches
Expand All @@ -541,65 +556,73 @@ void tools::addLTOOptions(const ToolChain &ToolChain, const ArgList &Args,
} else if (A->getOption().matches(options::OPT_O0))
OOpt = "0";
if (!OOpt.empty())
CmdArgs.push_back(Args.MakeArgString(Twine("-plugin-opt=O") + OOpt));
CmdArgs.push_back(
Args.MakeArgString(Twine(PluginOptPrefix) + OptLevelPrefix + OOpt));
}

if (Args.hasArg(options::OPT_gsplit_dwarf)) {
CmdArgs.push_back(
Args.MakeArgString(Twine("-plugin-opt=dwo_dir=") +
Output.getFilename() + "_dwo"));
}
if (Args.hasArg(options::OPT_gsplit_dwarf))
CmdArgs.push_back(Args.MakeArgString(
Twine(PluginOptPrefix) + "dwo_dir=" + Output.getFilename() + "_dwo"));

if (IsThinLTO)
CmdArgs.push_back("-plugin-opt=thinlto");
CmdArgs.push_back(Args.MakeArgString(Twine(PluginOptPrefix) + "thinlto"));

StringRef Parallelism = getLTOParallelism(Args, D);
if (!Parallelism.empty())
CmdArgs.push_back(
Args.MakeArgString("-plugin-opt=jobs=" + Twine(Parallelism)));
Args.MakeArgString(Twine(PluginOptPrefix) + "jobs=" + Parallelism));

// If an explicit debugger tuning argument appeared, pass it along.
if (Arg *A = Args.getLastArg(options::OPT_gTune_Group,
options::OPT_ggdbN_Group)) {
if (Arg *A =
Args.getLastArg(options::OPT_gTune_Group, options::OPT_ggdbN_Group)) {
if (A->getOption().matches(options::OPT_glldb))
CmdArgs.push_back("-plugin-opt=-debugger-tune=lldb");
CmdArgs.push_back(
Args.MakeArgString(Twine(PluginOptPrefix) + "-debugger-tune=lldb"));
else if (A->getOption().matches(options::OPT_gsce))
CmdArgs.push_back("-plugin-opt=-debugger-tune=sce");
CmdArgs.push_back(
Args.MakeArgString(Twine(PluginOptPrefix) + "-debugger-tune=sce"));
else if (A->getOption().matches(options::OPT_gdbx))
CmdArgs.push_back("-plugin-opt=-debugger-tune=dbx");
CmdArgs.push_back(
Args.MakeArgString(Twine(PluginOptPrefix) + "-debugger-tune=dbx"));
else
CmdArgs.push_back("-plugin-opt=-debugger-tune=gdb");
CmdArgs.push_back(
Args.MakeArgString(Twine(PluginOptPrefix) + "-debugger-tune=gdb"));
}

bool UseSeparateSections =
isUseSeparateSections(ToolChain.getEffectiveTriple());

if (Args.hasFlag(options::OPT_ffunction_sections,
options::OPT_fno_function_sections, UseSeparateSections))
CmdArgs.push_back("-plugin-opt=-function-sections=1");
CmdArgs.push_back(
Args.MakeArgString(Twine(PluginOptPrefix) + "-function-sections=1"));
else if (Args.hasArg(options::OPT_fno_function_sections))
CmdArgs.push_back("-plugin-opt=-function-sections=0");
CmdArgs.push_back(
Args.MakeArgString(Twine(PluginOptPrefix) + "-function-sections=0"));

if (Args.hasFlag(options::OPT_fdata_sections, options::OPT_fno_data_sections,
UseSeparateSections))
CmdArgs.push_back("-plugin-opt=-data-sections=1");
CmdArgs.push_back(
Args.MakeArgString(Twine(PluginOptPrefix) + "-data-sections=1"));
else if (Args.hasArg(options::OPT_fno_data_sections))
CmdArgs.push_back("-plugin-opt=-data-sections=0");
CmdArgs.push_back(
Args.MakeArgString(Twine(PluginOptPrefix) + "-data-sections=0"));

// Pass an option to enable split machine functions.
if (auto *A = Args.getLastArg(options::OPT_fsplit_machine_functions,
options::OPT_fno_split_machine_functions)) {
if (A->getOption().matches(options::OPT_fsplit_machine_functions))
CmdArgs.push_back("-plugin-opt=-split-machine-functions");
CmdArgs.push_back(Args.MakeArgString(Twine(PluginOptPrefix) +
"-split-machine-functions"));
}

if (Arg *A = getLastProfileSampleUseArg(Args)) {
StringRef FName = A->getValue();
if (!llvm::sys::fs::exists(FName))
D.Diag(diag::err_drv_no_such_file) << FName;
else
CmdArgs.push_back(
Args.MakeArgString(Twine("-plugin-opt=sample-profile=") + FName));
CmdArgs.push_back(Args.MakeArgString(Twine(PluginOptPrefix) +
"sample-profile=" + FName));
}

auto *CSPGOGenerateArg = Args.getLastArg(options::OPT_fcs_profile_generate,
Expand All @@ -612,29 +635,31 @@ void tools::addLTOOptions(const ToolChain &ToolChain, const ArgList &Args,
auto *ProfileUseArg = getLastProfileUseArg(Args);

if (CSPGOGenerateArg) {
CmdArgs.push_back(Args.MakeArgString("-plugin-opt=cs-profile-generate"));
CmdArgs.push_back(
Args.MakeArgString(Twine(PluginOptPrefix) + "cs-profile-generate"));
if (CSPGOGenerateArg->getOption().matches(
options::OPT_fcs_profile_generate_EQ)) {
SmallString<128> Path(CSPGOGenerateArg->getValue());
llvm::sys::path::append(Path, "default_%m.profraw");
CmdArgs.push_back(
Args.MakeArgString(Twine("-plugin-opt=cs-profile-path=") + Path));
CmdArgs.push_back(Args.MakeArgString(Twine(PluginOptPrefix) +
"cs-profile-path=" + Path));
} else
CmdArgs.push_back(
Args.MakeArgString("-plugin-opt=cs-profile-path=default_%m.profraw"));
CmdArgs.push_back(Args.MakeArgString(
Twine(PluginOptPrefix) + "cs-profile-path=default_%m.profraw"));
} else if (ProfileUseArg) {
SmallString<128> Path(
ProfileUseArg->getNumValues() == 0 ? "" : ProfileUseArg->getValue());
if (Path.empty() || llvm::sys::fs::is_directory(Path))
llvm::sys::path::append(Path, "default.profdata");
CmdArgs.push_back(Args.MakeArgString(Twine("-plugin-opt=cs-profile-path=") +
Path));
CmdArgs.push_back(
Args.MakeArgString(Twine(PluginOptPrefix) + "cs-profile-path=" + Path));
}

// This controls whether or not we perform JustMyCode instrumentation.
if (Args.hasFlag(options::OPT_fjmc, options::OPT_fno_jmc, false)) {
if (ToolChain.getEffectiveTriple().isOSBinFormatELF())
CmdArgs.push_back("-plugin-opt=-enable-jmc-instrument");
CmdArgs.push_back(Args.MakeArgString(Twine(PluginOptPrefix) +
"-enable-jmc-instrument"));
else
D.Diag(clang::diag::warn_drv_fjmc_for_elf_only);
}
Expand All @@ -643,29 +668,29 @@ void tools::addLTOOptions(const ToolChain &ToolChain, const ArgList &Args,
SmallString<128> StatsFile = getStatsFileName(Args, Output, Input, D);
if (!StatsFile.empty())
CmdArgs.push_back(
Args.MakeArgString(Twine("-plugin-opt=stats-file=") + StatsFile));
Args.MakeArgString(Twine(PluginOptPrefix) + "stats-file=" + StatsFile));

// Setup crash diagnostics dir.
if (Arg *A = Args.getLastArg(options::OPT_fcrash_diagnostics_dir))
CmdArgs.push_back(Args.MakeArgString(
Twine("-plugin-opt=-crash-diagnostics-dir=") + A->getValue()));
Twine(PluginOptPrefix) + "-crash-diagnostics-dir=" + A->getValue()));

addX86AlignBranchArgs(D, Args, CmdArgs, /*IsLTO=*/true);
addX86AlignBranchArgs(D, Args, CmdArgs, /*IsLTO=*/true, PluginOptPrefix);

// Handle remark diagnostics on screen options: '-Rpass-*'.
renderRpassOptions(Args, CmdArgs);
renderRpassOptions(Args, CmdArgs, PluginOptPrefix);

// Handle serialized remarks options: '-fsave-optimization-record'
// and '-foptimization-record-*'.
if (willEmitRemarks(Args))
renderRemarksOptions(Args, CmdArgs, ToolChain.getEffectiveTriple(), Input,
Output);
Output, PluginOptPrefix);

// Handle remarks hotness/threshold related options.
renderRemarksHotnessOptions(Args, CmdArgs);
renderRemarksHotnessOptions(Args, CmdArgs, PluginOptPrefix);

addMachineOutlinerArgs(D, Args, CmdArgs, ToolChain.getEffectiveTriple(),
/*IsLTO=*/true);
/*IsLTO=*/true, PluginOptPrefix);
}

void tools::addOpenMPRuntimeSpecificRPath(const ToolChain &TC,
Expand Down Expand Up @@ -1669,10 +1694,12 @@ void tools::addMultilibFlag(bool Enabled, const char *const Flag,
}

void tools::addX86AlignBranchArgs(const Driver &D, const ArgList &Args,
ArgStringList &CmdArgs, bool IsLTO) {
ArgStringList &CmdArgs, bool IsLTO,
const StringRef PluginOptPrefix) {
auto addArg = [&, IsLTO](const Twine &Arg) {
if (IsLTO) {
CmdArgs.push_back(Args.MakeArgString("-plugin-opt=" + Arg));
assert(!PluginOptPrefix.empty() && "Cannot have empty PluginOptPrefix!");
CmdArgs.push_back(Args.MakeArgString(Twine(PluginOptPrefix) + Arg));
} else {
CmdArgs.push_back("-mllvm");
CmdArgs.push_back(Args.MakeArgString(Arg));
Expand Down Expand Up @@ -2106,10 +2133,12 @@ bool tools::haveAMDGPUCodeObjectVersionArgument(
void tools::addMachineOutlinerArgs(const Driver &D,
const llvm::opt::ArgList &Args,
llvm::opt::ArgStringList &CmdArgs,
const llvm::Triple &Triple, bool IsLTO) {
const llvm::Triple &Triple, bool IsLTO,
const StringRef PluginOptPrefix) {
auto addArg = [&, IsLTO](const Twine &Arg) {
if (IsLTO) {
CmdArgs.push_back(Args.MakeArgString("-plugin-opt=" + Arg));
assert(!PluginOptPrefix.empty() && "Cannot have empty PluginOptPrefix!");
CmdArgs.push_back(Args.MakeArgString(Twine(PluginOptPrefix) + Arg));
} else {
CmdArgs.push_back("-mllvm");
CmdArgs.push_back(Args.MakeArgString(Arg));
Expand Down
6 changes: 4 additions & 2 deletions clang/lib/Driver/ToolChains/CommonArgs.h
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,8 @@ void addMultilibFlag(bool Enabled, const char *const Flag,
Multilib::flags_list &Flags);

void addX86AlignBranchArgs(const Driver &D, const llvm::opt::ArgList &Args,
llvm::opt::ArgStringList &CmdArgs, bool IsLTO);
llvm::opt::ArgStringList &CmdArgs, bool IsLTO,
const StringRef PluginOptPrefix = "");

void checkAMDGPUCodeObjectVersion(const Driver &D,
const llvm::opt::ArgList &Args);
Expand All @@ -203,7 +204,8 @@ bool haveAMDGPUCodeObjectVersionArgument(const Driver &D,

void addMachineOutlinerArgs(const Driver &D, const llvm::opt::ArgList &Args,
llvm::opt::ArgStringList &CmdArgs,
const llvm::Triple &Triple, bool IsLTO);
const llvm::Triple &Triple, bool IsLTO,
const StringRef PluginOptPrefix = "");

void addOpenMPDeviceRTL(const Driver &D, const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args,
Expand Down
6 changes: 6 additions & 0 deletions clang/test/Driver/lto-aix.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// Test LTO path, mcpu and opt level options
// RUN: %clang --target=powerpc-ibm-aix -### %s -flto -fuse-ld=ld -O3 2>&1 \
// RUN: | FileCheck -check-prefixes=LTOPATH,MCPUOPTLEVEL %s
//
// LTOPATH: "-bplugin:{{.*}}libLTO.{{so|dll|dylib}}"
// MCPUOPTLEVEL: "-bplugin_opt:-mcpu={{.*}}" "-bplugin_opt:-O3"

0 comments on commit ec94f37

Please sign in to comment.