
This patch moves the CommonArgs utilities into a location visible by the Frontend Drivers, so that the Frontend Drivers may share option parsing code with the Compiler Driver. This is useful when the Frontend Drivers would like to verify that their incoming options are well-formed and also not reinvent the option parsing wheel. We already see code in the Clang/Flang Drivers that is parsing and verifying its incoming options. E.g. OPT_ffp_contract. This option is parsed in the Compiler Driver, Clang Driver, and Flang Driver, all with slightly different parsing code. It would be nice if the Frontend Drivers were not required to duplicate this Compiler Driver code. That way there is no/low maintenance burden on keeping all these parsing functions in sync. Along those lines, the Frontend Drivers will now have a useful mechanism to verify their incoming options are well-formed. Currently, the Frontend Drivers trust that the Compiler Driver is not passing back junk in some cases. The Language Drivers may even accept junk with no error at all. E.g.: `clang -cc1 -mprefer-vector-width=junk test.c' With this patch, we'll now be able to tighten up incomming options to the Frontend drivers in a lightweight way. --------- Co-authored-by: Cameron McInally <cmcinally@nvidia.com> Co-authored-by: Shafik Yaghmour <shafik.yaghmour@intel.com>
611 lines
23 KiB
C++
611 lines
23 KiB
C++
//===--- AIX.cpp - AIX ToolChain Implementations ----------------*- C++ -*-===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "AIX.h"
|
|
#include "clang/Driver/CommonArgs.h"
|
|
#include "clang/Driver/Compilation.h"
|
|
#include "clang/Driver/Options.h"
|
|
#include "clang/Driver/SanitizerArgs.h"
|
|
#include "llvm/ADT/StringExtras.h"
|
|
#include "llvm/Option/ArgList.h"
|
|
#include "llvm/ProfileData/InstrProf.h"
|
|
#include "llvm/Support/Path.h"
|
|
|
|
#include <set>
|
|
|
|
using AIX = clang::driver::toolchains::AIX;
|
|
using namespace clang::driver;
|
|
using namespace clang::driver::tools;
|
|
using namespace clang::driver::toolchains;
|
|
|
|
using namespace llvm::opt;
|
|
using namespace llvm::sys;
|
|
|
|
void aix::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
|
|
const InputInfo &Output,
|
|
const InputInfoList &Inputs,
|
|
const ArgList &Args,
|
|
const char *LinkingOutput) const {
|
|
const Driver &D = getToolChain().getDriver();
|
|
ArgStringList CmdArgs;
|
|
|
|
const bool IsArch32Bit = getToolChain().getTriple().isArch32Bit();
|
|
const bool IsArch64Bit = getToolChain().getTriple().isArch64Bit();
|
|
// Only support 32 and 64 bit.
|
|
if (!IsArch32Bit && !IsArch64Bit)
|
|
llvm_unreachable("Unsupported bit width value.");
|
|
|
|
if (Arg *A = C.getArgs().getLastArg(options::OPT_G)) {
|
|
D.Diag(diag::err_drv_unsupported_opt_for_target)
|
|
<< A->getSpelling() << D.getTargetTriple();
|
|
}
|
|
|
|
// Specify the mode in which the as(1) command operates.
|
|
if (IsArch32Bit) {
|
|
CmdArgs.push_back("-a32");
|
|
} else {
|
|
// Must be 64-bit, otherwise asserted already.
|
|
CmdArgs.push_back("-a64");
|
|
}
|
|
|
|
// Accept any mixture of instructions.
|
|
// On Power for AIX and Linux, this behaviour matches that of GCC for both the
|
|
// user-provided assembler source case and the compiler-produced assembler
|
|
// source case. Yet XL with user-provided assembler source would not add this.
|
|
CmdArgs.push_back("-many");
|
|
|
|
Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler);
|
|
|
|
// Specify assembler output file.
|
|
assert((Output.isFilename() || Output.isNothing()) && "Invalid output.");
|
|
if (Output.isFilename()) {
|
|
CmdArgs.push_back("-o");
|
|
CmdArgs.push_back(Output.getFilename());
|
|
}
|
|
|
|
// Specify assembler input file.
|
|
// The system assembler on AIX takes exactly one input file. The driver is
|
|
// expected to invoke as(1) separately for each assembler source input file.
|
|
if (Inputs.size() != 1)
|
|
llvm_unreachable("Invalid number of input files.");
|
|
const InputInfo &II = Inputs[0];
|
|
assert((II.isFilename() || II.isNothing()) && "Invalid input.");
|
|
if (II.isFilename())
|
|
CmdArgs.push_back(II.getFilename());
|
|
|
|
const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as"));
|
|
C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(),
|
|
Exec, CmdArgs, Inputs, Output));
|
|
}
|
|
|
|
// Determine whether there are any linker options that supply an export list
|
|
// (or equivalent information about what to export) being sent to the linker.
|
|
static bool hasExportListLinkerOpts(const ArgStringList &CmdArgs) {
|
|
for (size_t i = 0, Size = CmdArgs.size(); i < Size; ++i) {
|
|
llvm::StringRef ArgString(CmdArgs[i]);
|
|
|
|
if (ArgString.starts_with("-bE:") || ArgString.starts_with("-bexport:") ||
|
|
ArgString == "-bexpall" || ArgString == "-bexpfull")
|
|
return true;
|
|
|
|
// If we split -b option, check the next opt.
|
|
if (ArgString == "-b" && i + 1 < Size) {
|
|
++i;
|
|
llvm::StringRef ArgNextString(CmdArgs[i]);
|
|
if (ArgNextString.starts_with("E:") ||
|
|
ArgNextString.starts_with("export:") || ArgNextString == "expall" ||
|
|
ArgNextString == "expfull")
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void aix::Linker::ConstructJob(Compilation &C, const JobAction &JA,
|
|
const InputInfo &Output,
|
|
const InputInfoList &Inputs, const ArgList &Args,
|
|
const char *LinkingOutput) const {
|
|
const AIX &ToolChain = static_cast<const AIX &>(getToolChain());
|
|
const Driver &D = ToolChain.getDriver();
|
|
ArgStringList CmdArgs;
|
|
|
|
const bool IsArch32Bit = ToolChain.getTriple().isArch32Bit();
|
|
const bool IsArch64Bit = ToolChain.getTriple().isArch64Bit();
|
|
// Only support 32 and 64 bit.
|
|
if (!(IsArch32Bit || IsArch64Bit))
|
|
llvm_unreachable("Unsupported bit width value.");
|
|
|
|
if (Arg *A = C.getArgs().getLastArg(options::OPT_G)) {
|
|
D.Diag(diag::err_drv_unsupported_opt_for_target)
|
|
<< A->getSpelling() << D.getTargetTriple();
|
|
}
|
|
|
|
// Force static linking when "-static" is present.
|
|
if (Args.hasArg(options::OPT_static))
|
|
CmdArgs.push_back("-bnso");
|
|
|
|
// Add options for shared libraries.
|
|
if (Args.hasArg(options::OPT_shared)) {
|
|
CmdArgs.push_back("-bM:SRE");
|
|
CmdArgs.push_back("-bnoentry");
|
|
}
|
|
|
|
if (Args.hasFlag(options::OPT_mxcoff_roptr, options::OPT_mno_xcoff_roptr,
|
|
false)) {
|
|
if (Args.hasArg(options::OPT_shared))
|
|
D.Diag(diag::err_roptr_cannot_build_shared);
|
|
|
|
// The `-mxcoff-roptr` option places constants in RO sections as much as
|
|
// possible. Then `-bforceimprw` changes such sections to RW if they contain
|
|
// imported symbols that need to be resolved.
|
|
CmdArgs.push_back("-bforceimprw");
|
|
}
|
|
|
|
// PGO instrumentation generates symbols belonging to special sections, and
|
|
// the linker needs to place all symbols in a particular section together in
|
|
// memory; the AIX linker does that under an option.
|
|
if (Args.hasFlag(options::OPT_fprofile_arcs, options::OPT_fno_profile_arcs,
|
|
false) ||
|
|
Args.hasFlag(options::OPT_fprofile_generate,
|
|
options::OPT_fno_profile_generate, false) ||
|
|
Args.hasFlag(options::OPT_fprofile_generate_EQ,
|
|
options::OPT_fno_profile_generate, false) ||
|
|
Args.hasFlag(options::OPT_fprofile_instr_generate,
|
|
options::OPT_fno_profile_instr_generate, false) ||
|
|
Args.hasFlag(options::OPT_fprofile_instr_generate_EQ,
|
|
options::OPT_fno_profile_instr_generate, false) ||
|
|
Args.hasFlag(options::OPT_fcs_profile_generate,
|
|
options::OPT_fno_profile_generate, false) ||
|
|
Args.hasFlag(options::OPT_fcs_profile_generate_EQ,
|
|
options::OPT_fno_profile_generate, false) ||
|
|
Args.hasArg(options::OPT_fcreate_profile) ||
|
|
Args.hasArg(options::OPT_coverage))
|
|
CmdArgs.push_back("-bdbg:namedsects:ss");
|
|
|
|
if (Arg *A =
|
|
Args.getLastArg(clang::driver::options::OPT_mxcoff_build_id_EQ)) {
|
|
StringRef BuildId = A->getValue();
|
|
if (BuildId[0] != '0' || BuildId[1] != 'x' ||
|
|
BuildId.find_if_not(llvm::isHexDigit, 2) != StringRef::npos)
|
|
ToolChain.getDriver().Diag(diag::err_drv_unsupported_option_argument)
|
|
<< A->getSpelling() << BuildId;
|
|
else {
|
|
std::string LinkerFlag = "-bdbg:ldrinfo:xcoff_binary_id:0x";
|
|
if (BuildId.size() % 2) // Prepend a 0 if odd number of digits.
|
|
LinkerFlag += "0";
|
|
LinkerFlag += BuildId.drop_front(2).lower();
|
|
CmdArgs.push_back(Args.MakeArgString(LinkerFlag));
|
|
}
|
|
}
|
|
|
|
// Specify linker output file.
|
|
assert((Output.isFilename() || Output.isNothing()) && "Invalid output.");
|
|
if (Output.isFilename()) {
|
|
CmdArgs.push_back("-o");
|
|
CmdArgs.push_back(Output.getFilename());
|
|
}
|
|
|
|
// Set linking mode (i.e., 32/64-bit) and the address of
|
|
// text and data sections based on arch bit width.
|
|
if (IsArch32Bit) {
|
|
CmdArgs.push_back("-b32");
|
|
CmdArgs.push_back("-bpT:0x10000000");
|
|
CmdArgs.push_back("-bpD:0x20000000");
|
|
} else {
|
|
// Must be 64-bit, otherwise asserted already.
|
|
CmdArgs.push_back("-b64");
|
|
CmdArgs.push_back("-bpT:0x100000000");
|
|
CmdArgs.push_back("-bpD:0x110000000");
|
|
}
|
|
|
|
if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles,
|
|
options::OPT_shared, options::OPT_r)) {
|
|
auto getCrt0Basename = [&Args, IsArch32Bit] {
|
|
if (Arg *A = Args.getLastArgNoClaim(options::OPT_p, options::OPT_pg)) {
|
|
// Enable gprofiling when "-pg" is specified.
|
|
if (A->getOption().matches(options::OPT_pg))
|
|
return IsArch32Bit ? "gcrt0.o" : "gcrt0_64.o";
|
|
// Enable profiling when "-p" is specified.
|
|
return IsArch32Bit ? "mcrt0.o" : "mcrt0_64.o";
|
|
}
|
|
return IsArch32Bit ? "crt0.o" : "crt0_64.o";
|
|
};
|
|
|
|
CmdArgs.push_back(
|
|
Args.MakeArgString(ToolChain.GetFilePath(getCrt0Basename())));
|
|
|
|
CmdArgs.push_back(Args.MakeArgString(
|
|
ToolChain.GetFilePath(IsArch32Bit ? "crti.o" : "crti_64.o")));
|
|
}
|
|
|
|
// Collect all static constructor and destructor functions in both C and CXX
|
|
// language link invocations. This has to come before AddLinkerInputs as the
|
|
// implied option needs to precede any other '-bcdtors' settings or
|
|
// '-bnocdtors' that '-Wl' might forward.
|
|
CmdArgs.push_back("-bcdtors:all:0:s");
|
|
|
|
if (Args.hasArg(options::OPT_rpath)) {
|
|
for (const auto &bopt : Args.getAllArgValues(options::OPT_b))
|
|
// Check -b opts prefix for "libpath:" or exact match for "nolibpath"
|
|
if (!bopt.rfind("libpath:", 0) || bopt == "nolibpath")
|
|
D.Diag(diag::err_drv_cannot_mix_options) << "-rpath" << "-b" + bopt;
|
|
|
|
for (const auto &wlopt : Args.getAllArgValues(options::OPT_Wl_COMMA))
|
|
// Check -Wl, opts prefix for "-blibpath:" or exact match for
|
|
// "-bnolibpath"
|
|
if (!wlopt.rfind("-blibpath:", 0) || wlopt == "-bnolibpath")
|
|
D.Diag(diag::err_drv_cannot_mix_options) << "-rpath" << "-Wl," + wlopt;
|
|
|
|
for (const auto &xopt : Args.getAllArgValues(options::OPT_Xlinker))
|
|
// Check -Xlinker opts prefix for "-blibpath:" or exact match for
|
|
// "-bnolibpath"
|
|
if (!xopt.rfind("-blibpath:", 0) || xopt == "-bnolibpath")
|
|
D.Diag(diag::err_drv_cannot_mix_options)
|
|
<< "-rpath" << "-Xlinker " + xopt;
|
|
|
|
std::string BlibPathStr = "";
|
|
for (const auto &dir : Args.getAllArgValues(options::OPT_rpath))
|
|
BlibPathStr += dir + ":";
|
|
BlibPathStr += "/usr/lib:/lib";
|
|
CmdArgs.push_back(Args.MakeArgString(Twine("-blibpath:") + BlibPathStr));
|
|
}
|
|
|
|
// Specify linker input file(s).
|
|
AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA);
|
|
|
|
if (D.isUsingLTO())
|
|
addLTOOptions(ToolChain, Args, CmdArgs, Output, Inputs,
|
|
D.getLTOMode() == LTOK_Thin);
|
|
|
|
if (Args.hasArg(options::OPT_shared) && !hasExportListLinkerOpts(CmdArgs)) {
|
|
|
|
const char *CreateExportListExec = Args.MakeArgString(
|
|
path::parent_path(ToolChain.getDriver().ClangExecutable) +
|
|
"/llvm-nm");
|
|
ArgStringList CreateExportCmdArgs;
|
|
|
|
std::string CreateExportListPath =
|
|
C.getDriver().GetTemporaryPath("CreateExportList", "exp");
|
|
const char *ExportList =
|
|
C.addTempFile(C.getArgs().MakeArgString(CreateExportListPath));
|
|
|
|
for (const auto &II : Inputs)
|
|
if (II.isFilename())
|
|
CreateExportCmdArgs.push_back(II.getFilename());
|
|
|
|
CreateExportCmdArgs.push_back("--export-symbols");
|
|
CreateExportCmdArgs.push_back("-X");
|
|
if (IsArch32Bit) {
|
|
CreateExportCmdArgs.push_back("32");
|
|
} else {
|
|
// Must be 64-bit, otherwise asserted already.
|
|
CreateExportCmdArgs.push_back("64");
|
|
}
|
|
|
|
auto ExpCommand = std::make_unique<Command>(
|
|
JA, *this, ResponseFileSupport::None(), CreateExportListExec,
|
|
CreateExportCmdArgs, Inputs, Output);
|
|
ExpCommand->setRedirectFiles(
|
|
{std::nullopt, std::string(ExportList), std::nullopt});
|
|
C.addCommand(std::move(ExpCommand));
|
|
CmdArgs.push_back(Args.MakeArgString(llvm::Twine("-bE:") + ExportList));
|
|
}
|
|
|
|
// Add directory to library search path.
|
|
Args.AddAllArgs(CmdArgs, options::OPT_L);
|
|
if (!Args.hasArg(options::OPT_r)) {
|
|
ToolChain.AddFilePathLibArgs(Args, CmdArgs);
|
|
ToolChain.addProfileRTLibs(Args, CmdArgs);
|
|
|
|
if (getToolChain().ShouldLinkCXXStdlib(Args))
|
|
getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs);
|
|
|
|
if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
|
|
AddRunTimeLibs(ToolChain, D, CmdArgs, Args);
|
|
|
|
// Add OpenMP runtime if -fopenmp is specified.
|
|
if (Args.hasFlag(options::OPT_fopenmp, options::OPT_fopenmp_EQ,
|
|
options::OPT_fno_openmp, false)) {
|
|
switch (ToolChain.getDriver().getOpenMPRuntime(Args)) {
|
|
case Driver::OMPRT_OMP:
|
|
CmdArgs.push_back("-lomp");
|
|
break;
|
|
case Driver::OMPRT_IOMP5:
|
|
CmdArgs.push_back("-liomp5");
|
|
break;
|
|
case Driver::OMPRT_GOMP:
|
|
CmdArgs.push_back("-lgomp");
|
|
break;
|
|
case Driver::OMPRT_Unknown:
|
|
// Already diagnosed.
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Support POSIX threads if "-pthreads" or "-pthread" is present.
|
|
if (Args.hasArg(options::OPT_pthreads, options::OPT_pthread))
|
|
CmdArgs.push_back("-lpthreads");
|
|
|
|
if (D.CCCIsCXX())
|
|
CmdArgs.push_back("-lm");
|
|
|
|
CmdArgs.push_back("-lc");
|
|
|
|
if (Args.hasArgNoClaim(options::OPT_p, options::OPT_pg)) {
|
|
CmdArgs.push_back(Args.MakeArgString((llvm::Twine("-L") + D.SysRoot) +
|
|
"/lib/profiled"));
|
|
CmdArgs.push_back(Args.MakeArgString((llvm::Twine("-L") + D.SysRoot) +
|
|
"/usr/lib/profiled"));
|
|
}
|
|
}
|
|
}
|
|
|
|
if (D.IsFlangMode() &&
|
|
!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
|
|
ToolChain.addFortranRuntimeLibraryPath(Args, CmdArgs);
|
|
ToolChain.addFortranRuntimeLibs(Args, CmdArgs);
|
|
CmdArgs.push_back("-lm");
|
|
CmdArgs.push_back("-lpthread");
|
|
}
|
|
const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath());
|
|
C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(),
|
|
Exec, CmdArgs, Inputs, Output));
|
|
}
|
|
|
|
/// AIX - AIX tool chain which can call as(1) and ld(1) directly.
|
|
AIX::AIX(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
|
|
: ToolChain(D, Triple, Args) {
|
|
getProgramPaths().push_back(getDriver().Dir);
|
|
|
|
ParseInlineAsmUsingAsmParser = Args.hasFlag(
|
|
options::OPT_fintegrated_as, options::OPT_fno_integrated_as, true);
|
|
getLibraryPaths().push_back(getDriver().SysRoot + "/usr/lib");
|
|
}
|
|
|
|
// Returns the effective header sysroot path to use.
|
|
// This comes from either -isysroot or --sysroot.
|
|
llvm::StringRef
|
|
AIX::GetHeaderSysroot(const llvm::opt::ArgList &DriverArgs) const {
|
|
if (DriverArgs.hasArg(options::OPT_isysroot))
|
|
return DriverArgs.getLastArgValue(options::OPT_isysroot);
|
|
if (!getDriver().SysRoot.empty())
|
|
return getDriver().SysRoot;
|
|
return "/";
|
|
}
|
|
|
|
void AIX::AddOpenMPIncludeArgs(const ArgList &DriverArgs,
|
|
ArgStringList &CC1Args) const {
|
|
// Add OpenMP include paths if -fopenmp is specified.
|
|
if (DriverArgs.hasFlag(options::OPT_fopenmp, options::OPT_fopenmp_EQ,
|
|
options::OPT_fno_openmp, false)) {
|
|
SmallString<128> PathOpenMP;
|
|
switch (getDriver().getOpenMPRuntime(DriverArgs)) {
|
|
case Driver::OMPRT_OMP:
|
|
PathOpenMP = GetHeaderSysroot(DriverArgs);
|
|
llvm::sys::path::append(PathOpenMP, "opt/IBM/openxlCSDK", "include",
|
|
"openmp");
|
|
addSystemInclude(DriverArgs, CC1Args, PathOpenMP.str());
|
|
break;
|
|
case Driver::OMPRT_IOMP5:
|
|
case Driver::OMPRT_GOMP:
|
|
case Driver::OMPRT_Unknown:
|
|
// Unknown / unsupported include paths.
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void AIX::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
|
|
ArgStringList &CC1Args) const {
|
|
// Return if -nostdinc is specified as a driver option.
|
|
if (DriverArgs.hasArg(options::OPT_nostdinc))
|
|
return;
|
|
|
|
llvm::StringRef Sysroot = GetHeaderSysroot(DriverArgs);
|
|
const Driver &D = getDriver();
|
|
|
|
if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {
|
|
SmallString<128> P(D.ResourceDir);
|
|
// Add the PowerPC intrinsic headers (<resource>/include/ppc_wrappers)
|
|
path::append(P, "include", "ppc_wrappers");
|
|
addSystemInclude(DriverArgs, CC1Args, P);
|
|
// Add the Clang builtin headers (<resource>/include)
|
|
addSystemInclude(DriverArgs, CC1Args, path::parent_path(P.str()));
|
|
}
|
|
|
|
// Add the include directory containing omp.h. This needs to be before
|
|
// adding the system include directory because other compilers put their
|
|
// omp.h in /usr/include.
|
|
AddOpenMPIncludeArgs(DriverArgs, CC1Args);
|
|
|
|
// Return if -nostdlibinc is specified as a driver option.
|
|
if (DriverArgs.hasArg(options::OPT_nostdlibinc))
|
|
return;
|
|
|
|
// Add <sysroot>/usr/include.
|
|
SmallString<128> UP(Sysroot);
|
|
path::append(UP, "/usr/include");
|
|
addSystemInclude(DriverArgs, CC1Args, UP.str());
|
|
}
|
|
|
|
void AIX::AddClangCXXStdlibIncludeArgs(
|
|
const llvm::opt::ArgList &DriverArgs,
|
|
llvm::opt::ArgStringList &CC1Args) const {
|
|
|
|
if (DriverArgs.hasArg(options::OPT_nostdinc) ||
|
|
DriverArgs.hasArg(options::OPT_nostdincxx) ||
|
|
DriverArgs.hasArg(options::OPT_nostdlibinc))
|
|
return;
|
|
|
|
switch (GetCXXStdlibType(DriverArgs)) {
|
|
case ToolChain::CST_Libstdcxx:
|
|
llvm::report_fatal_error(
|
|
"picking up libstdc++ headers is unimplemented on AIX");
|
|
case ToolChain::CST_Libcxx: {
|
|
llvm::StringRef Sysroot = GetHeaderSysroot(DriverArgs);
|
|
SmallString<128> PathCPP(Sysroot);
|
|
llvm::sys::path::append(PathCPP, "opt/IBM/openxlCSDK", "include", "c++",
|
|
"v1");
|
|
addSystemInclude(DriverArgs, CC1Args, PathCPP.str());
|
|
// Required in order to suppress conflicting C++ overloads in the system
|
|
// libc headers that were used by XL C++.
|
|
CC1Args.push_back("-D__LIBC_NO_CPP_MATH_OVERLOADS__");
|
|
return;
|
|
}
|
|
}
|
|
|
|
llvm_unreachable("Unexpected C++ library type; only libc++ is supported.");
|
|
}
|
|
|
|
void AIX::AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args,
|
|
llvm::opt::ArgStringList &CmdArgs) const {
|
|
switch (GetCXXStdlibType(Args)) {
|
|
case ToolChain::CST_Libstdcxx:
|
|
llvm::report_fatal_error("linking libstdc++ unimplemented on AIX");
|
|
case ToolChain::CST_Libcxx:
|
|
CmdArgs.push_back("-lc++");
|
|
if (Args.hasArg(options::OPT_fexperimental_library))
|
|
CmdArgs.push_back("-lc++experimental");
|
|
CmdArgs.push_back("-lc++abi");
|
|
return;
|
|
}
|
|
|
|
llvm_unreachable("Unexpected C++ library type; only libc++ is supported.");
|
|
}
|
|
|
|
// This function processes all the mtocdata options to build the final
|
|
// simplified toc data options to pass to CC1.
|
|
static void addTocDataOptions(const llvm::opt::ArgList &Args,
|
|
llvm::opt::ArgStringList &CC1Args,
|
|
const Driver &D) {
|
|
|
|
// Check the global toc-data setting. The default is -mno-tocdata.
|
|
// To enable toc-data globally, -mtocdata must be specified.
|
|
// Additionally, it must be last to take effect.
|
|
const bool TOCDataGloballyinEffect = [&Args]() {
|
|
if (const Arg *LastArg =
|
|
Args.getLastArg(options::OPT_mtocdata, options::OPT_mno_tocdata))
|
|
return LastArg->getOption().matches(options::OPT_mtocdata);
|
|
else
|
|
return false;
|
|
}();
|
|
|
|
enum TOCDataSetting {
|
|
AddressInTOC = 0, // Address of the symbol stored in the TOC.
|
|
DataInTOC = 1 // Symbol defined in the TOC.
|
|
};
|
|
|
|
const TOCDataSetting DefaultTocDataSetting =
|
|
TOCDataGloballyinEffect ? DataInTOC : AddressInTOC;
|
|
|
|
// Process the list of variables in the explicitly specified options
|
|
// -mtocdata= and -mno-tocdata= to see which variables are opposite to
|
|
// the global setting of tocdata in TOCDataGloballyinEffect.
|
|
// Those that have the opposite setting to TOCDataGloballyinEffect, are added
|
|
// to ExplicitlySpecifiedGlobals.
|
|
std::set<llvm::StringRef> ExplicitlySpecifiedGlobals;
|
|
for (const auto Arg :
|
|
Args.filtered(options::OPT_mtocdata_EQ, options::OPT_mno_tocdata_EQ)) {
|
|
TOCDataSetting ArgTocDataSetting =
|
|
Arg->getOption().matches(options::OPT_mtocdata_EQ) ? DataInTOC
|
|
: AddressInTOC;
|
|
|
|
if (ArgTocDataSetting != DefaultTocDataSetting)
|
|
for (const char *Val : Arg->getValues())
|
|
ExplicitlySpecifiedGlobals.insert(Val);
|
|
else
|
|
for (const char *Val : Arg->getValues())
|
|
ExplicitlySpecifiedGlobals.erase(Val);
|
|
}
|
|
|
|
auto buildExceptionList = [](const std::set<llvm::StringRef> &ExplicitValues,
|
|
const char *OptionSpelling) {
|
|
std::string Option(OptionSpelling);
|
|
bool IsFirst = true;
|
|
for (const auto &E : ExplicitValues) {
|
|
if (!IsFirst)
|
|
Option += ",";
|
|
|
|
IsFirst = false;
|
|
Option += E.str();
|
|
}
|
|
return Option;
|
|
};
|
|
|
|
// Pass the final tocdata options to CC1 consisting of the default
|
|
// tocdata option (-mtocdata/-mno-tocdata) along with the list
|
|
// option (-mno-tocdata=/-mtocdata=) if there are any explicitly specified
|
|
// variables which would be exceptions to the default setting.
|
|
const char *TocDataGlobalOption =
|
|
TOCDataGloballyinEffect ? "-mtocdata" : "-mno-tocdata";
|
|
CC1Args.push_back(TocDataGlobalOption);
|
|
|
|
const char *TocDataListOption =
|
|
TOCDataGloballyinEffect ? "-mno-tocdata=" : "-mtocdata=";
|
|
if (!ExplicitlySpecifiedGlobals.empty())
|
|
CC1Args.push_back(Args.MakeArgString(llvm::Twine(
|
|
buildExceptionList(ExplicitlySpecifiedGlobals, TocDataListOption))));
|
|
}
|
|
|
|
void AIX::addClangTargetOptions(
|
|
const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CC1Args,
|
|
Action::OffloadKind DeviceOffloadingKind) const {
|
|
Args.AddLastArg(CC1Args, options::OPT_mignore_xcoff_visibility);
|
|
Args.AddLastArg(CC1Args, options::OPT_mdefault_visibility_export_mapping_EQ);
|
|
Args.addOptInFlag(CC1Args, options::OPT_mxcoff_roptr, options::OPT_mno_xcoff_roptr);
|
|
|
|
// Forward last mtocdata/mno_tocdata options to -cc1.
|
|
if (Args.hasArg(options::OPT_mtocdata_EQ, options::OPT_mno_tocdata_EQ,
|
|
options::OPT_mtocdata))
|
|
addTocDataOptions(Args, CC1Args, getDriver());
|
|
|
|
if (Args.hasArg(options::OPT_msave_reg_params))
|
|
CC1Args.push_back("-msave-reg-params");
|
|
|
|
if (Args.hasFlag(options::OPT_fxl_pragma_pack,
|
|
options::OPT_fno_xl_pragma_pack, true))
|
|
CC1Args.push_back("-fxl-pragma-pack");
|
|
|
|
// Pass "-fno-sized-deallocation" only when the user hasn't manually enabled
|
|
// or disabled sized deallocations.
|
|
if (!Args.getLastArgNoClaim(options::OPT_fsized_deallocation,
|
|
options::OPT_fno_sized_deallocation))
|
|
CC1Args.push_back("-fno-sized-deallocation");
|
|
}
|
|
|
|
void AIX::addProfileRTLibs(const llvm::opt::ArgList &Args,
|
|
llvm::opt::ArgStringList &CmdArgs) const {
|
|
if (needsProfileRT(Args)) {
|
|
// Add linker option -u__llvm_profile_runtime to cause runtime
|
|
// initialization to occur.
|
|
CmdArgs.push_back(Args.MakeArgString(
|
|
Twine("-u", llvm::getInstrProfRuntimeHookVarName())));
|
|
|
|
if (const auto *A =
|
|
Args.getLastArgNoClaim(options::OPT_fprofile_update_EQ)) {
|
|
StringRef Val = A->getValue();
|
|
if (Val == "atomic" || Val == "prefer-atomic")
|
|
CmdArgs.push_back("-latomic");
|
|
}
|
|
}
|
|
|
|
ToolChain::addProfileRTLibs(Args, CmdArgs);
|
|
}
|
|
|
|
ToolChain::CXXStdlibType AIX::GetDefaultCXXStdlibType() const {
|
|
return ToolChain::CST_Libcxx;
|
|
}
|
|
|
|
ToolChain::RuntimeLibType AIX::GetDefaultRuntimeLibType() const {
|
|
return ToolChain::RLT_CompilerRT;
|
|
}
|
|
|
|
auto AIX::buildAssembler() const -> Tool * { return new aix::Assembler(*this); }
|
|
|
|
auto AIX::buildLinker() const -> Tool * { return new aix::Linker(*this); }
|