in clang/lib/Driver/ToolChains/Clang.cpp [4320:7130]
void Clang::ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output, const InputInfoList &Inputs,
const ArgList &Args, const char *LinkingOutput) const {
const auto &TC = getToolChain();
const llvm::Triple &RawTriple = TC.getTriple();
const llvm::Triple &Triple = TC.getEffectiveTriple();
const std::string &TripleStr = Triple.getTriple();
bool KernelOrKext =
Args.hasArg(options::OPT_mkernel, options::OPT_fapple_kext);
const Driver &D = TC.getDriver();
ArgStringList CmdArgs;
assert(Inputs.size() >= 1 && "Must have at least one input.");
// CUDA/HIP compilation may have multiple inputs (source file + results of
// device-side compilations). OpenMP device jobs also take the host IR as a
// second input. Module precompilation accepts a list of header files to
// include as part of the module. All other jobs are expected to have exactly
// one input.
bool IsCuda = JA.isOffloading(Action::OFK_Cuda);
bool IsCudaDevice = JA.isDeviceOffloading(Action::OFK_Cuda);
bool IsHIP = JA.isOffloading(Action::OFK_HIP);
bool IsHIPDevice = JA.isDeviceOffloading(Action::OFK_HIP);
bool IsOpenMPDevice = JA.isDeviceOffloading(Action::OFK_OpenMP);
bool IsHeaderModulePrecompile = isa<HeaderModulePrecompileJobAction>(JA);
bool IsDeviceOffloadAction = !(JA.isDeviceOffloading(Action::OFK_None) ||
JA.isDeviceOffloading(Action::OFK_Host));
bool IsUsingLTO = D.isUsingLTO(IsDeviceOffloadAction);
auto LTOMode = D.getLTOMode(IsDeviceOffloadAction);
// A header module compilation doesn't have a main input file, so invent a
// fake one as a placeholder.
const char *ModuleName = [&]{
auto *ModuleNameArg = Args.getLastArg(options::OPT_fmodule_name_EQ);
return ModuleNameArg ? ModuleNameArg->getValue() : "";
}();
InputInfo HeaderModuleInput(Inputs[0].getType(), ModuleName, ModuleName);
const InputInfo &Input =
IsHeaderModulePrecompile ? HeaderModuleInput : Inputs[0];
InputInfoList ModuleHeaderInputs;
const InputInfo *CudaDeviceInput = nullptr;
const InputInfo *OpenMPDeviceInput = nullptr;
for (const InputInfo &I : Inputs) {
if (&I == &Input) {
// This is the primary input.
} else if (IsHeaderModulePrecompile &&
types::getPrecompiledType(I.getType()) == types::TY_PCH) {
types::ID Expected = HeaderModuleInput.getType();
if (I.getType() != Expected) {
D.Diag(diag::err_drv_module_header_wrong_kind)
<< I.getFilename() << types::getTypeName(I.getType())
<< types::getTypeName(Expected);
}
ModuleHeaderInputs.push_back(I);
} else if ((IsCuda || IsHIP) && !CudaDeviceInput) {
CudaDeviceInput = &I;
} else if (IsOpenMPDevice && !OpenMPDeviceInput) {
OpenMPDeviceInput = &I;
} else {
llvm_unreachable("unexpectedly given multiple inputs");
}
}
const llvm::Triple *AuxTriple =
(IsCuda || IsHIP) ? TC.getAuxTriple() : nullptr;
bool IsWindowsMSVC = RawTriple.isWindowsMSVCEnvironment();
bool IsIAMCU = RawTriple.isOSIAMCU();
// Adjust IsWindowsXYZ for CUDA/HIP compilations. Even when compiling in
// device mode (i.e., getToolchain().getTriple() is NVPTX/AMDGCN, not
// Windows), we need to pass Windows-specific flags to cc1.
if (IsCuda || IsHIP)
IsWindowsMSVC |= AuxTriple && AuxTriple->isWindowsMSVCEnvironment();
// C++ is not supported for IAMCU.
if (IsIAMCU && types::isCXX(Input.getType()))
D.Diag(diag::err_drv_clang_unsupported) << "C++ for IAMCU";
// Invoke ourselves in -cc1 mode.
//
// FIXME: Implement custom jobs for internal actions.
CmdArgs.push_back("-cc1");
// Add the "effective" target triple.
CmdArgs.push_back("-triple");
CmdArgs.push_back(Args.MakeArgString(TripleStr));
if (const Arg *MJ = Args.getLastArg(options::OPT_MJ)) {
DumpCompilationDatabase(C, MJ->getValue(), TripleStr, Output, Input, Args);
Args.ClaimAllArgs(options::OPT_MJ);
} else if (const Arg *GenCDBFragment =
Args.getLastArg(options::OPT_gen_cdb_fragment_path)) {
DumpCompilationDatabaseFragmentToDir(GenCDBFragment->getValue(), C,
TripleStr, Output, Input, Args);
Args.ClaimAllArgs(options::OPT_gen_cdb_fragment_path);
}
if (IsCuda || IsHIP) {
// We have to pass the triple of the host if compiling for a CUDA/HIP device
// and vice-versa.
std::string NormalizedTriple;
if (JA.isDeviceOffloading(Action::OFK_Cuda) ||
JA.isDeviceOffloading(Action::OFK_HIP))
NormalizedTriple = C.getSingleOffloadToolChain<Action::OFK_Host>()
->getTriple()
.normalize();
else {
// Host-side compilation.
NormalizedTriple =
(IsCuda ? C.getSingleOffloadToolChain<Action::OFK_Cuda>()
: C.getSingleOffloadToolChain<Action::OFK_HIP>())
->getTriple()
.normalize();
if (IsCuda) {
// We need to figure out which CUDA version we're compiling for, as that
// determines how we load and launch GPU kernels.
auto *CTC = static_cast<const toolchains::CudaToolChain *>(
C.getSingleOffloadToolChain<Action::OFK_Cuda>());
assert(CTC && "Expected valid CUDA Toolchain.");
if (CTC && CTC->CudaInstallation.version() != CudaVersion::UNKNOWN)
CmdArgs.push_back(Args.MakeArgString(
Twine("-target-sdk-version=") +
CudaVersionToString(CTC->CudaInstallation.version())));
}
}
CmdArgs.push_back("-aux-triple");
CmdArgs.push_back(Args.MakeArgString(NormalizedTriple));
}
if (Args.hasFlag(options::OPT_fsycl, options::OPT_fno_sycl, false)) {
CmdArgs.push_back("-fsycl-is-device");
if (Arg *A = Args.getLastArg(options::OPT_sycl_std_EQ)) {
A->render(Args, CmdArgs);
} else {
// Ensure the default version in SYCL mode is 2020.
CmdArgs.push_back("-sycl-std=2020");
}
}
if (IsOpenMPDevice) {
// We have to pass the triple of the host if compiling for an OpenMP device.
std::string NormalizedTriple =
C.getSingleOffloadToolChain<Action::OFK_Host>()
->getTriple()
.normalize();
CmdArgs.push_back("-aux-triple");
CmdArgs.push_back(Args.MakeArgString(NormalizedTriple));
}
if (Triple.isOSWindows() && (Triple.getArch() == llvm::Triple::arm ||
Triple.getArch() == llvm::Triple::thumb)) {
unsigned Offset = Triple.getArch() == llvm::Triple::arm ? 4 : 6;
unsigned Version = 0;
bool Failure =
Triple.getArchName().substr(Offset).consumeInteger(10, Version);
if (Failure || Version < 7)
D.Diag(diag::err_target_unsupported_arch) << Triple.getArchName()
<< TripleStr;
}
// Push all default warning arguments that are specific to
// the given target. These come before user provided warning options
// are provided.
TC.addClangWarningOptions(CmdArgs);
// FIXME: Subclass ToolChain for SPIR and move this to addClangWarningOptions.
if (Triple.isSPIR() || Triple.isSPIRV())
CmdArgs.push_back("-Wspir-compat");
// Select the appropriate action.
RewriteKind rewriteKind = RK_None;
// If CollectArgsForIntegratedAssembler() isn't called below, claim the args
// it claims when not running an assembler. Otherwise, clang would emit
// "argument unused" warnings for assembler flags when e.g. adding "-E" to
// flags while debugging something. That'd be somewhat inconvenient, and it's
// also inconsistent with most other flags -- we don't warn on
// -ffunction-sections not being used in -E mode either for example, even
// though it's not really used either.
if (!isa<AssembleJobAction>(JA)) {
// The args claimed here should match the args used in
// CollectArgsForIntegratedAssembler().
if (TC.useIntegratedAs()) {
Args.ClaimAllArgs(options::OPT_mrelax_all);
Args.ClaimAllArgs(options::OPT_mno_relax_all);
Args.ClaimAllArgs(options::OPT_mincremental_linker_compatible);
Args.ClaimAllArgs(options::OPT_mno_incremental_linker_compatible);
switch (C.getDefaultToolChain().getArch()) {
case llvm::Triple::arm:
case llvm::Triple::armeb:
case llvm::Triple::thumb:
case llvm::Triple::thumbeb:
Args.ClaimAllArgs(options::OPT_mimplicit_it_EQ);
break;
default:
break;
}
}
Args.ClaimAllArgs(options::OPT_Wa_COMMA);
Args.ClaimAllArgs(options::OPT_Xassembler);
}
if (isa<AnalyzeJobAction>(JA)) {
assert(JA.getType() == types::TY_Plist && "Invalid output type.");
CmdArgs.push_back("-analyze");
} else if (isa<MigrateJobAction>(JA)) {
CmdArgs.push_back("-migrate");
} else if (isa<PreprocessJobAction>(JA)) {
if (Output.getType() == types::TY_Dependencies)
CmdArgs.push_back("-Eonly");
else {
CmdArgs.push_back("-E");
if (Args.hasArg(options::OPT_rewrite_objc) &&
!Args.hasArg(options::OPT_g_Group))
CmdArgs.push_back("-P");
}
} else if (isa<AssembleJobAction>(JA)) {
CmdArgs.push_back("-emit-obj");
CollectArgsForIntegratedAssembler(C, Args, CmdArgs, D);
// Also ignore explicit -force_cpusubtype_ALL option.
(void)Args.hasArg(options::OPT_force__cpusubtype__ALL);
} else if (isa<PrecompileJobAction>(JA)) {
if (JA.getType() == types::TY_Nothing)
CmdArgs.push_back("-fsyntax-only");
else if (JA.getType() == types::TY_ModuleFile)
CmdArgs.push_back(IsHeaderModulePrecompile
? "-emit-header-module"
: "-emit-module-interface");
else
CmdArgs.push_back("-emit-pch");
} else if (isa<VerifyPCHJobAction>(JA)) {
CmdArgs.push_back("-verify-pch");
} else {
assert((isa<CompileJobAction>(JA) || isa<BackendJobAction>(JA)) &&
"Invalid action for clang tool.");
if (JA.getType() == types::TY_Nothing) {
CmdArgs.push_back("-fsyntax-only");
} else if (JA.getType() == types::TY_LLVM_IR ||
JA.getType() == types::TY_LTO_IR) {
CmdArgs.push_back("-emit-llvm");
} else if (JA.getType() == types::TY_LLVM_BC ||
JA.getType() == types::TY_LTO_BC) {
// Emit textual llvm IR for AMDGPU offloading for -emit-llvm -S
if (Triple.isAMDGCN() && IsOpenMPDevice && Args.hasArg(options::OPT_S) &&
Args.hasArg(options::OPT_emit_llvm)) {
CmdArgs.push_back("-emit-llvm");
} else {
CmdArgs.push_back("-emit-llvm-bc");
}
} else if (JA.getType() == types::TY_IFS ||
JA.getType() == types::TY_IFS_CPP) {
StringRef ArgStr =
Args.hasArg(options::OPT_interface_stub_version_EQ)
? Args.getLastArgValue(options::OPT_interface_stub_version_EQ)
: "ifs-v1";
CmdArgs.push_back("-emit-interface-stubs");
CmdArgs.push_back(
Args.MakeArgString(Twine("-interface-stub-version=") + ArgStr.str()));
} else if (JA.getType() == types::TY_PP_Asm) {
CmdArgs.push_back("-S");
} else if (JA.getType() == types::TY_AST) {
CmdArgs.push_back("-emit-pch");
} else if (JA.getType() == types::TY_ModuleFile) {
CmdArgs.push_back("-module-file-info");
} else if (JA.getType() == types::TY_RewrittenObjC) {
CmdArgs.push_back("-rewrite-objc");
rewriteKind = RK_NonFragile;
} else if (JA.getType() == types::TY_RewrittenLegacyObjC) {
CmdArgs.push_back("-rewrite-objc");
rewriteKind = RK_Fragile;
} else {
assert(JA.getType() == types::TY_PP_Asm && "Unexpected output type!");
}
// Preserve use-list order by default when emitting bitcode, so that
// loading the bitcode up in 'opt' or 'llc' and running passes gives the
// same result as running passes here. For LTO, we don't need to preserve
// the use-list order, since serialization to bitcode is part of the flow.
if (JA.getType() == types::TY_LLVM_BC)
CmdArgs.push_back("-emit-llvm-uselists");
if (IsUsingLTO) {
// Only AMDGPU supports device-side LTO.
if (IsDeviceOffloadAction && !Triple.isAMDGPU()) {
D.Diag(diag::err_drv_unsupported_opt_for_target)
<< Args.getLastArg(options::OPT_foffload_lto,
options::OPT_foffload_lto_EQ)
->getAsString(Args)
<< Triple.getTriple();
} else {
assert(LTOMode == LTOK_Full || LTOMode == LTOK_Thin);
CmdArgs.push_back(Args.MakeArgString(
Twine("-flto=") + (LTOMode == LTOK_Thin ? "thin" : "full")));
CmdArgs.push_back("-flto-unit");
}
}
}
if (const Arg *A = Args.getLastArg(options::OPT_fthinlto_index_EQ)) {
if (!types::isLLVMIR(Input.getType()))
D.Diag(diag::err_drv_arg_requires_bitcode_input) << A->getAsString(Args);
Args.AddLastArg(CmdArgs, options::OPT_fthinlto_index_EQ);
}
if (Args.getLastArg(options::OPT_fthin_link_bitcode_EQ))
Args.AddLastArg(CmdArgs, options::OPT_fthin_link_bitcode_EQ);
if (Args.getLastArg(options::OPT_save_temps_EQ))
Args.AddLastArg(CmdArgs, options::OPT_save_temps_EQ);
auto *MemProfArg = Args.getLastArg(options::OPT_fmemory_profile,
options::OPT_fmemory_profile_EQ,
options::OPT_fno_memory_profile);
if (MemProfArg &&
!MemProfArg->getOption().matches(options::OPT_fno_memory_profile))
MemProfArg->render(Args, CmdArgs);
// Embed-bitcode option.
// Only white-listed flags below are allowed to be embedded.
if (C.getDriver().embedBitcodeInObject() && !IsUsingLTO &&
(isa<BackendJobAction>(JA) || isa<AssembleJobAction>(JA))) {
// Add flags implied by -fembed-bitcode.
Args.AddLastArg(CmdArgs, options::OPT_fembed_bitcode_EQ);
// Disable all llvm IR level optimizations.
CmdArgs.push_back("-disable-llvm-passes");
// Render target options.
TC.addClangTargetOptions(Args, CmdArgs, JA.getOffloadingDeviceKind());
// reject options that shouldn't be supported in bitcode
// also reject kernel/kext
static const constexpr unsigned kBitcodeOptionIgnorelist[] = {
options::OPT_mkernel,
options::OPT_fapple_kext,
options::OPT_ffunction_sections,
options::OPT_fno_function_sections,
options::OPT_fdata_sections,
options::OPT_fno_data_sections,
options::OPT_fbasic_block_sections_EQ,
options::OPT_funique_internal_linkage_names,
options::OPT_fno_unique_internal_linkage_names,
options::OPT_funique_section_names,
options::OPT_fno_unique_section_names,
options::OPT_funique_basic_block_section_names,
options::OPT_fno_unique_basic_block_section_names,
options::OPT_mrestrict_it,
options::OPT_mno_restrict_it,
options::OPT_mstackrealign,
options::OPT_mno_stackrealign,
options::OPT_mstack_alignment,
options::OPT_mcmodel_EQ,
options::OPT_mlong_calls,
options::OPT_mno_long_calls,
options::OPT_ggnu_pubnames,
options::OPT_gdwarf_aranges,
options::OPT_fdebug_types_section,
options::OPT_fno_debug_types_section,
options::OPT_fdwarf_directory_asm,
options::OPT_fno_dwarf_directory_asm,
options::OPT_mrelax_all,
options::OPT_mno_relax_all,
options::OPT_ftrap_function_EQ,
options::OPT_ffixed_r9,
options::OPT_mfix_cortex_a53_835769,
options::OPT_mno_fix_cortex_a53_835769,
options::OPT_ffixed_x18,
options::OPT_mglobal_merge,
options::OPT_mno_global_merge,
options::OPT_mred_zone,
options::OPT_mno_red_zone,
options::OPT_Wa_COMMA,
options::OPT_Xassembler,
options::OPT_mllvm,
};
for (const auto &A : Args)
if (llvm::is_contained(kBitcodeOptionIgnorelist, A->getOption().getID()))
D.Diag(diag::err_drv_unsupported_embed_bitcode) << A->getSpelling();
// Render the CodeGen options that need to be passed.
if (!Args.hasFlag(options::OPT_foptimize_sibling_calls,
options::OPT_fno_optimize_sibling_calls))
CmdArgs.push_back("-mdisable-tail-calls");
RenderFloatingPointOptions(TC, D, isOptimizationLevelFast(Args), Args,
CmdArgs, JA);
// Render ABI arguments
switch (TC.getArch()) {
default: break;
case llvm::Triple::arm:
case llvm::Triple::armeb:
case llvm::Triple::thumbeb:
RenderARMABI(D, Triple, Args, CmdArgs);
break;
case llvm::Triple::aarch64:
case llvm::Triple::aarch64_32:
case llvm::Triple::aarch64_be:
RenderAArch64ABI(Triple, Args, CmdArgs);
break;
}
// Optimization level for CodeGen.
if (const Arg *A = Args.getLastArg(options::OPT_O_Group)) {
if (A->getOption().matches(options::OPT_O4)) {
CmdArgs.push_back("-O3");
D.Diag(diag::warn_O4_is_O3);
} else {
A->render(Args, CmdArgs);
}
}
// Input/Output file.
if (Output.getType() == types::TY_Dependencies) {
// Handled with other dependency code.
} else if (Output.isFilename()) {
CmdArgs.push_back("-o");
CmdArgs.push_back(Output.getFilename());
} else {
assert(Output.isNothing() && "Input output.");
}
for (const auto &II : Inputs) {
addDashXForInput(Args, II, CmdArgs);
if (II.isFilename())
CmdArgs.push_back(II.getFilename());
else
II.getInputArg().renderAsInput(Args, CmdArgs);
}
C.addCommand(std::make_unique<Command>(
JA, *this, ResponseFileSupport::AtFileUTF8(), D.getClangProgramPath(),
CmdArgs, Inputs, Output));
return;
}
if (C.getDriver().embedBitcodeMarkerOnly() && !IsUsingLTO)
CmdArgs.push_back("-fembed-bitcode=marker");
// We normally speed up the clang process a bit by skipping destructors at
// exit, but when we're generating diagnostics we can rely on some of the
// cleanup.
if (!C.isForDiagnostics())
CmdArgs.push_back("-disable-free");
CmdArgs.push_back("-clear-ast-before-backend");
#ifdef NDEBUG
const bool IsAssertBuild = false;
#else
const bool IsAssertBuild = true;
#endif
// Disable the verification pass in -asserts builds.
if (!IsAssertBuild)
CmdArgs.push_back("-disable-llvm-verifier");
// Discard value names in assert builds unless otherwise specified.
if (Args.hasFlag(options::OPT_fdiscard_value_names,
options::OPT_fno_discard_value_names, !IsAssertBuild)) {
if (Args.hasArg(options::OPT_fdiscard_value_names) &&
llvm::any_of(Inputs, [](const clang::driver::InputInfo &II) {
return types::isLLVMIR(II.getType());
})) {
D.Diag(diag::warn_ignoring_fdiscard_for_bitcode);
}
CmdArgs.push_back("-discard-value-names");
}
// Set the main file name, so that debug info works even with
// -save-temps.
CmdArgs.push_back("-main-file-name");
CmdArgs.push_back(getBaseInputName(Args, Input));
// Some flags which affect the language (via preprocessor
// defines).
if (Args.hasArg(options::OPT_static))
CmdArgs.push_back("-static-define");
if (Args.hasArg(options::OPT_municode))
CmdArgs.push_back("-DUNICODE");
if (isa<AnalyzeJobAction>(JA))
RenderAnalyzerOptions(Args, CmdArgs, Triple, Input);
if (isa<AnalyzeJobAction>(JA) ||
(isa<PreprocessJobAction>(JA) && Args.hasArg(options::OPT__analyze)))
CmdArgs.push_back("-setup-static-analyzer");
// Enable compatilibily mode to avoid analyzer-config related errors.
// Since we can't access frontend flags through hasArg, let's manually iterate
// through them.
bool FoundAnalyzerConfig = false;
for (auto Arg : Args.filtered(options::OPT_Xclang))
if (StringRef(Arg->getValue()) == "-analyzer-config") {
FoundAnalyzerConfig = true;
break;
}
if (!FoundAnalyzerConfig)
for (auto Arg : Args.filtered(options::OPT_Xanalyzer))
if (StringRef(Arg->getValue()) == "-analyzer-config") {
FoundAnalyzerConfig = true;
break;
}
if (FoundAnalyzerConfig)
CmdArgs.push_back("-analyzer-config-compatibility-mode=true");
CheckCodeGenerationOptions(D, Args);
unsigned FunctionAlignment = ParseFunctionAlignment(TC, Args);
assert(FunctionAlignment <= 31 && "function alignment will be truncated!");
if (FunctionAlignment) {
CmdArgs.push_back("-function-alignment");
CmdArgs.push_back(Args.MakeArgString(std::to_string(FunctionAlignment)));
}
// We support -falign-loops=N where N is a power of 2. GCC supports more
// forms.
if (const Arg *A = Args.getLastArg(options::OPT_falign_loops_EQ)) {
unsigned Value = 0;
if (StringRef(A->getValue()).getAsInteger(10, Value) || Value > 65536)
TC.getDriver().Diag(diag::err_drv_invalid_int_value)
<< A->getAsString(Args) << A->getValue();
else if (Value & (Value - 1))
TC.getDriver().Diag(diag::err_drv_alignment_not_power_of_two)
<< A->getAsString(Args) << A->getValue();
// Treat =0 as unspecified (use the target preference).
if (Value)
CmdArgs.push_back(Args.MakeArgString("-falign-loops=" +
Twine(std::min(Value, 65536u))));
}
llvm::Reloc::Model RelocationModel;
unsigned PICLevel;
bool IsPIE;
std::tie(RelocationModel, PICLevel, IsPIE) = ParsePICArgs(TC, Args);
bool IsROPI = RelocationModel == llvm::Reloc::ROPI ||
RelocationModel == llvm::Reloc::ROPI_RWPI;
bool IsRWPI = RelocationModel == llvm::Reloc::RWPI ||
RelocationModel == llvm::Reloc::ROPI_RWPI;
if (Args.hasArg(options::OPT_mcmse) &&
!Args.hasArg(options::OPT_fallow_unsupported)) {
if (IsROPI)
D.Diag(diag::err_cmse_pi_are_incompatible) << IsROPI;
if (IsRWPI)
D.Diag(diag::err_cmse_pi_are_incompatible) << !IsRWPI;
}
if (IsROPI && types::isCXX(Input.getType()) &&
!Args.hasArg(options::OPT_fallow_unsupported))
D.Diag(diag::err_drv_ropi_incompatible_with_cxx);
const char *RMName = RelocationModelName(RelocationModel);
if (RMName) {
CmdArgs.push_back("-mrelocation-model");
CmdArgs.push_back(RMName);
}
if (PICLevel > 0) {
CmdArgs.push_back("-pic-level");
CmdArgs.push_back(PICLevel == 1 ? "1" : "2");
if (IsPIE)
CmdArgs.push_back("-pic-is-pie");
}
if (RelocationModel == llvm::Reloc::ROPI ||
RelocationModel == llvm::Reloc::ROPI_RWPI)
CmdArgs.push_back("-fropi");
if (RelocationModel == llvm::Reloc::RWPI ||
RelocationModel == llvm::Reloc::ROPI_RWPI)
CmdArgs.push_back("-frwpi");
if (Arg *A = Args.getLastArg(options::OPT_meabi)) {
CmdArgs.push_back("-meabi");
CmdArgs.push_back(A->getValue());
}
// -fsemantic-interposition is forwarded to CC1: set the
// "SemanticInterposition" metadata to 1 (make some linkages interposable) and
// make default visibility external linkage definitions dso_preemptable.
//
// -fno-semantic-interposition: if the target supports .Lfoo$local local
// aliases (make default visibility external linkage definitions dso_local).
// This is the CC1 default for ELF to match COFF/Mach-O.
//
// Otherwise use Clang's traditional behavior: like
// -fno-semantic-interposition but local aliases are not used. So references
// can be interposed if not optimized out.
if (Triple.isOSBinFormatELF()) {
Arg *A = Args.getLastArg(options::OPT_fsemantic_interposition,
options::OPT_fno_semantic_interposition);
if (RelocationModel != llvm::Reloc::Static && !IsPIE) {
// The supported targets need to call AsmPrinter::getSymbolPreferLocal.
bool SupportsLocalAlias =
Triple.isAArch64() || Triple.isRISCV() || Triple.isX86();
if (!A)
CmdArgs.push_back("-fhalf-no-semantic-interposition");
else if (A->getOption().matches(options::OPT_fsemantic_interposition))
A->render(Args, CmdArgs);
else if (!SupportsLocalAlias)
CmdArgs.push_back("-fhalf-no-semantic-interposition");
}
}
{
std::string Model;
if (Arg *A = Args.getLastArg(options::OPT_mthread_model)) {
if (!TC.isThreadModelSupported(A->getValue()))
D.Diag(diag::err_drv_invalid_thread_model_for_target)
<< A->getValue() << A->getAsString(Args);
Model = A->getValue();
} else
Model = TC.getThreadModel();
if (Model != "posix") {
CmdArgs.push_back("-mthread-model");
CmdArgs.push_back(Args.MakeArgString(Model));
}
}
Args.AddLastArg(CmdArgs, options::OPT_fveclib);
if (Args.hasFlag(options::OPT_fmerge_all_constants,
options::OPT_fno_merge_all_constants, false))
CmdArgs.push_back("-fmerge-all-constants");
if (Args.hasFlag(options::OPT_fno_delete_null_pointer_checks,
options::OPT_fdelete_null_pointer_checks, false))
CmdArgs.push_back("-fno-delete-null-pointer-checks");
// LLVM Code Generator Options.
for (const Arg *A : Args.filtered(options::OPT_frewrite_map_file_EQ)) {
StringRef Map = A->getValue();
if (!llvm::sys::fs::exists(Map)) {
D.Diag(diag::err_drv_no_such_file) << Map;
} else {
A->render(Args, CmdArgs);
A->claim();
}
}
if (Arg *A = Args.getLastArg(options::OPT_mabi_EQ_vec_extabi,
options::OPT_mabi_EQ_vec_default)) {
if (!Triple.isOSAIX())
D.Diag(diag::err_drv_unsupported_opt_for_target)
<< A->getSpelling() << RawTriple.str();
if (A->getOption().getID() == options::OPT_mabi_EQ_vec_extabi)
CmdArgs.push_back("-mabi=vec-extabi");
else
CmdArgs.push_back("-mabi=vec-default");
}
if (Arg *A = Args.getLastArg(options::OPT_mlong_double_128)) {
// Emit the unsupported option error until the Clang's library integration
// support for 128-bit long double is available for AIX.
if (Triple.isOSAIX())
D.Diag(diag::err_drv_unsupported_opt_for_target)
<< A->getSpelling() << RawTriple.str();
}
if (Arg *A = Args.getLastArg(options::OPT_Wframe_larger_than_EQ)) {
StringRef v = A->getValue();
// FIXME: Validate the argument here so we don't produce meaningless errors
// about -fwarn-stack-size=.
if (v.empty())
D.Diag(diag::err_drv_missing_argument) << A->getSpelling() << 1;
else
CmdArgs.push_back(Args.MakeArgString("-fwarn-stack-size=" + v));
A->claim();
}
if (!Args.hasFlag(options::OPT_fjump_tables, options::OPT_fno_jump_tables,
true))
CmdArgs.push_back("-fno-jump-tables");
if (Args.hasFlag(options::OPT_fprofile_sample_accurate,
options::OPT_fno_profile_sample_accurate, false))
CmdArgs.push_back("-fprofile-sample-accurate");
if (!Args.hasFlag(options::OPT_fpreserve_as_comments,
options::OPT_fno_preserve_as_comments, true))
CmdArgs.push_back("-fno-preserve-as-comments");
if (Arg *A = Args.getLastArg(options::OPT_mregparm_EQ)) {
CmdArgs.push_back("-mregparm");
CmdArgs.push_back(A->getValue());
}
if (Arg *A = Args.getLastArg(options::OPT_maix_struct_return,
options::OPT_msvr4_struct_return)) {
if (!TC.getTriple().isPPC32()) {
D.Diag(diag::err_drv_unsupported_opt_for_target)
<< A->getSpelling() << RawTriple.str();
} else if (A->getOption().matches(options::OPT_maix_struct_return)) {
CmdArgs.push_back("-maix-struct-return");
} else {
assert(A->getOption().matches(options::OPT_msvr4_struct_return));
CmdArgs.push_back("-msvr4-struct-return");
}
}
if (Arg *A = Args.getLastArg(options::OPT_fpcc_struct_return,
options::OPT_freg_struct_return)) {
if (TC.getArch() != llvm::Triple::x86) {
D.Diag(diag::err_drv_unsupported_opt_for_target)
<< A->getSpelling() << RawTriple.str();
} else if (A->getOption().matches(options::OPT_fpcc_struct_return)) {
CmdArgs.push_back("-fpcc-struct-return");
} else {
assert(A->getOption().matches(options::OPT_freg_struct_return));
CmdArgs.push_back("-freg-struct-return");
}
}
if (Args.hasFlag(options::OPT_mrtd, options::OPT_mno_rtd, false))
CmdArgs.push_back("-fdefault-calling-conv=stdcall");
if (Args.hasArg(options::OPT_fenable_matrix)) {
// enable-matrix is needed by both the LangOpts and by LLVM.
CmdArgs.push_back("-fenable-matrix");
CmdArgs.push_back("-mllvm");
CmdArgs.push_back("-enable-matrix");
}
CodeGenOptions::FramePointerKind FPKeepKind =
getFramePointerKind(Args, RawTriple);
const char *FPKeepKindStr = nullptr;
switch (FPKeepKind) {
case CodeGenOptions::FramePointerKind::None:
FPKeepKindStr = "-mframe-pointer=none";
break;
case CodeGenOptions::FramePointerKind::NonLeaf:
FPKeepKindStr = "-mframe-pointer=non-leaf";
break;
case CodeGenOptions::FramePointerKind::All:
FPKeepKindStr = "-mframe-pointer=all";
break;
}
assert(FPKeepKindStr && "unknown FramePointerKind");
CmdArgs.push_back(FPKeepKindStr);
if (!Args.hasFlag(options::OPT_fzero_initialized_in_bss,
options::OPT_fno_zero_initialized_in_bss, true))
CmdArgs.push_back("-fno-zero-initialized-in-bss");
bool OFastEnabled = isOptimizationLevelFast(Args);
// If -Ofast is the optimization level, then -fstrict-aliasing should be
// enabled. This alias option is being used to simplify the hasFlag logic.
OptSpecifier StrictAliasingAliasOption =
OFastEnabled ? options::OPT_Ofast : options::OPT_fstrict_aliasing;
// We turn strict aliasing off by default if we're in CL mode, since MSVC
// doesn't do any TBAA.
bool TBAAOnByDefault = !D.IsCLMode();
if (!Args.hasFlag(options::OPT_fstrict_aliasing, StrictAliasingAliasOption,
options::OPT_fno_strict_aliasing, TBAAOnByDefault))
CmdArgs.push_back("-relaxed-aliasing");
if (!Args.hasFlag(options::OPT_fstruct_path_tbaa,
options::OPT_fno_struct_path_tbaa))
CmdArgs.push_back("-no-struct-path-tbaa");
if (Args.hasFlag(options::OPT_fstrict_enums, options::OPT_fno_strict_enums,
false))
CmdArgs.push_back("-fstrict-enums");
if (!Args.hasFlag(options::OPT_fstrict_return, options::OPT_fno_strict_return,
true))
CmdArgs.push_back("-fno-strict-return");
if (Args.hasFlag(options::OPT_fallow_editor_placeholders,
options::OPT_fno_allow_editor_placeholders, false))
CmdArgs.push_back("-fallow-editor-placeholders");
if (Args.hasFlag(options::OPT_fstrict_vtable_pointers,
options::OPT_fno_strict_vtable_pointers,
false))
CmdArgs.push_back("-fstrict-vtable-pointers");
if (Args.hasFlag(options::OPT_fforce_emit_vtables,
options::OPT_fno_force_emit_vtables,
false))
CmdArgs.push_back("-fforce-emit-vtables");
if (!Args.hasFlag(options::OPT_foptimize_sibling_calls,
options::OPT_fno_optimize_sibling_calls))
CmdArgs.push_back("-mdisable-tail-calls");
if (Args.hasFlag(options::OPT_fno_escaping_block_tail_calls,
options::OPT_fescaping_block_tail_calls, false))
CmdArgs.push_back("-fno-escaping-block-tail-calls");
Args.AddLastArg(CmdArgs, options::OPT_ffine_grained_bitfield_accesses,
options::OPT_fno_fine_grained_bitfield_accesses);
Args.AddLastArg(CmdArgs, options::OPT_fexperimental_relative_cxx_abi_vtables,
options::OPT_fno_experimental_relative_cxx_abi_vtables);
// Handle segmented stacks.
if (Args.hasFlag(options::OPT_fsplit_stack, options::OPT_fno_split_stack,
false))
CmdArgs.push_back("-fsplit-stack");
// -fprotect-parens=0 is default.
if (Args.hasFlag(options::OPT_fprotect_parens,
options::OPT_fno_protect_parens, false))
CmdArgs.push_back("-fprotect-parens");
RenderFloatingPointOptions(TC, D, OFastEnabled, Args, CmdArgs, JA);
if (Arg *A = Args.getLastArg(options::OPT_fextend_args_EQ)) {
const llvm::Triple::ArchType Arch = TC.getArch();
if (Arch == llvm::Triple::x86 || Arch == llvm::Triple::x86_64) {
StringRef V = A->getValue();
if (V == "64")
CmdArgs.push_back("-fextend-arguments=64");
else if (V != "32")
D.Diag(diag::err_drv_invalid_argument_to_option)
<< A->getValue() << A->getOption().getName();
} else
D.Diag(diag::err_drv_unsupported_opt_for_target)
<< A->getOption().getName() << TripleStr;
}
if (Arg *A = Args.getLastArg(options::OPT_mdouble_EQ)) {
if (TC.getArch() == llvm::Triple::avr)
A->render(Args, CmdArgs);
else
D.Diag(diag::err_drv_unsupported_opt_for_target)
<< A->getAsString(Args) << TripleStr;
}
if (Arg *A = Args.getLastArg(options::OPT_LongDouble_Group)) {
if (TC.getTriple().isX86())
A->render(Args, CmdArgs);
else if (TC.getTriple().isPPC() &&
(A->getOption().getID() != options::OPT_mlong_double_80))
A->render(Args, CmdArgs);
else
D.Diag(diag::err_drv_unsupported_opt_for_target)
<< A->getAsString(Args) << TripleStr;
}
// Decide whether to use verbose asm. Verbose assembly is the default on
// toolchains which have the integrated assembler on by default.
bool IsIntegratedAssemblerDefault = TC.IsIntegratedAssemblerDefault();
if (!Args.hasFlag(options::OPT_fverbose_asm, options::OPT_fno_verbose_asm,
IsIntegratedAssemblerDefault))
CmdArgs.push_back("-fno-verbose-asm");
// Parse 'none' or '$major.$minor'. Disallow -fbinutils-version=0 because we
// use that to indicate the MC default in the backend.
if (Arg *A = Args.getLastArg(options::OPT_fbinutils_version_EQ)) {
StringRef V = A->getValue();
unsigned Num;
if (V == "none")
A->render(Args, CmdArgs);
else if (!V.consumeInteger(10, Num) && Num > 0 &&
(V.empty() || (V.consume_front(".") &&
!V.consumeInteger(10, Num) && V.empty())))
A->render(Args, CmdArgs);
else
D.Diag(diag::err_drv_invalid_argument_to_option)
<< A->getValue() << A->getOption().getName();
}
// If toolchain choose to use MCAsmParser for inline asm don't pass the
// option to disable integrated-as explictly.
if (!TC.useIntegratedAs() && !TC.parseInlineAsmUsingAsmParser())
CmdArgs.push_back("-no-integrated-as");
if (Args.hasArg(options::OPT_fdebug_pass_structure)) {
CmdArgs.push_back("-mdebug-pass");
CmdArgs.push_back("Structure");
}
if (Args.hasArg(options::OPT_fdebug_pass_arguments)) {
CmdArgs.push_back("-mdebug-pass");
CmdArgs.push_back("Arguments");
}
// Enable -mconstructor-aliases except on darwin, where we have to work around
// a linker bug (see <rdar://problem/7651567>), and CUDA device code, where
// aliases aren't supported.
if (!RawTriple.isOSDarwin() && !RawTriple.isNVPTX())
CmdArgs.push_back("-mconstructor-aliases");
// Darwin's kernel doesn't support guard variables; just die if we
// try to use them.
if (KernelOrKext && RawTriple.isOSDarwin())
CmdArgs.push_back("-fforbid-guard-variables");
if (Args.hasFlag(options::OPT_mms_bitfields, options::OPT_mno_ms_bitfields,
Triple.isWindowsGNUEnvironment())) {
CmdArgs.push_back("-mms-bitfields");
}
// Non-PIC code defaults to -fdirect-access-external-data while PIC code
// defaults to -fno-direct-access-external-data. Pass the option if different
// from the default.
if (Arg *A = Args.getLastArg(options::OPT_fdirect_access_external_data,
options::OPT_fno_direct_access_external_data))
if (A->getOption().matches(options::OPT_fdirect_access_external_data) !=
(PICLevel == 0))
A->render(Args, CmdArgs);
if (Args.hasFlag(options::OPT_fno_plt, options::OPT_fplt, false)) {
CmdArgs.push_back("-fno-plt");
}
// -fhosted is default.
// TODO: Audit uses of KernelOrKext and see where it'd be more appropriate to
// use Freestanding.
bool Freestanding =
Args.hasFlag(options::OPT_ffreestanding, options::OPT_fhosted, false) ||
KernelOrKext;
if (Freestanding)
CmdArgs.push_back("-ffreestanding");
// This is a coarse approximation of what llvm-gcc actually does, both
// -fasynchronous-unwind-tables and -fnon-call-exceptions interact in more
// complicated ways.
auto SanitizeArgs = TC.getSanitizerArgs(Args);
bool AsyncUnwindTables = Args.hasFlag(
options::OPT_fasynchronous_unwind_tables,
options::OPT_fno_asynchronous_unwind_tables,
(TC.IsUnwindTablesDefault(Args) || SanitizeArgs.needsUnwindTables()) &&
!Freestanding);
bool UnwindTables = Args.hasFlag(options::OPT_funwind_tables,
options::OPT_fno_unwind_tables, false);
if (AsyncUnwindTables)
CmdArgs.push_back("-funwind-tables=2");
else if (UnwindTables)
CmdArgs.push_back("-funwind-tables=1");
// Prepare `-aux-target-cpu` and `-aux-target-feature` unless
// `--gpu-use-aux-triple-only` is specified.
if (!Args.getLastArg(options::OPT_gpu_use_aux_triple_only) &&
(IsCudaDevice || IsHIPDevice)) {
const ArgList &HostArgs =
C.getArgsForToolChain(nullptr, StringRef(), Action::OFK_None);
std::string HostCPU =
getCPUName(D, HostArgs, *TC.getAuxTriple(), /*FromAs*/ false);
if (!HostCPU.empty()) {
CmdArgs.push_back("-aux-target-cpu");
CmdArgs.push_back(Args.MakeArgString(HostCPU));
}
getTargetFeatures(D, *TC.getAuxTriple(), HostArgs, CmdArgs,
/*ForAS*/ false, /*IsAux*/ true);
}
TC.addClangTargetOptions(Args, CmdArgs, JA.getOffloadingDeviceKind());
// FIXME: Handle -mtune=.
(void)Args.hasArg(options::OPT_mtune_EQ);
if (Arg *A = Args.getLastArg(options::OPT_mcmodel_EQ)) {
StringRef CM = A->getValue();
if (CM == "small" || CM == "kernel" || CM == "medium" || CM == "large" ||
CM == "tiny") {
if (Triple.isOSAIX() && CM == "medium")
CmdArgs.push_back("-mcmodel=large");
else
A->render(Args, CmdArgs);
} else {
D.Diag(diag::err_drv_invalid_argument_to_option)
<< CM << A->getOption().getName();
}
}
if (Arg *A = Args.getLastArg(options::OPT_mtls_size_EQ)) {
StringRef Value = A->getValue();
unsigned TLSSize = 0;
Value.getAsInteger(10, TLSSize);
if (!Triple.isAArch64() || !Triple.isOSBinFormatELF())
D.Diag(diag::err_drv_unsupported_opt_for_target)
<< A->getOption().getName() << TripleStr;
if (TLSSize != 12 && TLSSize != 24 && TLSSize != 32 && TLSSize != 48)
D.Diag(diag::err_drv_invalid_int_value)
<< A->getOption().getName() << Value;
Args.AddLastArg(CmdArgs, options::OPT_mtls_size_EQ);
}
// Add the target cpu
std::string CPU = getCPUName(D, Args, Triple, /*FromAs*/ false);
if (!CPU.empty()) {
CmdArgs.push_back("-target-cpu");
CmdArgs.push_back(Args.MakeArgString(CPU));
}
RenderTargetOptions(Triple, Args, KernelOrKext, CmdArgs);
// FIXME: For now we want to demote any errors to warnings, when they have
// been raised for asking the wrong question of scalable vectors, such as
// asking for the fixed number of elements. This may happen because code that
// is not yet ported to work for scalable vectors uses the wrong interfaces,
// whereas the behaviour is actually correct. Emitting a warning helps bring
// up scalable vector support in an incremental way. When scalable vector
// support is stable enough, all uses of wrong interfaces should be considered
// as errors, but until then, we can live with a warning being emitted by the
// compiler. This way, Clang can be used to compile code with scalable vectors
// and identify possible issues.
if (isa<BackendJobAction>(JA)) {
CmdArgs.push_back("-mllvm");
CmdArgs.push_back("-treat-scalable-fixed-error-as-warning");
}
// These two are potentially updated by AddClangCLArgs.
codegenoptions::DebugInfoKind DebugInfoKind = codegenoptions::NoDebugInfo;
bool EmitCodeView = false;
// Add clang-cl arguments.
types::ID InputType = Input.getType();
if (D.IsCLMode())
AddClangCLArgs(Args, InputType, CmdArgs, &DebugInfoKind, &EmitCodeView);
DwarfFissionKind DwarfFission = DwarfFissionKind::None;
renderDebugOptions(TC, D, RawTriple, Args, EmitCodeView,
types::isLLVMIR(InputType), CmdArgs, DebugInfoKind,
DwarfFission);
// Add the split debug info name to the command lines here so we
// can propagate it to the backend.
bool SplitDWARF = (DwarfFission != DwarfFissionKind::None) &&
(TC.getTriple().isOSBinFormatELF() ||
TC.getTriple().isOSBinFormatWasm()) &&
(isa<AssembleJobAction>(JA) || isa<CompileJobAction>(JA) ||
isa<BackendJobAction>(JA));
if (SplitDWARF) {
const char *SplitDWARFOut = SplitDebugName(JA, Args, Input, Output);
CmdArgs.push_back("-split-dwarf-file");
CmdArgs.push_back(SplitDWARFOut);
if (DwarfFission == DwarfFissionKind::Split) {
CmdArgs.push_back("-split-dwarf-output");
CmdArgs.push_back(SplitDWARFOut);
}
}
// Pass the linker version in use.
if (Arg *A = Args.getLastArg(options::OPT_mlinker_version_EQ)) {
CmdArgs.push_back("-target-linker-version");
CmdArgs.push_back(A->getValue());
}
// Explicitly error on some things we know we don't support and can't just
// ignore.
if (!Args.hasArg(options::OPT_fallow_unsupported)) {
Arg *Unsupported;
if (types::isCXX(InputType) && RawTriple.isOSDarwin() &&
TC.getArch() == llvm::Triple::x86) {
if ((Unsupported = Args.getLastArg(options::OPT_fapple_kext)) ||
(Unsupported = Args.getLastArg(options::OPT_mkernel)))
D.Diag(diag::err_drv_clang_unsupported_opt_cxx_darwin_i386)
<< Unsupported->getOption().getName();
}
// The faltivec option has been superseded by the maltivec option.
if ((Unsupported = Args.getLastArg(options::OPT_faltivec)))
D.Diag(diag::err_drv_clang_unsupported_opt_faltivec)
<< Unsupported->getOption().getName()
<< "please use -maltivec and include altivec.h explicitly";
if ((Unsupported = Args.getLastArg(options::OPT_fno_altivec)))
D.Diag(diag::err_drv_clang_unsupported_opt_faltivec)
<< Unsupported->getOption().getName() << "please use -mno-altivec";
}
Args.AddAllArgs(CmdArgs, options::OPT_v);
if (Args.getLastArg(options::OPT_H)) {
CmdArgs.push_back("-H");
CmdArgs.push_back("-sys-header-deps");
}
Args.AddAllArgs(CmdArgs, options::OPT_fshow_skipped_includes);
if (D.CCPrintHeaders && !D.CCGenDiagnostics) {
CmdArgs.push_back("-header-include-file");
CmdArgs.push_back(!D.CCPrintHeadersFilename.empty()
? D.CCPrintHeadersFilename.c_str()
: "-");
CmdArgs.push_back("-sys-header-deps");
}
Args.AddLastArg(CmdArgs, options::OPT_P);
Args.AddLastArg(CmdArgs, options::OPT_print_ivar_layout);
if (D.CCLogDiagnostics && !D.CCGenDiagnostics) {
CmdArgs.push_back("-diagnostic-log-file");
CmdArgs.push_back(!D.CCLogDiagnosticsFilename.empty()
? D.CCLogDiagnosticsFilename.c_str()
: "-");
}
// Give the gen diagnostics more chances to succeed, by avoiding intentional
// crashes.
if (D.CCGenDiagnostics)
CmdArgs.push_back("-disable-pragma-debug-crash");
// Allow backend to put its diagnostic files in the same place as frontend
// crash diagnostics files.
if (Args.hasArg(options::OPT_fcrash_diagnostics_dir)) {
StringRef Dir = Args.getLastArgValue(options::OPT_fcrash_diagnostics_dir);
CmdArgs.push_back("-mllvm");
CmdArgs.push_back(Args.MakeArgString("-crash-diagnostics-dir=" + Dir));
}
bool UseSeparateSections = isUseSeparateSections(Triple);
if (Args.hasFlag(options::OPT_ffunction_sections,
options::OPT_fno_function_sections, UseSeparateSections)) {
CmdArgs.push_back("-ffunction-sections");
}
if (Arg *A = Args.getLastArg(options::OPT_fbasic_block_sections_EQ)) {
StringRef Val = A->getValue();
if (Triple.isX86() && Triple.isOSBinFormatELF()) {
if (Val != "all" && Val != "labels" && Val != "none" &&
!Val.startswith("list="))
D.Diag(diag::err_drv_invalid_value)
<< A->getAsString(Args) << A->getValue();
else
A->render(Args, CmdArgs);
} else if (Triple.isNVPTX()) {
// Do not pass the option to the GPU compilation. We still want it enabled
// for the host-side compilation, so seeing it here is not an error.
} else if (Val != "none") {
// =none is allowed everywhere. It's useful for overriding the option
// and is the same as not specifying the option.
D.Diag(diag::err_drv_unsupported_opt_for_target)
<< A->getAsString(Args) << TripleStr;
}
}
bool HasDefaultDataSections = Triple.isOSBinFormatXCOFF();
if (Args.hasFlag(options::OPT_fdata_sections, options::OPT_fno_data_sections,
UseSeparateSections || HasDefaultDataSections)) {
CmdArgs.push_back("-fdata-sections");
}
if (!Args.hasFlag(options::OPT_funique_section_names,
options::OPT_fno_unique_section_names, true))
CmdArgs.push_back("-fno-unique-section-names");
if (Args.hasFlag(options::OPT_funique_internal_linkage_names,
options::OPT_fno_unique_internal_linkage_names, false))
CmdArgs.push_back("-funique-internal-linkage-names");
if (Args.hasFlag(options::OPT_funique_basic_block_section_names,
options::OPT_fno_unique_basic_block_section_names, false))
CmdArgs.push_back("-funique-basic-block-section-names");
if (Arg *A = Args.getLastArg(options::OPT_fsplit_machine_functions,
options::OPT_fno_split_machine_functions)) {
// This codegen pass is only available on x86-elf targets.
if (Triple.isX86() && Triple.isOSBinFormatELF()) {
if (A->getOption().matches(options::OPT_fsplit_machine_functions))
A->render(Args, CmdArgs);
} else {
D.Diag(diag::err_drv_unsupported_opt_for_target)
<< A->getAsString(Args) << TripleStr;
}
}
Args.AddLastArg(CmdArgs, options::OPT_finstrument_functions,
options::OPT_finstrument_functions_after_inlining,
options::OPT_finstrument_function_entry_bare);
// NVPTX/AMDGCN doesn't support PGO or coverage. There's no runtime support
// for sampling, overhead of call arc collection is way too high and there's
// no way to collect the output.
if (!Triple.isNVPTX() && !Triple.isAMDGCN())
addPGOAndCoverageFlags(TC, C, D, Output, Args, SanitizeArgs, CmdArgs);
Args.AddLastArg(CmdArgs, options::OPT_fclang_abi_compat_EQ);
// Add runtime flag for PS4 when PGO, coverage, or sanitizers are enabled.
if (RawTriple.isPS4CPU() &&
!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
PS4cpu::addProfileRTArgs(TC, Args, CmdArgs);
PS4cpu::addSanitizerArgs(TC, Args, CmdArgs);
}
// Pass options for controlling the default header search paths.
if (Args.hasArg(options::OPT_nostdinc)) {
CmdArgs.push_back("-nostdsysteminc");
CmdArgs.push_back("-nobuiltininc");
} else {
if (Args.hasArg(options::OPT_nostdlibinc))
CmdArgs.push_back("-nostdsysteminc");
Args.AddLastArg(CmdArgs, options::OPT_nostdincxx);
Args.AddLastArg(CmdArgs, options::OPT_nobuiltininc);
}
// Pass the path to compiler resource files.
CmdArgs.push_back("-resource-dir");
CmdArgs.push_back(D.ResourceDir.c_str());
Args.AddLastArg(CmdArgs, options::OPT_working_directory);
RenderARCMigrateToolOptions(D, Args, CmdArgs);
// Add preprocessing options like -I, -D, etc. if we are using the
// preprocessor.
//
// FIXME: Support -fpreprocessed
if (types::getPreprocessedType(InputType) != types::TY_INVALID)
AddPreprocessingOptions(C, JA, D, Args, CmdArgs, Output, Inputs);
// Don't warn about "clang -c -DPIC -fPIC test.i" because libtool.m4 assumes
// that "The compiler can only warn and ignore the option if not recognized".
// When building with ccache, it will pass -D options to clang even on
// preprocessed inputs and configure concludes that -fPIC is not supported.
Args.ClaimAllArgs(options::OPT_D);
// Manually translate -O4 to -O3; let clang reject others.
if (Arg *A = Args.getLastArg(options::OPT_O_Group)) {
if (A->getOption().matches(options::OPT_O4)) {
CmdArgs.push_back("-O3");
D.Diag(diag::warn_O4_is_O3);
} else {
A->render(Args, CmdArgs);
}
}
// Warn about ignored options to clang.
for (const Arg *A :
Args.filtered(options::OPT_clang_ignored_gcc_optimization_f_Group)) {
D.Diag(diag::warn_ignored_gcc_optimization) << A->getAsString(Args);
A->claim();
}
for (const Arg *A :
Args.filtered(options::OPT_clang_ignored_legacy_options_Group)) {
D.Diag(diag::warn_ignored_clang_option) << A->getAsString(Args);
A->claim();
}
claimNoWarnArgs(Args);
Args.AddAllArgs(CmdArgs, options::OPT_R_Group);
for (const Arg *A :
Args.filtered(options::OPT_W_Group, options::OPT__SLASH_wd)) {
A->claim();
if (A->getOption().getID() == options::OPT__SLASH_wd) {
unsigned WarningNumber;
if (StringRef(A->getValue()).getAsInteger(10, WarningNumber)) {
D.Diag(diag::err_drv_invalid_int_value)
<< A->getAsString(Args) << A->getValue();
continue;
}
if (auto Group = diagGroupFromCLWarningID(WarningNumber)) {
CmdArgs.push_back(Args.MakeArgString(
"-Wno-" + DiagnosticIDs::getWarningOptionForGroup(*Group)));
}
continue;
}
A->render(Args, CmdArgs);
}
if (Args.hasFlag(options::OPT_pedantic, options::OPT_no_pedantic, false))
CmdArgs.push_back("-pedantic");
Args.AddLastArg(CmdArgs, options::OPT_pedantic_errors);
Args.AddLastArg(CmdArgs, options::OPT_w);
// Fixed point flags
if (Args.hasFlag(options::OPT_ffixed_point, options::OPT_fno_fixed_point,
/*Default=*/false))
Args.AddLastArg(CmdArgs, options::OPT_ffixed_point);
if (Arg *A = Args.getLastArg(options::OPT_fcxx_abi_EQ))
A->render(Args, CmdArgs);
Args.AddLastArg(CmdArgs, options::OPT_fexperimental_relative_cxx_abi_vtables,
options::OPT_fno_experimental_relative_cxx_abi_vtables);
if (Arg *A = Args.getLastArg(options::OPT_ffuchsia_api_level_EQ))
A->render(Args, CmdArgs);
// Handle -{std, ansi, trigraphs} -- take the last of -{std, ansi}
// (-ansi is equivalent to -std=c89 or -std=c++98).
//
// If a std is supplied, only add -trigraphs if it follows the
// option.
bool ImplyVCPPCVer = false;
bool ImplyVCPPCXXVer = false;
const Arg *Std = Args.getLastArg(options::OPT_std_EQ, options::OPT_ansi);
if (Std) {
if (Std->getOption().matches(options::OPT_ansi))
if (types::isCXX(InputType))
CmdArgs.push_back("-std=c++98");
else
CmdArgs.push_back("-std=c89");
else
Std->render(Args, CmdArgs);
// If -f(no-)trigraphs appears after the language standard flag, honor it.
if (Arg *A = Args.getLastArg(options::OPT_std_EQ, options::OPT_ansi,
options::OPT_ftrigraphs,
options::OPT_fno_trigraphs))
if (A != Std)
A->render(Args, CmdArgs);
} else {
// Honor -std-default.
//
// FIXME: Clang doesn't correctly handle -std= when the input language
// doesn't match. For the time being just ignore this for C++ inputs;
// eventually we want to do all the standard defaulting here instead of
// splitting it between the driver and clang -cc1.
if (!types::isCXX(InputType)) {
if (!Args.hasArg(options::OPT__SLASH_std)) {
Args.AddAllArgsTranslated(CmdArgs, options::OPT_std_default_EQ, "-std=",
/*Joined=*/true);
} else
ImplyVCPPCVer = true;
}
else if (IsWindowsMSVC)
ImplyVCPPCXXVer = true;
Args.AddLastArg(CmdArgs, options::OPT_ftrigraphs,
options::OPT_fno_trigraphs);
// HIP headers has minimum C++ standard requirements. Therefore set the
// default language standard.
if (IsHIP)
CmdArgs.push_back(IsWindowsMSVC ? "-std=c++14" : "-std=c++11");
}
// GCC's behavior for -Wwrite-strings is a bit strange:
// * In C, this "warning flag" changes the types of string literals from
// 'char[N]' to 'const char[N]', and thus triggers an unrelated warning
// for the discarded qualifier.
// * In C++, this is just a normal warning flag.
//
// Implementing this warning correctly in C is hard, so we follow GCC's
// behavior for now. FIXME: Directly diagnose uses of a string literal as
// a non-const char* in C, rather than using this crude hack.
if (!types::isCXX(InputType)) {
// FIXME: This should behave just like a warning flag, and thus should also
// respect -Weverything, -Wno-everything, -Werror=write-strings, and so on.
Arg *WriteStrings =
Args.getLastArg(options::OPT_Wwrite_strings,
options::OPT_Wno_write_strings, options::OPT_w);
if (WriteStrings &&
WriteStrings->getOption().matches(options::OPT_Wwrite_strings))
CmdArgs.push_back("-fconst-strings");
}
// GCC provides a macro definition '__DEPRECATED' when -Wdeprecated is active
// during C++ compilation, which it is by default. GCC keeps this define even
// in the presence of '-w', match this behavior bug-for-bug.
if (types::isCXX(InputType) &&
Args.hasFlag(options::OPT_Wdeprecated, options::OPT_Wno_deprecated,
true)) {
CmdArgs.push_back("-fdeprecated-macro");
}
// Translate GCC's misnamer '-fasm' arguments to '-fgnu-keywords'.
if (Arg *Asm = Args.getLastArg(options::OPT_fasm, options::OPT_fno_asm)) {
if (Asm->getOption().matches(options::OPT_fasm))
CmdArgs.push_back("-fgnu-keywords");
else
CmdArgs.push_back("-fno-gnu-keywords");
}
if (!ShouldEnableAutolink(Args, TC, JA))
CmdArgs.push_back("-fno-autolink");
// Add in -fdebug-compilation-dir if necessary.
const char *DebugCompilationDir =
addDebugCompDirArg(Args, CmdArgs, D.getVFS());
addDebugPrefixMapArg(D, Args, CmdArgs);
if (Arg *A = Args.getLastArg(options::OPT_ftemplate_depth_,
options::OPT_ftemplate_depth_EQ)) {
CmdArgs.push_back("-ftemplate-depth");
CmdArgs.push_back(A->getValue());
}
if (Arg *A = Args.getLastArg(options::OPT_foperator_arrow_depth_EQ)) {
CmdArgs.push_back("-foperator-arrow-depth");
CmdArgs.push_back(A->getValue());
}
if (Arg *A = Args.getLastArg(options::OPT_fconstexpr_depth_EQ)) {
CmdArgs.push_back("-fconstexpr-depth");
CmdArgs.push_back(A->getValue());
}
if (Arg *A = Args.getLastArg(options::OPT_fconstexpr_steps_EQ)) {
CmdArgs.push_back("-fconstexpr-steps");
CmdArgs.push_back(A->getValue());
}
if (Args.hasArg(options::OPT_fexperimental_new_constant_interpreter))
CmdArgs.push_back("-fexperimental-new-constant-interpreter");
if (Arg *A = Args.getLastArg(options::OPT_fbracket_depth_EQ)) {
CmdArgs.push_back("-fbracket-depth");
CmdArgs.push_back(A->getValue());
}
if (Arg *A = Args.getLastArg(options::OPT_Wlarge_by_value_copy_EQ,
options::OPT_Wlarge_by_value_copy_def)) {
if (A->getNumValues()) {
StringRef bytes = A->getValue();
CmdArgs.push_back(Args.MakeArgString("-Wlarge-by-value-copy=" + bytes));
} else
CmdArgs.push_back("-Wlarge-by-value-copy=64"); // default value
}
if (Args.hasArg(options::OPT_relocatable_pch))
CmdArgs.push_back("-relocatable-pch");
if (const Arg *A = Args.getLastArg(options::OPT_fcf_runtime_abi_EQ)) {
static const char *kCFABIs[] = {
"standalone", "objc", "swift", "swift-5.0", "swift-4.2", "swift-4.1",
};
if (find(kCFABIs, StringRef(A->getValue())) == std::end(kCFABIs))
D.Diag(diag::err_drv_invalid_cf_runtime_abi) << A->getValue();
else
A->render(Args, CmdArgs);
}
if (Arg *A = Args.getLastArg(options::OPT_fconstant_string_class_EQ)) {
CmdArgs.push_back("-fconstant-string-class");
CmdArgs.push_back(A->getValue());
}
if (Arg *A = Args.getLastArg(options::OPT_ftabstop_EQ)) {
CmdArgs.push_back("-ftabstop");
CmdArgs.push_back(A->getValue());
}
if (Args.hasFlag(options::OPT_fstack_size_section,
options::OPT_fno_stack_size_section, RawTriple.isPS4()))
CmdArgs.push_back("-fstack-size-section");
if (Args.hasArg(options::OPT_fstack_usage)) {
CmdArgs.push_back("-stack-usage-file");
if (Arg *OutputOpt = Args.getLastArg(options::OPT_o)) {
SmallString<128> OutputFilename(OutputOpt->getValue());
llvm::sys::path::replace_extension(OutputFilename, "su");
CmdArgs.push_back(Args.MakeArgString(OutputFilename));
} else
CmdArgs.push_back(
Args.MakeArgString(Twine(getBaseInputStem(Args, Inputs)) + ".su"));
}
CmdArgs.push_back("-ferror-limit");
if (Arg *A = Args.getLastArg(options::OPT_ferror_limit_EQ))
CmdArgs.push_back(A->getValue());
else
CmdArgs.push_back("19");
if (Arg *A = Args.getLastArg(options::OPT_fmacro_backtrace_limit_EQ)) {
CmdArgs.push_back("-fmacro-backtrace-limit");
CmdArgs.push_back(A->getValue());
}
if (Arg *A = Args.getLastArg(options::OPT_ftemplate_backtrace_limit_EQ)) {
CmdArgs.push_back("-ftemplate-backtrace-limit");
CmdArgs.push_back(A->getValue());
}
if (Arg *A = Args.getLastArg(options::OPT_fconstexpr_backtrace_limit_EQ)) {
CmdArgs.push_back("-fconstexpr-backtrace-limit");
CmdArgs.push_back(A->getValue());
}
if (Arg *A = Args.getLastArg(options::OPT_fspell_checking_limit_EQ)) {
CmdArgs.push_back("-fspell-checking-limit");
CmdArgs.push_back(A->getValue());
}
// Pass -fmessage-length=.
unsigned MessageLength = 0;
if (Arg *A = Args.getLastArg(options::OPT_fmessage_length_EQ)) {
StringRef V(A->getValue());
if (V.getAsInteger(0, MessageLength))
D.Diag(diag::err_drv_invalid_argument_to_option)
<< V << A->getOption().getName();
} else {
// If -fmessage-length=N was not specified, determine whether this is a
// terminal and, if so, implicitly define -fmessage-length appropriately.
MessageLength = llvm::sys::Process::StandardErrColumns();
}
if (MessageLength != 0)
CmdArgs.push_back(
Args.MakeArgString("-fmessage-length=" + Twine(MessageLength)));
// -fvisibility= and -fvisibility-ms-compat are of a piece.
if (const Arg *A = Args.getLastArg(options::OPT_fvisibility_EQ,
options::OPT_fvisibility_ms_compat)) {
if (A->getOption().matches(options::OPT_fvisibility_EQ)) {
CmdArgs.push_back("-fvisibility");
CmdArgs.push_back(A->getValue());
} else {
assert(A->getOption().matches(options::OPT_fvisibility_ms_compat));
CmdArgs.push_back("-fvisibility");
CmdArgs.push_back("hidden");
CmdArgs.push_back("-ftype-visibility");
CmdArgs.push_back("default");
}
}
if (!RawTriple.isPS4())
if (const Arg *A =
Args.getLastArg(options::OPT_fvisibility_from_dllstorageclass,
options::OPT_fno_visibility_from_dllstorageclass)) {
if (A->getOption().matches(
options::OPT_fvisibility_from_dllstorageclass)) {
CmdArgs.push_back("-fvisibility-from-dllstorageclass");
Args.AddLastArg(CmdArgs, options::OPT_fvisibility_dllexport_EQ);
Args.AddLastArg(CmdArgs, options::OPT_fvisibility_nodllstorageclass_EQ);
Args.AddLastArg(CmdArgs, options::OPT_fvisibility_externs_dllimport_EQ);
Args.AddLastArg(CmdArgs,
options::OPT_fvisibility_externs_nodllstorageclass_EQ);
}
}
if (const Arg *A = Args.getLastArg(options::OPT_mignore_xcoff_visibility)) {
if (Triple.isOSAIX())
CmdArgs.push_back("-mignore-xcoff-visibility");
else
D.Diag(diag::err_drv_unsupported_opt_for_target)
<< A->getAsString(Args) << TripleStr;
}
if (Args.hasFlag(options::OPT_fvisibility_inlines_hidden,
options::OPT_fno_visibility_inlines_hidden, false))
CmdArgs.push_back("-fvisibility-inlines-hidden");
Args.AddLastArg(CmdArgs, options::OPT_fvisibility_inlines_hidden_static_local_var,
options::OPT_fno_visibility_inlines_hidden_static_local_var);
Args.AddLastArg(CmdArgs, options::OPT_fvisibility_global_new_delete_hidden);
Args.AddLastArg(CmdArgs, options::OPT_ftlsmodel_EQ);
if (Args.hasFlag(options::OPT_fnew_infallible,
options::OPT_fno_new_infallible, false))
CmdArgs.push_back("-fnew-infallible");
if (Args.hasFlag(options::OPT_fno_operator_names,
options::OPT_foperator_names, false))
CmdArgs.push_back("-fno-operator-names");
// Forward -f (flag) options which we can pass directly.
Args.AddLastArg(CmdArgs, options::OPT_femit_all_decls);
Args.AddLastArg(CmdArgs, options::OPT_fheinous_gnu_extensions);
Args.AddLastArg(CmdArgs, options::OPT_fdigraphs, options::OPT_fno_digraphs);
Args.AddLastArg(CmdArgs, options::OPT_femulated_tls,
options::OPT_fno_emulated_tls);
// AltiVec-like language extensions aren't relevant for assembling.
if (!isa<PreprocessJobAction>(JA) || Output.getType() != types::TY_PP_Asm)
Args.AddLastArg(CmdArgs, options::OPT_fzvector);
Args.AddLastArg(CmdArgs, options::OPT_fdiagnostics_show_template_tree);
Args.AddLastArg(CmdArgs, options::OPT_fno_elide_type);
// Forward flags for OpenMP. We don't do this if the current action is an
// device offloading action other than OpenMP.
if (Args.hasFlag(options::OPT_fopenmp, options::OPT_fopenmp_EQ,
options::OPT_fno_openmp, false) &&
(JA.isDeviceOffloading(Action::OFK_None) ||
JA.isDeviceOffloading(Action::OFK_OpenMP))) {
switch (D.getOpenMPRuntime(Args)) {
case Driver::OMPRT_OMP:
case Driver::OMPRT_IOMP5:
// Clang can generate useful OpenMP code for these two runtime libraries.
CmdArgs.push_back("-fopenmp");
// If no option regarding the use of TLS in OpenMP codegeneration is
// given, decide a default based on the target. Otherwise rely on the
// options and pass the right information to the frontend.
if (!Args.hasFlag(options::OPT_fopenmp_use_tls,
options::OPT_fnoopenmp_use_tls, /*Default=*/true))
CmdArgs.push_back("-fnoopenmp-use-tls");
Args.AddLastArg(CmdArgs, options::OPT_fopenmp_simd,
options::OPT_fno_openmp_simd);
Args.AddAllArgs(CmdArgs, options::OPT_fopenmp_enable_irbuilder);
Args.AddAllArgs(CmdArgs, options::OPT_fopenmp_version_EQ);
if (!Args.hasFlag(options::OPT_fopenmp_extensions,
options::OPT_fno_openmp_extensions, /*Default=*/true))
CmdArgs.push_back("-fno-openmp-extensions");
Args.AddAllArgs(CmdArgs, options::OPT_fopenmp_cuda_number_of_sm_EQ);
Args.AddAllArgs(CmdArgs, options::OPT_fopenmp_cuda_blocks_per_sm_EQ);
Args.AddAllArgs(CmdArgs,
options::OPT_fopenmp_cuda_teams_reduction_recs_num_EQ);
if (Args.hasFlag(options::OPT_fopenmp_optimistic_collapse,
options::OPT_fno_openmp_optimistic_collapse,
/*Default=*/false))
CmdArgs.push_back("-fopenmp-optimistic-collapse");
// When in OpenMP offloading mode with NVPTX target, forward
// cuda-mode flag
if (Args.hasFlag(options::OPT_fopenmp_cuda_mode,
options::OPT_fno_openmp_cuda_mode, /*Default=*/false))
CmdArgs.push_back("-fopenmp-cuda-mode");
// When in OpenMP offloading mode, enable or disable the new device
// runtime.
if (Args.hasFlag(options::OPT_fopenmp_target_new_runtime,
options::OPT_fno_openmp_target_new_runtime,
/*Default=*/true))
CmdArgs.push_back("-fopenmp-target-new-runtime");
// When in OpenMP offloading mode, enable debugging on the device.
Args.AddAllArgs(CmdArgs, options::OPT_fopenmp_target_debug_EQ);
if (Args.hasFlag(options::OPT_fopenmp_target_debug,
options::OPT_fno_openmp_target_debug, /*Default=*/false))
CmdArgs.push_back("-fopenmp-target-debug");
// When in OpenMP offloading mode with NVPTX target, check if full runtime
// is required.
if (Args.hasFlag(options::OPT_fopenmp_cuda_force_full_runtime,
options::OPT_fno_openmp_cuda_force_full_runtime,
/*Default=*/false))
CmdArgs.push_back("-fopenmp-cuda-force-full-runtime");
// When in OpenMP offloading mode, forward assumptions information about
// thread and team counts in the device.
if (Args.hasFlag(options::OPT_fopenmp_assume_teams_oversubscription,
options::OPT_fno_openmp_assume_teams_oversubscription,
/*Default=*/false))
CmdArgs.push_back("-fopenmp-assume-teams-oversubscription");
if (Args.hasFlag(options::OPT_fopenmp_assume_threads_oversubscription,
options::OPT_fno_openmp_assume_threads_oversubscription,
/*Default=*/false))
CmdArgs.push_back("-fopenmp-assume-threads-oversubscription");
break;
default:
// By default, if Clang doesn't know how to generate useful OpenMP code
// for a specific runtime library, we just don't pass the '-fopenmp' flag
// down to the actual compilation.
// FIXME: It would be better to have a mode which *only* omits IR
// generation based on the OpenMP support so that we get consistent
// semantic analysis, etc.
break;
}
} else {
Args.AddLastArg(CmdArgs, options::OPT_fopenmp_simd,
options::OPT_fno_openmp_simd);
Args.AddAllArgs(CmdArgs, options::OPT_fopenmp_version_EQ);
if (!Args.hasFlag(options::OPT_fopenmp_extensions,
options::OPT_fno_openmp_extensions, /*Default=*/true))
CmdArgs.push_back("-fno-openmp-extensions");
}
SanitizeArgs.addArgs(TC, Args, CmdArgs, InputType);
const XRayArgs &XRay = TC.getXRayArgs();
XRay.addArgs(TC, Args, CmdArgs, InputType);
for (const auto &Filename :
Args.getAllArgValues(options::OPT_fprofile_list_EQ)) {
if (D.getVFS().exists(Filename))
CmdArgs.push_back(Args.MakeArgString("-fprofile-list=" + Filename));
else
D.Diag(clang::diag::err_drv_no_such_file) << Filename;
}
if (Arg *A = Args.getLastArg(options::OPT_fpatchable_function_entry_EQ)) {
StringRef S0 = A->getValue(), S = S0;
unsigned Size, Offset = 0;
if (!Triple.isAArch64() && !Triple.isRISCV() && !Triple.isX86())
D.Diag(diag::err_drv_unsupported_opt_for_target)
<< A->getAsString(Args) << TripleStr;
else if (S.consumeInteger(10, Size) ||
(!S.empty() && (!S.consume_front(",") ||
S.consumeInteger(10, Offset) || !S.empty())))
D.Diag(diag::err_drv_invalid_argument_to_option)
<< S0 << A->getOption().getName();
else if (Size < Offset)
D.Diag(diag::err_drv_unsupported_fpatchable_function_entry_argument);
else {
CmdArgs.push_back(Args.MakeArgString(A->getSpelling() + Twine(Size)));
CmdArgs.push_back(Args.MakeArgString(
"-fpatchable-function-entry-offset=" + Twine(Offset)));
}
}
if (TC.SupportsProfiling()) {
Args.AddLastArg(CmdArgs, options::OPT_pg);
llvm::Triple::ArchType Arch = TC.getArch();
if (Arg *A = Args.getLastArg(options::OPT_mfentry)) {
if (Arch == llvm::Triple::systemz || TC.getTriple().isX86())
A->render(Args, CmdArgs);
else
D.Diag(diag::err_drv_unsupported_opt_for_target)
<< A->getAsString(Args) << TripleStr;
}
if (Arg *A = Args.getLastArg(options::OPT_mnop_mcount)) {
if (Arch == llvm::Triple::systemz)
A->render(Args, CmdArgs);
else
D.Diag(diag::err_drv_unsupported_opt_for_target)
<< A->getAsString(Args) << TripleStr;
}
if (Arg *A = Args.getLastArg(options::OPT_mrecord_mcount)) {
if (Arch == llvm::Triple::systemz)
A->render(Args, CmdArgs);
else
D.Diag(diag::err_drv_unsupported_opt_for_target)
<< A->getAsString(Args) << TripleStr;
}
}
if (Args.getLastArg(options::OPT_fapple_kext) ||
(Args.hasArg(options::OPT_mkernel) && types::isCXX(InputType)))
CmdArgs.push_back("-fapple-kext");
Args.AddLastArg(CmdArgs, options::OPT_altivec_src_compat);
Args.AddLastArg(CmdArgs, options::OPT_flax_vector_conversions_EQ);
Args.AddLastArg(CmdArgs, options::OPT_fobjc_sender_dependent_dispatch);
Args.AddLastArg(CmdArgs, options::OPT_fdiagnostics_print_source_range_info);
Args.AddLastArg(CmdArgs, options::OPT_fdiagnostics_parseable_fixits);
Args.AddLastArg(CmdArgs, options::OPT_ftime_report);
Args.AddLastArg(CmdArgs, options::OPT_ftime_report_EQ);
Args.AddLastArg(CmdArgs, options::OPT_ftime_trace);
Args.AddLastArg(CmdArgs, options::OPT_ftime_trace_granularity_EQ);
Args.AddLastArg(CmdArgs, options::OPT_ftrapv);
Args.AddLastArg(CmdArgs, options::OPT_malign_double);
Args.AddLastArg(CmdArgs, options::OPT_fno_temp_file);
if (Arg *A = Args.getLastArg(options::OPT_ftrapv_handler_EQ)) {
CmdArgs.push_back("-ftrapv-handler");
CmdArgs.push_back(A->getValue());
}
Args.AddLastArg(CmdArgs, options::OPT_ftrap_function_EQ);
// -fno-strict-overflow implies -fwrapv if it isn't disabled, but
// -fstrict-overflow won't turn off an explicitly enabled -fwrapv.
if (Arg *A = Args.getLastArg(options::OPT_fwrapv, options::OPT_fno_wrapv)) {
if (A->getOption().matches(options::OPT_fwrapv))
CmdArgs.push_back("-fwrapv");
} else if (Arg *A = Args.getLastArg(options::OPT_fstrict_overflow,
options::OPT_fno_strict_overflow)) {
if (A->getOption().matches(options::OPT_fno_strict_overflow))
CmdArgs.push_back("-fwrapv");
}
if (Arg *A = Args.getLastArg(options::OPT_freroll_loops,
options::OPT_fno_reroll_loops))
if (A->getOption().matches(options::OPT_freroll_loops))
CmdArgs.push_back("-freroll-loops");
Args.AddLastArg(CmdArgs, options::OPT_ffinite_loops,
options::OPT_fno_finite_loops);
Args.AddLastArg(CmdArgs, options::OPT_fwritable_strings);
Args.AddLastArg(CmdArgs, options::OPT_funroll_loops,
options::OPT_fno_unroll_loops);
Args.AddLastArg(CmdArgs, options::OPT_pthread);
if (Args.hasFlag(options::OPT_mspeculative_load_hardening,
options::OPT_mno_speculative_load_hardening, false))
CmdArgs.push_back(Args.MakeArgString("-mspeculative-load-hardening"));
RenderSSPOptions(D, TC, Args, CmdArgs, KernelOrKext);
RenderSCPOptions(TC, Args, CmdArgs);
RenderTrivialAutoVarInitOptions(D, TC, Args, CmdArgs);
Args.AddLastArg(CmdArgs, options::OPT_fswift_async_fp_EQ);
// Translate -mstackrealign
if (Args.hasFlag(options::OPT_mstackrealign, options::OPT_mno_stackrealign,
false))
CmdArgs.push_back(Args.MakeArgString("-mstackrealign"));
if (Args.hasArg(options::OPT_mstack_alignment)) {
StringRef alignment = Args.getLastArgValue(options::OPT_mstack_alignment);
CmdArgs.push_back(Args.MakeArgString("-mstack-alignment=" + alignment));
}
if (Args.hasArg(options::OPT_mstack_probe_size)) {
StringRef Size = Args.getLastArgValue(options::OPT_mstack_probe_size);
if (!Size.empty())
CmdArgs.push_back(Args.MakeArgString("-mstack-probe-size=" + Size));
else
CmdArgs.push_back("-mstack-probe-size=0");
}
if (!Args.hasFlag(options::OPT_mstack_arg_probe,
options::OPT_mno_stack_arg_probe, true))
CmdArgs.push_back(Args.MakeArgString("-mno-stack-arg-probe"));
if (Arg *A = Args.getLastArg(options::OPT_mrestrict_it,
options::OPT_mno_restrict_it)) {
if (A->getOption().matches(options::OPT_mrestrict_it)) {
CmdArgs.push_back("-mllvm");
CmdArgs.push_back("-arm-restrict-it");
} else {
CmdArgs.push_back("-mllvm");
CmdArgs.push_back("-arm-no-restrict-it");
}
} else if (Triple.isOSWindows() &&
(Triple.getArch() == llvm::Triple::arm ||
Triple.getArch() == llvm::Triple::thumb)) {
// Windows on ARM expects restricted IT blocks
CmdArgs.push_back("-mllvm");
CmdArgs.push_back("-arm-restrict-it");
}
// Forward -cl options to -cc1
RenderOpenCLOptions(Args, CmdArgs, InputType);
if (IsHIP) {
if (Args.hasFlag(options::OPT_fhip_new_launch_api,
options::OPT_fno_hip_new_launch_api, true))
CmdArgs.push_back("-fhip-new-launch-api");
if (Args.hasFlag(options::OPT_fgpu_allow_device_init,
options::OPT_fno_gpu_allow_device_init, false))
CmdArgs.push_back("-fgpu-allow-device-init");
}
if (IsCuda || IsHIP) {
if (Args.hasFlag(options::OPT_fgpu_rdc, options::OPT_fno_gpu_rdc, false))
CmdArgs.push_back("-fgpu-rdc");
if (Args.hasFlag(options::OPT_fgpu_defer_diag,
options::OPT_fno_gpu_defer_diag, false))
CmdArgs.push_back("-fgpu-defer-diag");
if (Args.hasFlag(options::OPT_fgpu_exclude_wrong_side_overloads,
options::OPT_fno_gpu_exclude_wrong_side_overloads,
false)) {
CmdArgs.push_back("-fgpu-exclude-wrong-side-overloads");
CmdArgs.push_back("-fgpu-defer-diag");
}
}
if (Arg *A = Args.getLastArg(options::OPT_fcf_protection_EQ)) {
CmdArgs.push_back(
Args.MakeArgString(Twine("-fcf-protection=") + A->getValue()));
}
// Forward -f options with positive and negative forms; we translate these by
// hand. Do not propagate PGO options to the GPU-side compilations as the
// profile info is for the host-side compilation only.
if (!(IsCudaDevice || IsHIPDevice)) {
if (Arg *A = getLastProfileSampleUseArg(Args)) {
auto *PGOArg = Args.getLastArg(
options::OPT_fprofile_generate, options::OPT_fprofile_generate_EQ,
options::OPT_fcs_profile_generate,
options::OPT_fcs_profile_generate_EQ, options::OPT_fprofile_use,
options::OPT_fprofile_use_EQ);
if (PGOArg)
D.Diag(diag::err_drv_argument_not_allowed_with)
<< "SampleUse with PGO options";
StringRef fname = A->getValue();
if (!llvm::sys::fs::exists(fname))
D.Diag(diag::err_drv_no_such_file) << fname;
else
A->render(Args, CmdArgs);
}
Args.AddLastArg(CmdArgs, options::OPT_fprofile_remapping_file_EQ);
if (Args.hasFlag(options::OPT_fpseudo_probe_for_profiling,
options::OPT_fno_pseudo_probe_for_profiling, false)) {
CmdArgs.push_back("-fpseudo-probe-for-profiling");
// Enforce -funique-internal-linkage-names if it's not explicitly turned
// off.
if (Args.hasFlag(options::OPT_funique_internal_linkage_names,
options::OPT_fno_unique_internal_linkage_names, true))
CmdArgs.push_back("-funique-internal-linkage-names");
}
}
RenderBuiltinOptions(TC, RawTriple, Args, CmdArgs);
if (!Args.hasFlag(options::OPT_fassume_sane_operator_new,
options::OPT_fno_assume_sane_operator_new))
CmdArgs.push_back("-fno-assume-sane-operator-new");
// -fblocks=0 is default.
if (Args.hasFlag(options::OPT_fblocks, options::OPT_fno_blocks,
TC.IsBlocksDefault()) ||
(Args.hasArg(options::OPT_fgnu_runtime) &&
Args.hasArg(options::OPT_fobjc_nonfragile_abi) &&
!Args.hasArg(options::OPT_fno_blocks))) {
CmdArgs.push_back("-fblocks");
if (!Args.hasArg(options::OPT_fgnu_runtime) && !TC.hasBlocksRuntime())
CmdArgs.push_back("-fblocks-runtime-optional");
}
// -fencode-extended-block-signature=1 is default.
if (TC.IsEncodeExtendedBlockSignatureDefault())
CmdArgs.push_back("-fencode-extended-block-signature");
if (Args.hasFlag(options::OPT_fcoroutines_ts, options::OPT_fno_coroutines_ts,
false) &&
types::isCXX(InputType)) {
CmdArgs.push_back("-fcoroutines-ts");
}
Args.AddLastArg(CmdArgs, options::OPT_fdouble_square_bracket_attributes,
options::OPT_fno_double_square_bracket_attributes);
// -faccess-control is default.
if (Args.hasFlag(options::OPT_fno_access_control,
options::OPT_faccess_control, false))
CmdArgs.push_back("-fno-access-control");
// -felide-constructors is the default.
if (Args.hasFlag(options::OPT_fno_elide_constructors,
options::OPT_felide_constructors, false))
CmdArgs.push_back("-fno-elide-constructors");
ToolChain::RTTIMode RTTIMode = TC.getRTTIMode();
if (KernelOrKext || (types::isCXX(InputType) &&
(RTTIMode == ToolChain::RM_Disabled)))
CmdArgs.push_back("-fno-rtti");
// -fshort-enums=0 is default for all architectures except Hexagon and z/OS.
if (Args.hasFlag(options::OPT_fshort_enums, options::OPT_fno_short_enums,
TC.getArch() == llvm::Triple::hexagon || Triple.isOSzOS()))
CmdArgs.push_back("-fshort-enums");
RenderCharacterOptions(Args, AuxTriple ? *AuxTriple : RawTriple, CmdArgs);
// -fuse-cxa-atexit is default.
if (!Args.hasFlag(
options::OPT_fuse_cxa_atexit, options::OPT_fno_use_cxa_atexit,
!RawTriple.isOSAIX() && !RawTriple.isOSWindows() &&
TC.getArch() != llvm::Triple::xcore &&
((RawTriple.getVendor() != llvm::Triple::MipsTechnologies) ||
RawTriple.hasEnvironment())) ||
KernelOrKext)
CmdArgs.push_back("-fno-use-cxa-atexit");
if (Args.hasFlag(options::OPT_fregister_global_dtors_with_atexit,
options::OPT_fno_register_global_dtors_with_atexit,
RawTriple.isOSDarwin() && !KernelOrKext))
CmdArgs.push_back("-fregister-global-dtors-with-atexit");
// -fno-use-line-directives is default.
if (Args.hasFlag(options::OPT_fuse_line_directives,
options::OPT_fno_use_line_directives, false))
CmdArgs.push_back("-fuse-line-directives");
// -fno-minimize-whitespace is default.
if (Args.hasFlag(options::OPT_fminimize_whitespace,
options::OPT_fno_minimize_whitespace, false)) {
types::ID InputType = Inputs[0].getType();
if (!isDerivedFromC(InputType))
D.Diag(diag::err_drv_minws_unsupported_input_type)
<< types::getTypeName(InputType);
CmdArgs.push_back("-fminimize-whitespace");
}
// -fms-extensions=0 is default.
if (Args.hasFlag(options::OPT_fms_extensions, options::OPT_fno_ms_extensions,
IsWindowsMSVC))
CmdArgs.push_back("-fms-extensions");
// -fms-compatibility=0 is default.
bool IsMSVCCompat = Args.hasFlag(
options::OPT_fms_compatibility, options::OPT_fno_ms_compatibility,
(IsWindowsMSVC && Args.hasFlag(options::OPT_fms_extensions,
options::OPT_fno_ms_extensions, true)));
if (IsMSVCCompat)
CmdArgs.push_back("-fms-compatibility");
// Handle -fgcc-version, if present.
VersionTuple GNUCVer;
if (Arg *A = Args.getLastArg(options::OPT_fgnuc_version_EQ)) {
// Check that the version has 1 to 3 components and the minor and patch
// versions fit in two decimal digits.
StringRef Val = A->getValue();
Val = Val.empty() ? "0" : Val; // Treat "" as 0 or disable.
bool Invalid = GNUCVer.tryParse(Val);
unsigned Minor = GNUCVer.getMinor().getValueOr(0);
unsigned Patch = GNUCVer.getSubminor().getValueOr(0);
if (Invalid || GNUCVer.getBuild() || Minor >= 100 || Patch >= 100) {
D.Diag(diag::err_drv_invalid_value)
<< A->getAsString(Args) << A->getValue();
}
} else if (!IsMSVCCompat) {
// Imitate GCC 4.2.1 by default if -fms-compatibility is not in effect.
GNUCVer = VersionTuple(4, 2, 1);
}
if (!GNUCVer.empty()) {
CmdArgs.push_back(
Args.MakeArgString("-fgnuc-version=" + GNUCVer.getAsString()));
}
VersionTuple MSVT = TC.computeMSVCVersion(&D, Args);
if (!MSVT.empty())
CmdArgs.push_back(
Args.MakeArgString("-fms-compatibility-version=" + MSVT.getAsString()));
bool IsMSVC2015Compatible = MSVT.getMajor() >= 19;
if (ImplyVCPPCVer) {
StringRef LanguageStandard;
if (const Arg *StdArg = Args.getLastArg(options::OPT__SLASH_std)) {
Std = StdArg;
LanguageStandard = llvm::StringSwitch<StringRef>(StdArg->getValue())
.Case("c11", "-std=c11")
.Case("c17", "-std=c17")
.Default("");
if (LanguageStandard.empty())
D.Diag(clang::diag::warn_drv_unused_argument)
<< StdArg->getAsString(Args);
}
CmdArgs.push_back(LanguageStandard.data());
}
if (ImplyVCPPCXXVer) {
StringRef LanguageStandard;
if (const Arg *StdArg = Args.getLastArg(options::OPT__SLASH_std)) {
Std = StdArg;
LanguageStandard = llvm::StringSwitch<StringRef>(StdArg->getValue())
.Case("c++14", "-std=c++14")
.Case("c++17", "-std=c++17")
.Case("c++20", "-std=c++20")
.Case("c++latest", "-std=c++2b")
.Default("");
if (LanguageStandard.empty())
D.Diag(clang::diag::warn_drv_unused_argument)
<< StdArg->getAsString(Args);
}
if (LanguageStandard.empty()) {
if (IsMSVC2015Compatible)
LanguageStandard = "-std=c++14";
else
LanguageStandard = "-std=c++11";
}
CmdArgs.push_back(LanguageStandard.data());
}
// -fno-borland-extensions is default.
if (Args.hasFlag(options::OPT_fborland_extensions,
options::OPT_fno_borland_extensions, false))
CmdArgs.push_back("-fborland-extensions");
// -fno-declspec is default, except for PS4.
if (Args.hasFlag(options::OPT_fdeclspec, options::OPT_fno_declspec,
RawTriple.isPS4()))
CmdArgs.push_back("-fdeclspec");
else if (Args.hasArg(options::OPT_fno_declspec))
CmdArgs.push_back("-fno-declspec"); // Explicitly disabling __declspec.
// -fthreadsafe-static is default, except for MSVC compatibility versions less
// than 19.
if (!Args.hasFlag(options::OPT_fthreadsafe_statics,
options::OPT_fno_threadsafe_statics,
!types::isOpenCL(InputType) &&
(!IsWindowsMSVC || IsMSVC2015Compatible)))
CmdArgs.push_back("-fno-threadsafe-statics");
// -fno-delayed-template-parsing is default, except when targeting MSVC.
// Many old Windows SDK versions require this to parse.
// FIXME: MSVC introduced /Zc:twoPhase- to disable this behavior in their
// compiler. We should be able to disable this by default at some point.
if (Args.hasFlag(options::OPT_fdelayed_template_parsing,
options::OPT_fno_delayed_template_parsing, IsWindowsMSVC))
CmdArgs.push_back("-fdelayed-template-parsing");
// -fgnu-keywords default varies depending on language; only pass if
// specified.
Args.AddLastArg(CmdArgs, options::OPT_fgnu_keywords,
options::OPT_fno_gnu_keywords);
if (Args.hasFlag(options::OPT_fgnu89_inline, options::OPT_fno_gnu89_inline,
false))
CmdArgs.push_back("-fgnu89-inline");
if (Args.hasArg(options::OPT_fno_inline))
CmdArgs.push_back("-fno-inline");
Args.AddLastArg(CmdArgs, options::OPT_finline_functions,
options::OPT_finline_hint_functions,
options::OPT_fno_inline_functions);
// FIXME: Find a better way to determine whether the language has modules
// support by default, or just assume that all languages do.
bool HaveModules =
Std && (Std->containsValue("c++2a") || Std->containsValue("c++20") ||
Std->containsValue("c++latest"));
RenderModulesOptions(C, D, Args, Input, Output, CmdArgs, HaveModules);
if (Args.hasFlag(options::OPT_fpch_validate_input_files_content,
options::OPT_fno_pch_validate_input_files_content, false))
CmdArgs.push_back("-fvalidate-ast-input-files-content");
if (Args.hasFlag(options::OPT_fpch_instantiate_templates,
options::OPT_fno_pch_instantiate_templates, false))
CmdArgs.push_back("-fpch-instantiate-templates");
if (Args.hasFlag(options::OPT_fpch_codegen, options::OPT_fno_pch_codegen,
false))
CmdArgs.push_back("-fmodules-codegen");
if (Args.hasFlag(options::OPT_fpch_debuginfo, options::OPT_fno_pch_debuginfo,
false))
CmdArgs.push_back("-fmodules-debuginfo");
Args.AddLastArg(CmdArgs, options::OPT_flegacy_pass_manager,
options::OPT_fno_legacy_pass_manager);
ObjCRuntime Runtime = AddObjCRuntimeArgs(Args, Inputs, CmdArgs, rewriteKind);
RenderObjCOptions(TC, D, RawTriple, Args, Runtime, rewriteKind != RK_None,
Input, CmdArgs);
if (types::isObjC(Input.getType()) &&
Args.hasFlag(options::OPT_fobjc_encode_cxx_class_template_spec,
options::OPT_fno_objc_encode_cxx_class_template_spec,
!Runtime.isNeXTFamily()))
CmdArgs.push_back("-fobjc-encode-cxx-class-template-spec");
if (Args.hasFlag(options::OPT_fapplication_extension,
options::OPT_fno_application_extension, false))
CmdArgs.push_back("-fapplication-extension");
// Handle GCC-style exception args.
bool EH = false;
if (!C.getDriver().IsCLMode())
EH = addExceptionArgs(Args, InputType, TC, KernelOrKext, Runtime, CmdArgs);
// Handle exception personalities
Arg *A = Args.getLastArg(
options::OPT_fsjlj_exceptions, options::OPT_fseh_exceptions,
options::OPT_fdwarf_exceptions, options::OPT_fwasm_exceptions);
if (A) {
const Option &Opt = A->getOption();
if (Opt.matches(options::OPT_fsjlj_exceptions))
CmdArgs.push_back("-exception-model=sjlj");
if (Opt.matches(options::OPT_fseh_exceptions))
CmdArgs.push_back("-exception-model=seh");
if (Opt.matches(options::OPT_fdwarf_exceptions))
CmdArgs.push_back("-exception-model=dwarf");
if (Opt.matches(options::OPT_fwasm_exceptions))
CmdArgs.push_back("-exception-model=wasm");
} else {
switch (TC.GetExceptionModel(Args)) {
default:
break;
case llvm::ExceptionHandling::DwarfCFI:
CmdArgs.push_back("-exception-model=dwarf");
break;
case llvm::ExceptionHandling::SjLj:
CmdArgs.push_back("-exception-model=sjlj");
break;
case llvm::ExceptionHandling::WinEH:
CmdArgs.push_back("-exception-model=seh");
break;
}
}
// C++ "sane" operator new.
if (!Args.hasFlag(options::OPT_fassume_sane_operator_new,
options::OPT_fno_assume_sane_operator_new))
CmdArgs.push_back("-fno-assume-sane-operator-new");
// -frelaxed-template-template-args is off by default, as it is a severe
// breaking change until a corresponding change to template partial ordering
// is provided.
if (Args.hasFlag(options::OPT_frelaxed_template_template_args,
options::OPT_fno_relaxed_template_template_args, false))
CmdArgs.push_back("-frelaxed-template-template-args");
// -fsized-deallocation is off by default, as it is an ABI-breaking change for
// most platforms.
if (Args.hasFlag(options::OPT_fsized_deallocation,
options::OPT_fno_sized_deallocation, false))
CmdArgs.push_back("-fsized-deallocation");
// -faligned-allocation is on by default in C++17 onwards and otherwise off
// by default.
if (Arg *A = Args.getLastArg(options::OPT_faligned_allocation,
options::OPT_fno_aligned_allocation,
options::OPT_faligned_new_EQ)) {
if (A->getOption().matches(options::OPT_fno_aligned_allocation))
CmdArgs.push_back("-fno-aligned-allocation");
else
CmdArgs.push_back("-faligned-allocation");
}
// The default new alignment can be specified using a dedicated option or via
// a GCC-compatible option that also turns on aligned allocation.
if (Arg *A = Args.getLastArg(options::OPT_fnew_alignment_EQ,
options::OPT_faligned_new_EQ))
CmdArgs.push_back(
Args.MakeArgString(Twine("-fnew-alignment=") + A->getValue()));
// -fconstant-cfstrings is default, and may be subject to argument translation
// on Darwin.
if (!Args.hasFlag(options::OPT_fconstant_cfstrings,
options::OPT_fno_constant_cfstrings) ||
!Args.hasFlag(options::OPT_mconstant_cfstrings,
options::OPT_mno_constant_cfstrings))
CmdArgs.push_back("-fno-constant-cfstrings");
// -fno-pascal-strings is default, only pass non-default.
if (Args.hasFlag(options::OPT_fpascal_strings,
options::OPT_fno_pascal_strings, false))
CmdArgs.push_back("-fpascal-strings");
// Honor -fpack-struct= and -fpack-struct, if given. Note that
// -fno-pack-struct doesn't apply to -fpack-struct=.
if (Arg *A = Args.getLastArg(options::OPT_fpack_struct_EQ)) {
std::string PackStructStr = "-fpack-struct=";
PackStructStr += A->getValue();
CmdArgs.push_back(Args.MakeArgString(PackStructStr));
} else if (Args.hasFlag(options::OPT_fpack_struct,
options::OPT_fno_pack_struct, false)) {
CmdArgs.push_back("-fpack-struct=1");
}
// Handle -fmax-type-align=N and -fno-type-align
bool SkipMaxTypeAlign = Args.hasArg(options::OPT_fno_max_type_align);
if (Arg *A = Args.getLastArg(options::OPT_fmax_type_align_EQ)) {
if (!SkipMaxTypeAlign) {
std::string MaxTypeAlignStr = "-fmax-type-align=";
MaxTypeAlignStr += A->getValue();
CmdArgs.push_back(Args.MakeArgString(MaxTypeAlignStr));
}
} else if (RawTriple.isOSDarwin()) {
if (!SkipMaxTypeAlign) {
std::string MaxTypeAlignStr = "-fmax-type-align=16";
CmdArgs.push_back(Args.MakeArgString(MaxTypeAlignStr));
}
}
if (!Args.hasFlag(options::OPT_Qy, options::OPT_Qn, true))
CmdArgs.push_back("-Qn");
// -fno-common is the default, set -fcommon only when that flag is set.
if (Args.hasFlag(options::OPT_fcommon, options::OPT_fno_common, false))
CmdArgs.push_back("-fcommon");
// -fsigned-bitfields is default, and clang doesn't yet support
// -funsigned-bitfields.
if (!Args.hasFlag(options::OPT_fsigned_bitfields,
options::OPT_funsigned_bitfields))
D.Diag(diag::warn_drv_clang_unsupported)
<< Args.getLastArg(options::OPT_funsigned_bitfields)->getAsString(Args);
// -fsigned-bitfields is default, and clang doesn't support -fno-for-scope.
if (!Args.hasFlag(options::OPT_ffor_scope, options::OPT_fno_for_scope))
D.Diag(diag::err_drv_clang_unsupported)
<< Args.getLastArg(options::OPT_fno_for_scope)->getAsString(Args);
// -finput_charset=UTF-8 is default. Reject others
if (Arg *inputCharset = Args.getLastArg(options::OPT_finput_charset_EQ)) {
StringRef value = inputCharset->getValue();
if (!value.equals_insensitive("utf-8"))
D.Diag(diag::err_drv_invalid_value) << inputCharset->getAsString(Args)
<< value;
}
// -fexec_charset=UTF-8 is default. Reject others
if (Arg *execCharset = Args.getLastArg(options::OPT_fexec_charset_EQ)) {
StringRef value = execCharset->getValue();
if (!value.equals_insensitive("utf-8"))
D.Diag(diag::err_drv_invalid_value) << execCharset->getAsString(Args)
<< value;
}
RenderDiagnosticsOptions(D, Args, CmdArgs);
// -fno-asm-blocks is default.
if (Args.hasFlag(options::OPT_fasm_blocks, options::OPT_fno_asm_blocks,
false))
CmdArgs.push_back("-fasm-blocks");
// -fgnu-inline-asm is default.
if (!Args.hasFlag(options::OPT_fgnu_inline_asm,
options::OPT_fno_gnu_inline_asm, true))
CmdArgs.push_back("-fno-gnu-inline-asm");
// Enable vectorization per default according to the optimization level
// selected. For optimization levels that want vectorization we use the alias
// option to simplify the hasFlag logic.
bool EnableVec = shouldEnableVectorizerAtOLevel(Args, false);
OptSpecifier VectorizeAliasOption =
EnableVec ? options::OPT_O_Group : options::OPT_fvectorize;
if (Args.hasFlag(options::OPT_fvectorize, VectorizeAliasOption,
options::OPT_fno_vectorize, EnableVec))
CmdArgs.push_back("-vectorize-loops");
// -fslp-vectorize is enabled based on the optimization level selected.
bool EnableSLPVec = shouldEnableVectorizerAtOLevel(Args, true);
OptSpecifier SLPVectAliasOption =
EnableSLPVec ? options::OPT_O_Group : options::OPT_fslp_vectorize;
if (Args.hasFlag(options::OPT_fslp_vectorize, SLPVectAliasOption,
options::OPT_fno_slp_vectorize, EnableSLPVec))
CmdArgs.push_back("-vectorize-slp");
ParseMPreferVectorWidth(D, Args, CmdArgs);
Args.AddLastArg(CmdArgs, options::OPT_fshow_overloads_EQ);
Args.AddLastArg(CmdArgs,
options::OPT_fsanitize_undefined_strip_path_components_EQ);
// -fdollars-in-identifiers default varies depending on platform and
// language; only pass if specified.
if (Arg *A = Args.getLastArg(options::OPT_fdollars_in_identifiers,
options::OPT_fno_dollars_in_identifiers)) {
if (A->getOption().matches(options::OPT_fdollars_in_identifiers))
CmdArgs.push_back("-fdollars-in-identifiers");
else
CmdArgs.push_back("-fno-dollars-in-identifiers");
}
// -funit-at-a-time is default, and we don't support -fno-unit-at-a-time for
// practical purposes.
if (Arg *A = Args.getLastArg(options::OPT_funit_at_a_time,
options::OPT_fno_unit_at_a_time)) {
if (A->getOption().matches(options::OPT_fno_unit_at_a_time))
D.Diag(diag::warn_drv_clang_unsupported) << A->getAsString(Args);
}
if (Args.hasFlag(options::OPT_fapple_pragma_pack,
options::OPT_fno_apple_pragma_pack, false))
CmdArgs.push_back("-fapple-pragma-pack");
if (Args.hasFlag(options::OPT_fxl_pragma_pack,
options::OPT_fno_xl_pragma_pack, RawTriple.isOSAIX()))
CmdArgs.push_back("-fxl-pragma-pack");
// Remarks can be enabled with any of the `-f.*optimization-record.*` flags.
if (willEmitRemarks(Args) && checkRemarksOptions(D, Args, Triple))
renderRemarksOptions(Args, CmdArgs, Triple, Input, Output, JA);
bool RewriteImports = Args.hasFlag(options::OPT_frewrite_imports,
options::OPT_fno_rewrite_imports, false);
if (RewriteImports)
CmdArgs.push_back("-frewrite-imports");
// Enable rewrite includes if the user's asked for it or if we're generating
// diagnostics.
// TODO: Once -module-dependency-dir works with -frewrite-includes it'd be
// nice to enable this when doing a crashdump for modules as well.
if (Args.hasFlag(options::OPT_frewrite_includes,
options::OPT_fno_rewrite_includes, false) ||
(C.isForDiagnostics() && !HaveModules))
CmdArgs.push_back("-frewrite-includes");
// Only allow -traditional or -traditional-cpp outside in preprocessing modes.
if (Arg *A = Args.getLastArg(options::OPT_traditional,
options::OPT_traditional_cpp)) {
if (isa<PreprocessJobAction>(JA))
CmdArgs.push_back("-traditional-cpp");
else
D.Diag(diag::err_drv_clang_unsupported) << A->getAsString(Args);
}
Args.AddLastArg(CmdArgs, options::OPT_dM);
Args.AddLastArg(CmdArgs, options::OPT_dD);
Args.AddLastArg(CmdArgs, options::OPT_fmax_tokens_EQ);
// Handle serialized diagnostics.
if (Arg *A = Args.getLastArg(options::OPT__serialize_diags)) {
CmdArgs.push_back("-serialize-diagnostic-file");
CmdArgs.push_back(Args.MakeArgString(A->getValue()));
}
if (Args.hasArg(options::OPT_fretain_comments_from_system_headers))
CmdArgs.push_back("-fretain-comments-from-system-headers");
// Forward -fcomment-block-commands to -cc1.
Args.AddAllArgs(CmdArgs, options::OPT_fcomment_block_commands);
// Forward -fparse-all-comments to -cc1.
Args.AddAllArgs(CmdArgs, options::OPT_fparse_all_comments);
// Turn -fplugin=name.so into -load name.so
for (const Arg *A : Args.filtered(options::OPT_fplugin_EQ)) {
CmdArgs.push_back("-load");
CmdArgs.push_back(A->getValue());
A->claim();
}
// Turn -fplugin-arg-pluginname-key=value into
// -plugin-arg-pluginname key=value
// GCC has an actual plugin_argument struct with key/value pairs that it
// passes to its plugins, but we don't, so just pass it on as-is.
//
// The syntax for -fplugin-arg- is ambiguous if both plugin name and
// argument key are allowed to contain dashes. GCC therefore only
// allows dashes in the key. We do the same.
for (const Arg *A : Args.filtered(options::OPT_fplugin_arg)) {
auto ArgValue = StringRef(A->getValue());
auto FirstDashIndex = ArgValue.find('-');
StringRef PluginName = ArgValue.substr(0, FirstDashIndex);
StringRef Arg = ArgValue.substr(FirstDashIndex + 1);
A->claim();
if (FirstDashIndex == StringRef::npos || Arg.empty()) {
if (PluginName.empty()) {
D.Diag(diag::warn_drv_missing_plugin_name) << A->getAsString(Args);
} else {
D.Diag(diag::warn_drv_missing_plugin_arg)
<< PluginName << A->getAsString(Args);
}
continue;
}
CmdArgs.push_back(Args.MakeArgString(Twine("-plugin-arg-") + PluginName));
CmdArgs.push_back(Args.MakeArgString(Arg));
}
// Forward -fpass-plugin=name.so to -cc1.
for (const Arg *A : Args.filtered(options::OPT_fpass_plugin_EQ)) {
CmdArgs.push_back(
Args.MakeArgString(Twine("-fpass-plugin=") + A->getValue()));
A->claim();
}
// Setup statistics file output.
SmallString<128> StatsFile = getStatsFileName(Args, Output, Input, D);
if (!StatsFile.empty())
CmdArgs.push_back(Args.MakeArgString(Twine("-stats-file=") + StatsFile));
// Forward -Xclang arguments to -cc1, and -mllvm arguments to the LLVM option
// parser.
// -finclude-default-header flag is for preprocessor,
// do not pass it to other cc1 commands when save-temps is enabled
if (C.getDriver().isSaveTempsEnabled() &&
!isa<PreprocessJobAction>(JA)) {
for (auto Arg : Args.filtered(options::OPT_Xclang)) {
Arg->claim();
if (StringRef(Arg->getValue()) != "-finclude-default-header")
CmdArgs.push_back(Arg->getValue());
}
}
else {
Args.AddAllArgValues(CmdArgs, options::OPT_Xclang);
}
for (const Arg *A : Args.filtered(options::OPT_mllvm)) {
A->claim();
// We translate this by hand to the -cc1 argument, since nightly test uses
// it and developers have been trained to spell it with -mllvm. Both
// spellings are now deprecated and should be removed.
if (StringRef(A->getValue(0)) == "-disable-llvm-optzns") {
CmdArgs.push_back("-disable-llvm-optzns");
} else {
A->render(Args, CmdArgs);
}
}
// With -save-temps, we want to save the unoptimized bitcode output from the
// CompileJobAction, use -disable-llvm-passes to get pristine IR generated
// by the frontend.
// When -fembed-bitcode is enabled, optimized bitcode is emitted because it
// has slightly different breakdown between stages.
// FIXME: -fembed-bitcode -save-temps will save optimized bitcode instead of
// pristine IR generated by the frontend. Ideally, a new compile action should
// be added so both IR can be captured.
if ((C.getDriver().isSaveTempsEnabled() ||
JA.isHostOffloading(Action::OFK_OpenMP)) &&
!(C.getDriver().embedBitcodeInObject() && !IsUsingLTO) &&
isa<CompileJobAction>(JA))
CmdArgs.push_back("-disable-llvm-passes");
Args.AddAllArgs(CmdArgs, options::OPT_undef);
const char *Exec = D.getClangProgramPath();
// 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.
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);
SmallString<256> Flags;
EscapeSpacesAndBackslashes(Exec, Flags);
for (const char *OriginalArg : OriginalArgs) {
SmallString<128> EscapedArg;
EscapeSpacesAndBackslashes(OriginalArg, EscapedArg);
Flags += " ";
Flags += EscapedArg;
}
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
// fatbin as Inputs[1]. Include the binary with -fcuda-include-gpubinary.
if ((IsCuda || IsHIP) && CudaDeviceInput) {
CmdArgs.push_back("-fcuda-include-gpubinary");
CmdArgs.push_back(CudaDeviceInput->getFilename());
if (Args.hasFlag(options::OPT_fgpu_rdc, options::OPT_fno_gpu_rdc, false))
CmdArgs.push_back("-fgpu-rdc");
}
if (IsCuda) {
if (Args.hasFlag(options::OPT_fcuda_short_ptr,
options::OPT_fno_cuda_short_ptr, false))
CmdArgs.push_back("-fcuda-short-ptr");
}
if (IsCuda || IsHIP) {
// Determine the original source input.
const Action *SourceAction = &JA;
while (SourceAction->getKind() != Action::InputClass) {
assert(!SourceAction->getInputs().empty() && "unexpected root action!");
SourceAction = SourceAction->getInputs()[0];
}
auto CUID = cast<InputAction>(SourceAction)->getId();
if (!CUID.empty())
CmdArgs.push_back(Args.MakeArgString(Twine("-cuid=") + Twine(CUID)));
}
if (IsHIP)
CmdArgs.push_back("-fcuda-allow-variadic-functions");
if (IsCudaDevice || IsHIPDevice) {
StringRef InlineThresh =
Args.getLastArgValue(options::OPT_fgpu_inline_threshold_EQ);
if (!InlineThresh.empty()) {
std::string ArgStr =
std::string("-inline-threshold=") + InlineThresh.str();
CmdArgs.append({"-mllvm", Args.MakeArgStringRef(ArgStr)});
}
}
// OpenMP offloading device jobs take the argument -fopenmp-host-ir-file-path
// to specify the result of the compile phase on the host, so the meaningful
// device declarations can be identified. Also, -fopenmp-is-device is passed
// along to tell the frontend that it is generating code for a device, so that
// only the relevant declarations are emitted.
if (IsOpenMPDevice) {
CmdArgs.push_back("-fopenmp-is-device");
if (OpenMPDeviceInput) {
CmdArgs.push_back("-fopenmp-host-ir-file-path");
CmdArgs.push_back(Args.MakeArgString(OpenMPDeviceInput->getFilename()));
}
}
if (Triple.isAMDGPU()) {
handleAMDGPUCodeObjectVersionOptions(D, Args, CmdArgs);
if (Args.hasFlag(options::OPT_munsafe_fp_atomics,
options::OPT_mno_unsafe_fp_atomics, /*Default=*/false))
CmdArgs.push_back("-munsafe-fp-atomics");
}
// For all the host OpenMP offloading compile jobs we need to pass the targets
// information using -fopenmp-targets= option.
if (JA.isHostOffloading(Action::OFK_OpenMP)) {
SmallString<128> TargetInfo("-fopenmp-targets=");
Arg *Tgts = Args.getLastArg(options::OPT_fopenmp_targets_EQ);
assert(Tgts && Tgts->getNumValues() &&
"OpenMP offloading has to have targets specified.");
for (unsigned i = 0; i < Tgts->getNumValues(); ++i) {
if (i)
TargetInfo += ',';
// We need to get the string from the triple because it may be not exactly
// the same as the one we get directly from the arguments.
llvm::Triple T(Tgts->getValue(i));
TargetInfo += T.getTriple();
}
CmdArgs.push_back(Args.MakeArgString(TargetInfo.str()));
}
bool VirtualFunctionElimination =
Args.hasFlag(options::OPT_fvirtual_function_elimination,
options::OPT_fno_virtual_function_elimination, false);
if (VirtualFunctionElimination) {
// VFE requires full LTO (currently, this might be relaxed to allow ThinLTO
// in the future).
if (LTOMode != LTOK_Full)
D.Diag(diag::err_drv_argument_only_allowed_with)
<< "-fvirtual-function-elimination"
<< "-flto=full";
CmdArgs.push_back("-fvirtual-function-elimination");
}
// VFE requires whole-program-vtables, and enables it by default.
bool WholeProgramVTables = Args.hasFlag(
options::OPT_fwhole_program_vtables,
options::OPT_fno_whole_program_vtables, VirtualFunctionElimination);
if (VirtualFunctionElimination && !WholeProgramVTables) {
D.Diag(diag::err_drv_argument_not_allowed_with)
<< "-fno-whole-program-vtables"
<< "-fvirtual-function-elimination";
}
if (WholeProgramVTables) {
// Propagate -fwhole-program-vtables if this is an LTO compile.
if (IsUsingLTO)
CmdArgs.push_back("-fwhole-program-vtables");
// Check if we passed LTO options but they were suppressed because this is a
// device offloading action, or we passed device offload LTO options which
// were suppressed because this is not the device offload action.
// Otherwise, issue an error.
else if (!D.isUsingLTO(!IsDeviceOffloadAction))
D.Diag(diag::err_drv_argument_only_allowed_with)
<< "-fwhole-program-vtables"
<< "-flto";
}
bool DefaultsSplitLTOUnit =
(WholeProgramVTables || SanitizeArgs.needsLTO()) &&
(LTOMode == LTOK_Full || TC.canSplitThinLTOUnit());
bool SplitLTOUnit =
Args.hasFlag(options::OPT_fsplit_lto_unit,
options::OPT_fno_split_lto_unit, DefaultsSplitLTOUnit);
if (SanitizeArgs.needsLTO() && !SplitLTOUnit)
D.Diag(diag::err_drv_argument_not_allowed_with) << "-fno-split-lto-unit"
<< "-fsanitize=cfi";
if (SplitLTOUnit)
CmdArgs.push_back("-fsplit-lto-unit");
if (Arg *A = Args.getLastArg(options::OPT_fglobal_isel,
options::OPT_fno_global_isel)) {
CmdArgs.push_back("-mllvm");
if (A->getOption().matches(options::OPT_fglobal_isel)) {
CmdArgs.push_back("-global-isel=1");
// GISel is on by default on AArch64 -O0, so don't bother adding
// the fallback remarks for it. Other combinations will add a warning of
// some kind.
bool IsArchSupported = Triple.getArch() == llvm::Triple::aarch64;
bool IsOptLevelSupported = false;
Arg *A = Args.getLastArg(options::OPT_O_Group);
if (Triple.getArch() == llvm::Triple::aarch64) {
if (!A || A->getOption().matches(options::OPT_O0))
IsOptLevelSupported = true;
}
if (!IsArchSupported || !IsOptLevelSupported) {
CmdArgs.push_back("-mllvm");
CmdArgs.push_back("-global-isel-abort=2");
if (!IsArchSupported)
D.Diag(diag::warn_drv_global_isel_incomplete) << Triple.getArchName();
else
D.Diag(diag::warn_drv_global_isel_incomplete_opt);
}
} else {
CmdArgs.push_back("-global-isel=0");
}
}
if (Args.hasArg(options::OPT_forder_file_instrumentation)) {
CmdArgs.push_back("-forder-file-instrumentation");
// Enable order file instrumentation when ThinLTO is not on. When ThinLTO is
// on, we need to pass these flags as linker flags and that will be handled
// outside of the compiler.
if (!IsUsingLTO) {
CmdArgs.push_back("-mllvm");
CmdArgs.push_back("-enable-order-file-instrumentation");
}
}
if (Arg *A = Args.getLastArg(options::OPT_fforce_enable_int128,
options::OPT_fno_force_enable_int128)) {
if (A->getOption().matches(options::OPT_fforce_enable_int128))
CmdArgs.push_back("-fforce-enable-int128");
}
if (Args.hasFlag(options::OPT_fkeep_static_consts,
options::OPT_fno_keep_static_consts, false))
CmdArgs.push_back("-fkeep-static-consts");
if (Args.hasFlag(options::OPT_fcomplete_member_pointers,
options::OPT_fno_complete_member_pointers, false))
CmdArgs.push_back("-fcomplete-member-pointers");
if (!Args.hasFlag(options::OPT_fcxx_static_destructors,
options::OPT_fno_cxx_static_destructors, true))
CmdArgs.push_back("-fno-c++-static-destructors");
addMachineOutlinerArgs(D, Args, CmdArgs, Triple, /*IsLTO=*/false);
if (Arg *A = Args.getLastArg(options::OPT_moutline_atomics,
options::OPT_mno_outline_atomics)) {
// Option -moutline-atomics supported for AArch64 target only.
if (!Triple.isAArch64()) {
D.Diag(diag::warn_drv_moutline_atomics_unsupported_opt)
<< Triple.getArchName() << A->getOption().getName();
} else {
if (A->getOption().matches(options::OPT_moutline_atomics)) {
CmdArgs.push_back("-target-feature");
CmdArgs.push_back("+outline-atomics");
} else {
CmdArgs.push_back("-target-feature");
CmdArgs.push_back("-outline-atomics");
}
}
} else if (Triple.isAArch64() &&
getToolChain().IsAArch64OutlineAtomicsDefault(Args)) {
CmdArgs.push_back("-target-feature");
CmdArgs.push_back("+outline-atomics");
}
if (Args.hasFlag(options::OPT_faddrsig, options::OPT_fno_addrsig,
(TC.getTriple().isOSBinFormatELF() ||
TC.getTriple().isOSBinFormatCOFF()) &&
!TC.getTriple().isPS4() && !TC.getTriple().isVE() &&
!TC.getTriple().isOSNetBSD() &&
!Distro(D.getVFS(), TC.getTriple()).IsGentoo() &&
!TC.getTriple().isAndroid() && TC.useIntegratedAs()))
CmdArgs.push_back("-faddrsig");
if ((Triple.isOSBinFormatELF() || Triple.isOSBinFormatMachO()) &&
(EH || AsyncUnwindTables || UnwindTables ||
DebugInfoKind != codegenoptions::NoDebugInfo))
CmdArgs.push_back("-D__GCC_HAVE_DWARF2_CFI_ASM=1");
if (Arg *A = Args.getLastArg(options::OPT_fsymbol_partition_EQ)) {
std::string Str = A->getAsString(Args);
if (!TC.getTriple().isOSBinFormatELF())
D.Diag(diag::err_drv_unsupported_opt_for_target)
<< Str << TC.getTripleString();
CmdArgs.push_back(Args.MakeArgString(Str));
}
// Add the output path to the object file for CodeView debug infos.
if (EmitCodeView && Output.isFilename())
addDebugObjectName(Args, CmdArgs, DebugCompilationDir,
Output.getFilename());
// Add the "-o out -x type src.c" flags last. This is done primarily to make
// the -cc1 command easier to edit when reproducing compiler crashes.
if (Output.getType() == types::TY_Dependencies) {
// Handled with other dependency code.
} else if (Output.isFilename()) {
if (Output.getType() == clang::driver::types::TY_IFS_CPP ||
Output.getType() == clang::driver::types::TY_IFS) {
SmallString<128> OutputFilename(Output.getFilename());
llvm::sys::path::replace_extension(OutputFilename, "ifs");
CmdArgs.push_back("-o");
CmdArgs.push_back(Args.MakeArgString(OutputFilename));
} else {
CmdArgs.push_back("-o");
CmdArgs.push_back(Output.getFilename());
}
} else {
assert(Output.isNothing() && "Invalid output.");
}
addDashXForInput(Args, Input, CmdArgs);
ArrayRef<InputInfo> FrontendInputs = Input;
if (IsHeaderModulePrecompile)
FrontendInputs = ModuleHeaderInputs;
else if (Input.isNothing())
FrontendInputs = {};
for (const InputInfo &Input : FrontendInputs) {
if (Input.isFilename())
CmdArgs.push_back(Input.getFilename());
else
Input.getInputArg().renderAsInput(Args, CmdArgs);
}
if (D.CC1Main && !D.CCGenDiagnostics) {
// Invoke the CC1 directly in this process
C.addCommand(std::make_unique<CC1Command>(JA, *this,
ResponseFileSupport::AtFileUTF8(),
Exec, CmdArgs, Inputs, Output));
} else {
C.addCommand(std::make_unique<Command>(JA, *this,
ResponseFileSupport::AtFileUTF8(),
Exec, CmdArgs, Inputs, Output));
}
// Make the compile command echo its inputs for /showFilenames.
if (Output.getType() == types::TY_Object &&
Args.hasFlag(options::OPT__SLASH_showFilenames,
options::OPT__SLASH_showFilenames_, false)) {
C.getJobs().getJobs().back()->PrintInputFilenames = true;
}
if (Arg *A = Args.getLastArg(options::OPT_pg))
if (FPKeepKind == CodeGenOptions::FramePointerKind::None &&
!Args.hasArg(options::OPT_mfentry))
D.Diag(diag::err_drv_argument_not_allowed_with) << "-fomit-frame-pointer"
<< A->getAsString(Args);
// Claim some arguments which clang supports automatically.
// -fpch-preprocess is used with gcc to add a special marker in the output to
// include the PCH file.
Args.ClaimAllArgs(options::OPT_fpch_preprocess);
// Claim some arguments which clang doesn't support, but we don't
// care to warn the user about.
Args.ClaimAllArgs(options::OPT_clang_ignored_f_Group);
Args.ClaimAllArgs(options::OPT_clang_ignored_m_Group);
// Disable warnings for clang -E -emit-llvm foo.c
Args.ClaimAllArgs(options::OPT_emit_llvm);
}