diff --git a/clang/lib/Driver/ToolChains/AIX.h b/clang/lib/Driver/ToolChains/AIX.h --- a/clang/lib/Driver/ToolChains/AIX.h +++ b/clang/lib/Driver/ToolChains/AIX.h @@ -67,6 +67,7 @@ return false; } bool isPICDefaultForced() const override { return true; } + bool HasNativeLLVMSupport() const override { return true; } void AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, diff --git a/clang/lib/Driver/ToolChains/AIX.cpp b/clang/lib/Driver/ToolChains/AIX.cpp --- a/clang/lib/Driver/ToolChains/AIX.cpp +++ b/clang/lib/Driver/ToolChains/AIX.cpp @@ -191,6 +191,12 @@ // 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( diff --git a/clang/lib/Driver/ToolChains/CommonArgs.h b/clang/lib/Driver/ToolChains/CommonArgs.h --- a/clang/lib/Driver/ToolChains/CommonArgs.h +++ b/clang/lib/Driver/ToolChains/CommonArgs.h @@ -190,7 +190,8 @@ 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); @@ -203,7 +204,8 @@ 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, diff --git a/clang/lib/Driver/ToolChains/CommonArgs.cpp b/clang/lib/Driver/ToolChains/CommonArgs.cpp --- a/clang/lib/Driver/ToolChains/CommonArgs.cpp +++ b/clang/lib/Driver/ToolChains/CommonArgs.cpp @@ -65,24 +65,26 @@ 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(); @@ -96,29 +98,32 @@ assert(!F.empty() && "Cannot determine remarks output name."); // Append "opt.ld." 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, @@ -484,14 +489,19 @@ 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"; @@ -502,19 +512,23 @@ #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 @@ -523,7 +537,8 @@ // 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 @@ -541,34 +556,37 @@ } 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 = @@ -576,21 +594,26 @@ 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)) { @@ -598,8 +621,8 @@ 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, @@ -612,29 +635,31 @@ 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); } @@ -643,29 +668,29 @@ 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, @@ -1669,10 +1694,12 @@ } 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)); @@ -2106,10 +2133,12 @@ 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)); diff --git a/clang/test/Driver/lto-aix.c b/clang/test/Driver/lto-aix.c new file mode 100644 --- /dev/null +++ b/clang/test/Driver/lto-aix.c @@ -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"