Path: blob/main/contrib/llvm-project/clang/lib/Driver/ToolChains/Flang.cpp
35269 views
//===-- Flang.cpp - Flang+LLVM ToolChain Implementations --------*- C++ -*-===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "Flang.h"9#include "Arch/RISCV.h"10#include "CommonArgs.h"1112#include "clang/Basic/CodeGenOptions.h"13#include "clang/Driver/Options.h"14#include "llvm/Frontend/Debug/Options.h"15#include "llvm/Support/FileSystem.h"16#include "llvm/Support/Path.h"17#include "llvm/TargetParser/Host.h"18#include "llvm/TargetParser/RISCVISAInfo.h"19#include "llvm/TargetParser/RISCVTargetParser.h"2021#include <cassert>2223using namespace clang::driver;24using namespace clang::driver::tools;25using namespace clang;26using namespace llvm::opt;2728/// Add -x lang to \p CmdArgs for \p Input.29static void addDashXForInput(const ArgList &Args, const InputInfo &Input,30ArgStringList &CmdArgs) {31CmdArgs.push_back("-x");32// Map the driver type to the frontend type.33CmdArgs.push_back(types::getTypeName(Input.getType()));34}3536void Flang::addFortranDialectOptions(const ArgList &Args,37ArgStringList &CmdArgs) const {38Args.addAllArgs(CmdArgs, {options::OPT_ffixed_form,39options::OPT_ffree_form,40options::OPT_ffixed_line_length_EQ,41options::OPT_fopenacc,42options::OPT_finput_charset_EQ,43options::OPT_fimplicit_none,44options::OPT_fno_implicit_none,45options::OPT_fbackslash,46options::OPT_fno_backslash,47options::OPT_flogical_abbreviations,48options::OPT_fno_logical_abbreviations,49options::OPT_fxor_operator,50options::OPT_fno_xor_operator,51options::OPT_falternative_parameter_statement,52options::OPT_fdefault_real_8,53options::OPT_fdefault_integer_8,54options::OPT_fdefault_double_8,55options::OPT_flarge_sizes,56options::OPT_fno_automatic,57options::OPT_fhermetic_module_files});58}5960void Flang::addPreprocessingOptions(const ArgList &Args,61ArgStringList &CmdArgs) const {62Args.addAllArgs(CmdArgs,63{options::OPT_P, options::OPT_D, options::OPT_U,64options::OPT_I, options::OPT_cpp, options::OPT_nocpp});65}6667/// @C shouldLoopVersion68///69/// Check if Loop Versioning should be enabled.70/// We look for the last of one of the following:71/// -Ofast, -O4, -O<number> and -f[no-]version-loops-for-stride.72/// Loop versioning is disabled if the last option is73/// -fno-version-loops-for-stride.74/// Loop versioning is enabled if the last option is one of:75/// -floop-versioning76/// -Ofast77/// -O478/// -O379/// For all other cases, loop versioning is is disabled.80///81/// The gfortran compiler automatically enables the option for -O3 or -Ofast.82///83/// @return true if loop-versioning should be enabled, otherwise false.84static bool shouldLoopVersion(const ArgList &Args) {85const Arg *LoopVersioningArg = Args.getLastArg(86options::OPT_Ofast, options::OPT_O, options::OPT_O4,87options::OPT_floop_versioning, options::OPT_fno_loop_versioning);88if (!LoopVersioningArg)89return false;9091if (LoopVersioningArg->getOption().matches(options::OPT_fno_loop_versioning))92return false;9394if (LoopVersioningArg->getOption().matches(options::OPT_floop_versioning))95return true;9697if (LoopVersioningArg->getOption().matches(options::OPT_Ofast) ||98LoopVersioningArg->getOption().matches(options::OPT_O4))99return true;100101if (LoopVersioningArg->getOption().matches(options::OPT_O)) {102StringRef S(LoopVersioningArg->getValue());103unsigned OptLevel = 0;104// Note -Os or Oz woould "fail" here, so return false. Which is the105// desiered behavior.106if (S.getAsInteger(10, OptLevel))107return false;108109return OptLevel > 2;110}111112llvm_unreachable("We should not end up here");113return false;114}115116void Flang::addOtherOptions(const ArgList &Args, ArgStringList &CmdArgs) const {117Args.addAllArgs(CmdArgs,118{options::OPT_module_dir, options::OPT_fdebug_module_writer,119options::OPT_fintrinsic_modules_path, options::OPT_pedantic,120options::OPT_std_EQ, options::OPT_W_Joined,121options::OPT_fconvert_EQ, options::OPT_fpass_plugin_EQ,122options::OPT_funderscoring, options::OPT_fno_underscoring});123124llvm::codegenoptions::DebugInfoKind DebugInfoKind;125if (Args.hasArg(options::OPT_gN_Group)) {126Arg *gNArg = Args.getLastArg(options::OPT_gN_Group);127DebugInfoKind = debugLevelToInfoKind(*gNArg);128} else if (Args.hasArg(options::OPT_g_Flag)) {129DebugInfoKind = llvm::codegenoptions::FullDebugInfo;130} else {131DebugInfoKind = llvm::codegenoptions::NoDebugInfo;132}133addDebugInfoKind(CmdArgs, DebugInfoKind);134}135136void Flang::addCodegenOptions(const ArgList &Args,137ArgStringList &CmdArgs) const {138Arg *stackArrays =139Args.getLastArg(options::OPT_Ofast, options::OPT_fstack_arrays,140options::OPT_fno_stack_arrays);141if (stackArrays &&142!stackArrays->getOption().matches(options::OPT_fno_stack_arrays))143CmdArgs.push_back("-fstack-arrays");144145if (shouldLoopVersion(Args))146CmdArgs.push_back("-fversion-loops-for-stride");147148Args.addAllArgs(CmdArgs, {options::OPT_flang_experimental_hlfir,149options::OPT_flang_deprecated_no_hlfir,150options::OPT_flang_experimental_integer_overflow,151options::OPT_fno_ppc_native_vec_elem_order,152options::OPT_fppc_native_vec_elem_order});153}154155void Flang::addPicOptions(const ArgList &Args, ArgStringList &CmdArgs) const {156// ParsePICArgs parses -fPIC/-fPIE and their variants and returns a tuple of157// (RelocationModel, PICLevel, IsPIE).158llvm::Reloc::Model RelocationModel;159unsigned PICLevel;160bool IsPIE;161std::tie(RelocationModel, PICLevel, IsPIE) =162ParsePICArgs(getToolChain(), Args);163164if (auto *RMName = RelocationModelName(RelocationModel)) {165CmdArgs.push_back("-mrelocation-model");166CmdArgs.push_back(RMName);167}168if (PICLevel > 0) {169CmdArgs.push_back("-pic-level");170CmdArgs.push_back(PICLevel == 1 ? "1" : "2");171if (IsPIE)172CmdArgs.push_back("-pic-is-pie");173}174}175176void Flang::AddAArch64TargetArgs(const ArgList &Args,177ArgStringList &CmdArgs) const {178// Handle -msve_vector_bits=<bits>179if (Arg *A = Args.getLastArg(options::OPT_msve_vector_bits_EQ)) {180StringRef Val = A->getValue();181const Driver &D = getToolChain().getDriver();182if (Val == "128" || Val == "256" || Val == "512" || Val == "1024" ||183Val == "2048" || Val == "128+" || Val == "256+" || Val == "512+" ||184Val == "1024+" || Val == "2048+") {185unsigned Bits = 0;186if (!Val.consume_back("+")) {187[[maybe_unused]] bool Invalid = Val.getAsInteger(10, Bits);188assert(!Invalid && "Failed to parse value");189CmdArgs.push_back(190Args.MakeArgString("-mvscale-max=" + llvm::Twine(Bits / 128)));191}192193[[maybe_unused]] bool Invalid = Val.getAsInteger(10, Bits);194assert(!Invalid && "Failed to parse value");195CmdArgs.push_back(196Args.MakeArgString("-mvscale-min=" + llvm::Twine(Bits / 128)));197// Silently drop requests for vector-length agnostic code as it's implied.198} else if (Val != "scalable")199// Handle the unsupported values passed to msve-vector-bits.200D.Diag(diag::err_drv_unsupported_option_argument)201<< A->getSpelling() << Val;202}203}204205void Flang::AddRISCVTargetArgs(const ArgList &Args,206ArgStringList &CmdArgs) const {207const llvm::Triple &Triple = getToolChain().getTriple();208// Handle -mrvv-vector-bits=<bits>209if (Arg *A = Args.getLastArg(options::OPT_mrvv_vector_bits_EQ)) {210StringRef Val = A->getValue();211const Driver &D = getToolChain().getDriver();212213// Get minimum VLen from march.214unsigned MinVLen = 0;215std::string Arch = riscv::getRISCVArch(Args, Triple);216auto ISAInfo = llvm::RISCVISAInfo::parseArchString(217Arch, /*EnableExperimentalExtensions*/ true);218// Ignore parsing error.219if (!errorToBool(ISAInfo.takeError()))220MinVLen = (*ISAInfo)->getMinVLen();221222// If the value is "zvl", use MinVLen from march. Otherwise, try to parse223// as integer as long as we have a MinVLen.224unsigned Bits = 0;225if (Val == "zvl" && MinVLen >= llvm::RISCV::RVVBitsPerBlock) {226Bits = MinVLen;227} else if (!Val.getAsInteger(10, Bits)) {228// Only accept power of 2 values beteen RVVBitsPerBlock and 65536 that229// at least MinVLen.230if (Bits < MinVLen || Bits < llvm::RISCV::RVVBitsPerBlock ||231Bits > 65536 || !llvm::isPowerOf2_32(Bits))232Bits = 0;233}234235// If we got a valid value try to use it.236if (Bits != 0) {237unsigned VScaleMin = Bits / llvm::RISCV::RVVBitsPerBlock;238CmdArgs.push_back(239Args.MakeArgString("-mvscale-max=" + llvm::Twine(VScaleMin)));240CmdArgs.push_back(241Args.MakeArgString("-mvscale-min=" + llvm::Twine(VScaleMin)));242} else if (Val != "scalable") {243// Handle the unsupported values passed to mrvv-vector-bits.244D.Diag(diag::err_drv_unsupported_option_argument)245<< A->getSpelling() << Val;246}247}248}249250void Flang::AddX86_64TargetArgs(const ArgList &Args,251ArgStringList &CmdArgs) const {252if (Arg *A = Args.getLastArg(options::OPT_masm_EQ)) {253StringRef Value = A->getValue();254if (Value == "intel" || Value == "att") {255CmdArgs.push_back(Args.MakeArgString("-mllvm"));256CmdArgs.push_back(Args.MakeArgString("-x86-asm-syntax=" + Value));257} else {258getToolChain().getDriver().Diag(diag::err_drv_unsupported_option_argument)259<< A->getSpelling() << Value;260}261}262}263264static void addVSDefines(const ToolChain &TC, const ArgList &Args,265ArgStringList &CmdArgs) {266267unsigned ver = 0;268const VersionTuple vt = TC.computeMSVCVersion(nullptr, Args);269ver = vt.getMajor() * 10000000 + vt.getMinor().value_or(0) * 100000 +270vt.getSubminor().value_or(0);271CmdArgs.push_back(Args.MakeArgString("-D_MSC_VER=" + Twine(ver / 100000)));272CmdArgs.push_back(Args.MakeArgString("-D_MSC_FULL_VER=" + Twine(ver)));273CmdArgs.push_back(Args.MakeArgString("-D_WIN32"));274275const llvm::Triple &triple = TC.getTriple();276if (triple.isAArch64()) {277CmdArgs.push_back("-D_M_ARM64=1");278} else if (triple.isX86() && triple.isArch32Bit()) {279CmdArgs.push_back("-D_M_IX86=600");280} else if (triple.isX86() && triple.isArch64Bit()) {281CmdArgs.push_back("-D_M_X64=100");282} else {283llvm_unreachable(284"Flang on Windows only supports X86_32, X86_64 and AArch64");285}286}287288static void processVSRuntimeLibrary(const ToolChain &TC, const ArgList &Args,289ArgStringList &CmdArgs) {290assert(TC.getTriple().isKnownWindowsMSVCEnvironment() &&291"can only add VS runtime library on Windows!");292// if -fno-fortran-main has been passed, skip linking Fortran_main.a293if (TC.getTriple().isKnownWindowsMSVCEnvironment()) {294CmdArgs.push_back(Args.MakeArgString(295"--dependent-lib=" + TC.getCompilerRTBasename(Args, "builtins")));296}297unsigned RTOptionID = options::OPT__SLASH_MT;298if (auto *rtl = Args.getLastArg(options::OPT_fms_runtime_lib_EQ)) {299RTOptionID = llvm::StringSwitch<unsigned>(rtl->getValue())300.Case("static", options::OPT__SLASH_MT)301.Case("static_dbg", options::OPT__SLASH_MTd)302.Case("dll", options::OPT__SLASH_MD)303.Case("dll_dbg", options::OPT__SLASH_MDd)304.Default(options::OPT__SLASH_MT);305}306switch (RTOptionID) {307case options::OPT__SLASH_MT:308CmdArgs.push_back("-D_MT");309CmdArgs.push_back("--dependent-lib=libcmt");310CmdArgs.push_back("--dependent-lib=FortranRuntime.static.lib");311CmdArgs.push_back("--dependent-lib=FortranDecimal.static.lib");312break;313case options::OPT__SLASH_MTd:314CmdArgs.push_back("-D_MT");315CmdArgs.push_back("-D_DEBUG");316CmdArgs.push_back("--dependent-lib=libcmtd");317CmdArgs.push_back("--dependent-lib=FortranRuntime.static_dbg.lib");318CmdArgs.push_back("--dependent-lib=FortranDecimal.static_dbg.lib");319break;320case options::OPT__SLASH_MD:321CmdArgs.push_back("-D_MT");322CmdArgs.push_back("-D_DLL");323CmdArgs.push_back("--dependent-lib=msvcrt");324CmdArgs.push_back("--dependent-lib=FortranRuntime.dynamic.lib");325CmdArgs.push_back("--dependent-lib=FortranDecimal.dynamic.lib");326break;327case options::OPT__SLASH_MDd:328CmdArgs.push_back("-D_MT");329CmdArgs.push_back("-D_DEBUG");330CmdArgs.push_back("-D_DLL");331CmdArgs.push_back("--dependent-lib=msvcrtd");332CmdArgs.push_back("--dependent-lib=FortranRuntime.dynamic_dbg.lib");333CmdArgs.push_back("--dependent-lib=FortranDecimal.dynamic_dbg.lib");334break;335}336}337338void Flang::AddAMDGPUTargetArgs(const ArgList &Args,339ArgStringList &CmdArgs) const {340if (Arg *A = Args.getLastArg(options::OPT_mcode_object_version_EQ)) {341StringRef Val = A->getValue();342CmdArgs.push_back(Args.MakeArgString("-mcode-object-version=" + Val));343}344}345346void Flang::addTargetOptions(const ArgList &Args,347ArgStringList &CmdArgs) const {348const ToolChain &TC = getToolChain();349const llvm::Triple &Triple = TC.getEffectiveTriple();350const Driver &D = TC.getDriver();351352std::string CPU = getCPUName(D, Args, Triple);353if (!CPU.empty()) {354CmdArgs.push_back("-target-cpu");355CmdArgs.push_back(Args.MakeArgString(CPU));356}357358addOutlineAtomicsArgs(D, getToolChain(), Args, CmdArgs, Triple);359360// Add the target features.361switch (TC.getArch()) {362default:363break;364case llvm::Triple::aarch64:365getTargetFeatures(D, Triple, Args, CmdArgs, /*ForAs*/ false);366AddAArch64TargetArgs(Args, CmdArgs);367break;368369case llvm::Triple::r600:370case llvm::Triple::amdgcn:371getTargetFeatures(D, Triple, Args, CmdArgs, /*ForAs*/ false);372AddAMDGPUTargetArgs(Args, CmdArgs);373break;374case llvm::Triple::riscv64:375getTargetFeatures(D, Triple, Args, CmdArgs, /*ForAs*/ false);376AddRISCVTargetArgs(Args, CmdArgs);377break;378case llvm::Triple::x86_64:379getTargetFeatures(D, Triple, Args, CmdArgs, /*ForAs*/ false);380AddX86_64TargetArgs(Args, CmdArgs);381break;382}383384if (Arg *A = Args.getLastArg(options::OPT_fveclib)) {385StringRef Name = A->getValue();386if (Name == "SVML") {387if (Triple.getArch() != llvm::Triple::x86 &&388Triple.getArch() != llvm::Triple::x86_64)389D.Diag(diag::err_drv_unsupported_opt_for_target)390<< Name << Triple.getArchName();391} else if (Name == "LIBMVEC-X86") {392if (Triple.getArch() != llvm::Triple::x86 &&393Triple.getArch() != llvm::Triple::x86_64)394D.Diag(diag::err_drv_unsupported_opt_for_target)395<< Name << Triple.getArchName();396} else if (Name == "SLEEF" || Name == "ArmPL") {397if (Triple.getArch() != llvm::Triple::aarch64 &&398Triple.getArch() != llvm::Triple::aarch64_be)399D.Diag(diag::err_drv_unsupported_opt_for_target)400<< Name << Triple.getArchName();401}402403if (Triple.isOSDarwin()) {404// flang doesn't currently suport nostdlib, nodefaultlibs. Adding these405// here incase they are added someday406if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {407if (A->getValue() == StringRef{"Accelerate"}) {408CmdArgs.push_back("-framework");409CmdArgs.push_back("Accelerate");410}411}412}413A->render(Args, CmdArgs);414}415416if (Triple.isKnownWindowsMSVCEnvironment()) {417processVSRuntimeLibrary(TC, Args, CmdArgs);418addVSDefines(TC, Args, CmdArgs);419}420421// TODO: Add target specific flags, ABI, mtune option etc.422if (const Arg *A = Args.getLastArg(options::OPT_mtune_EQ)) {423CmdArgs.push_back("-tune-cpu");424if (A->getValue() == StringRef{"native"})425CmdArgs.push_back(Args.MakeArgString(llvm::sys::getHostCPUName()));426else427CmdArgs.push_back(A->getValue());428}429}430431void Flang::addOffloadOptions(Compilation &C, const InputInfoList &Inputs,432const JobAction &JA, const ArgList &Args,433ArgStringList &CmdArgs) const {434bool IsOpenMPDevice = JA.isDeviceOffloading(Action::OFK_OpenMP);435bool IsHostOffloadingAction = JA.isHostOffloading(Action::OFK_OpenMP) ||436JA.isHostOffloading(C.getActiveOffloadKinds());437438// Skips the primary input file, which is the input file that the compilation439// proccess will be executed upon (e.g. the host bitcode file) and440// adds other secondary input (e.g. device bitcode files for embedding to the441// -fembed-offload-object argument or the host IR file for proccessing442// during device compilation to the fopenmp-host-ir-file-path argument via443// OpenMPDeviceInput). This is condensed logic from the ConstructJob444// function inside of the Clang driver for pushing on further input arguments445// needed for offloading during various phases of compilation.446for (size_t i = 1; i < Inputs.size(); ++i) {447if (Inputs[i].getType() == types::TY_Nothing) {448// contains nothing, so it's skippable449} else if (IsHostOffloadingAction) {450CmdArgs.push_back(451Args.MakeArgString("-fembed-offload-object=" +452getToolChain().getInputFilename(Inputs[i])));453} else if (IsOpenMPDevice) {454if (Inputs[i].getFilename()) {455CmdArgs.push_back("-fopenmp-host-ir-file-path");456CmdArgs.push_back(Args.MakeArgString(Inputs[i].getFilename()));457} else {458llvm_unreachable("missing openmp host-ir file for device offloading");459}460} else {461llvm_unreachable(462"unexpectedly given multiple inputs or given unknown input");463}464}465466if (IsOpenMPDevice) {467// -fopenmp-is-target-device is passed along to tell the frontend that it is468// generating code for a device, so that only the relevant code is emitted.469CmdArgs.push_back("-fopenmp-is-target-device");470471// When in OpenMP offloading mode, enable debugging on the device.472Args.AddAllArgs(CmdArgs, options::OPT_fopenmp_target_debug_EQ);473if (Args.hasFlag(options::OPT_fopenmp_target_debug,474options::OPT_fno_openmp_target_debug, /*Default=*/false))475CmdArgs.push_back("-fopenmp-target-debug");476477// When in OpenMP offloading mode, forward assumptions information about478// thread and team counts in the device.479if (Args.hasFlag(options::OPT_fopenmp_assume_teams_oversubscription,480options::OPT_fno_openmp_assume_teams_oversubscription,481/*Default=*/false))482CmdArgs.push_back("-fopenmp-assume-teams-oversubscription");483if (Args.hasFlag(options::OPT_fopenmp_assume_threads_oversubscription,484options::OPT_fno_openmp_assume_threads_oversubscription,485/*Default=*/false))486CmdArgs.push_back("-fopenmp-assume-threads-oversubscription");487if (Args.hasArg(options::OPT_fopenmp_assume_no_thread_state))488CmdArgs.push_back("-fopenmp-assume-no-thread-state");489if (Args.hasArg(options::OPT_fopenmp_assume_no_nested_parallelism))490CmdArgs.push_back("-fopenmp-assume-no-nested-parallelism");491if (Args.hasArg(options::OPT_nogpulib))492CmdArgs.push_back("-nogpulib");493}494}495496static void addFloatingPointOptions(const Driver &D, const ArgList &Args,497ArgStringList &CmdArgs) {498StringRef FPContract;499bool HonorINFs = true;500bool HonorNaNs = true;501bool ApproxFunc = false;502bool SignedZeros = true;503bool AssociativeMath = false;504bool ReciprocalMath = false;505506if (const Arg *A = Args.getLastArg(options::OPT_ffp_contract)) {507const StringRef Val = A->getValue();508if (Val == "fast" || Val == "off") {509FPContract = Val;510} else if (Val == "on") {511// Warn instead of error because users might have makefiles written for512// gfortran (which accepts -ffp-contract=on)513D.Diag(diag::warn_drv_unsupported_option_for_flang)514<< Val << A->getOption().getName() << "off";515FPContract = "off";516} else517// Clang's "fast-honor-pragmas" option is not supported because it is518// non-standard519D.Diag(diag::err_drv_unsupported_option_argument)520<< A->getSpelling() << Val;521}522523for (const Arg *A : Args) {524auto optId = A->getOption().getID();525switch (optId) {526// if this isn't an FP option, skip the claim below527default:528continue;529530case options::OPT_fhonor_infinities:531HonorINFs = true;532break;533case options::OPT_fno_honor_infinities:534HonorINFs = false;535break;536case options::OPT_fhonor_nans:537HonorNaNs = true;538break;539case options::OPT_fno_honor_nans:540HonorNaNs = false;541break;542case options::OPT_fapprox_func:543ApproxFunc = true;544break;545case options::OPT_fno_approx_func:546ApproxFunc = false;547break;548case options::OPT_fsigned_zeros:549SignedZeros = true;550break;551case options::OPT_fno_signed_zeros:552SignedZeros = false;553break;554case options::OPT_fassociative_math:555AssociativeMath = true;556break;557case options::OPT_fno_associative_math:558AssociativeMath = false;559break;560case options::OPT_freciprocal_math:561ReciprocalMath = true;562break;563case options::OPT_fno_reciprocal_math:564ReciprocalMath = false;565break;566case options::OPT_Ofast:567[[fallthrough]];568case options::OPT_ffast_math:569HonorINFs = false;570HonorNaNs = false;571AssociativeMath = true;572ReciprocalMath = true;573ApproxFunc = true;574SignedZeros = false;575FPContract = "fast";576break;577case options::OPT_fno_fast_math:578HonorINFs = true;579HonorNaNs = true;580AssociativeMath = false;581ReciprocalMath = false;582ApproxFunc = false;583SignedZeros = true;584// -fno-fast-math should undo -ffast-math so I return FPContract to the585// default. It is important to check it is "fast" (the default) so that586// --ffp-contract=off -fno-fast-math --> -ffp-contract=off587if (FPContract == "fast")588FPContract = "";589break;590}591592// If we handled this option claim it593A->claim();594}595596if (!HonorINFs && !HonorNaNs && AssociativeMath && ReciprocalMath &&597ApproxFunc && !SignedZeros &&598(FPContract == "fast" || FPContract.empty())) {599CmdArgs.push_back("-ffast-math");600return;601}602603if (!FPContract.empty())604CmdArgs.push_back(Args.MakeArgString("-ffp-contract=" + FPContract));605606if (!HonorINFs)607CmdArgs.push_back("-menable-no-infs");608609if (!HonorNaNs)610CmdArgs.push_back("-menable-no-nans");611612if (ApproxFunc)613CmdArgs.push_back("-fapprox-func");614615if (!SignedZeros)616CmdArgs.push_back("-fno-signed-zeros");617618if (AssociativeMath && !SignedZeros)619CmdArgs.push_back("-mreassociate");620621if (ReciprocalMath)622CmdArgs.push_back("-freciprocal-math");623}624625static void renderRemarksOptions(const ArgList &Args, ArgStringList &CmdArgs,626const InputInfo &Input) {627StringRef Format = "yaml";628if (const Arg *A = Args.getLastArg(options::OPT_fsave_optimization_record_EQ))629Format = A->getValue();630631CmdArgs.push_back("-opt-record-file");632633const Arg *A = Args.getLastArg(options::OPT_foptimization_record_file_EQ);634if (A) {635CmdArgs.push_back(A->getValue());636} else {637SmallString<128> F;638639if (Args.hasArg(options::OPT_c) || Args.hasArg(options::OPT_S)) {640if (Arg *FinalOutput = Args.getLastArg(options::OPT_o))641F = FinalOutput->getValue();642}643644if (F.empty()) {645// Use the input filename.646F = llvm::sys::path::stem(Input.getBaseInput());647}648649SmallString<32> Extension;650Extension += "opt.";651Extension += Format;652653llvm::sys::path::replace_extension(F, Extension);654CmdArgs.push_back(Args.MakeArgString(F));655}656657if (const Arg *A =658Args.getLastArg(options::OPT_foptimization_record_passes_EQ)) {659CmdArgs.push_back("-opt-record-passes");660CmdArgs.push_back(A->getValue());661}662663if (!Format.empty()) {664CmdArgs.push_back("-opt-record-format");665CmdArgs.push_back(Format.data());666}667}668669void Flang::ConstructJob(Compilation &C, const JobAction &JA,670const InputInfo &Output, const InputInfoList &Inputs,671const ArgList &Args, const char *LinkingOutput) const {672const auto &TC = getToolChain();673const llvm::Triple &Triple = TC.getEffectiveTriple();674const std::string &TripleStr = Triple.getTriple();675676const Driver &D = TC.getDriver();677ArgStringList CmdArgs;678DiagnosticsEngine &Diags = D.getDiags();679680// Invoke ourselves in -fc1 mode.681CmdArgs.push_back("-fc1");682683// Add the "effective" target triple.684CmdArgs.push_back("-triple");685CmdArgs.push_back(Args.MakeArgString(TripleStr));686687if (isa<PreprocessJobAction>(JA)) {688CmdArgs.push_back("-E");689if (Args.getLastArg(options::OPT_dM)) {690CmdArgs.push_back("-dM");691}692} else if (isa<CompileJobAction>(JA) || isa<BackendJobAction>(JA)) {693if (JA.getType() == types::TY_Nothing) {694CmdArgs.push_back("-fsyntax-only");695} else if (JA.getType() == types::TY_AST) {696CmdArgs.push_back("-emit-ast");697} else if (JA.getType() == types::TY_LLVM_IR ||698JA.getType() == types::TY_LTO_IR) {699CmdArgs.push_back("-emit-llvm");700} else if (JA.getType() == types::TY_LLVM_BC ||701JA.getType() == types::TY_LTO_BC) {702CmdArgs.push_back("-emit-llvm-bc");703} else if (JA.getType() == types::TY_PP_Asm) {704CmdArgs.push_back("-S");705} else {706assert(false && "Unexpected output type!");707}708} else if (isa<AssembleJobAction>(JA)) {709CmdArgs.push_back("-emit-obj");710} else {711assert(false && "Unexpected action class for Flang tool.");712}713714const InputInfo &Input = Inputs[0];715types::ID InputType = Input.getType();716717// Add preprocessing options like -I, -D, etc. if we are using the718// preprocessor (i.e. skip when dealing with e.g. binary files).719if (types::getPreprocessedType(InputType) != types::TY_INVALID)720addPreprocessingOptions(Args, CmdArgs);721722addFortranDialectOptions(Args, CmdArgs);723724// Color diagnostics are parsed by the driver directly from argv and later725// re-parsed to construct this job; claim any possible color diagnostic here726// to avoid warn_drv_unused_argument.727Args.getLastArg(options::OPT_fcolor_diagnostics,728options::OPT_fno_color_diagnostics);729if (Diags.getDiagnosticOptions().ShowColors)730CmdArgs.push_back("-fcolor-diagnostics");731732// LTO mode is parsed by the Clang driver library.733LTOKind LTOMode = D.getLTOMode(/* IsOffload */ false);734assert(LTOMode != LTOK_Unknown && "Unknown LTO mode.");735if (LTOMode == LTOK_Full)736CmdArgs.push_back("-flto=full");737else if (LTOMode == LTOK_Thin) {738Diags.Report(739Diags.getCustomDiagID(DiagnosticsEngine::Warning,740"the option '-flto=thin' is a work in progress"));741CmdArgs.push_back("-flto=thin");742}743744// -fPIC and related options.745addPicOptions(Args, CmdArgs);746747// Floating point related options748addFloatingPointOptions(D, Args, CmdArgs);749750// Add target args, features, etc.751addTargetOptions(Args, CmdArgs);752753llvm::Reloc::Model RelocationModel =754std::get<0>(ParsePICArgs(getToolChain(), Args));755// Add MCModel information756addMCModel(D, Args, Triple, RelocationModel, CmdArgs);757758// Add Codegen options759addCodegenOptions(Args, CmdArgs);760761// Add R Group options762Args.AddAllArgs(CmdArgs, options::OPT_R_Group);763764// Remarks can be enabled with any of the `-f.*optimization-record.*` flags.765if (willEmitRemarks(Args))766renderRemarksOptions(Args, CmdArgs, Input);767768// Add other compile options769addOtherOptions(Args, CmdArgs);770771// Disable all warnings772// TODO: Handle interactions between -w, -pedantic, -Wall, -WOption773Args.AddLastArg(CmdArgs, options::OPT_w);774775// Forward flags for OpenMP. We don't do this if the current action is an776// device offloading action other than OpenMP.777if (Args.hasFlag(options::OPT_fopenmp, options::OPT_fopenmp_EQ,778options::OPT_fno_openmp, false) &&779(JA.isDeviceOffloading(Action::OFK_None) ||780JA.isDeviceOffloading(Action::OFK_OpenMP))) {781switch (D.getOpenMPRuntime(Args)) {782case Driver::OMPRT_OMP:783case Driver::OMPRT_IOMP5:784// Clang can generate useful OpenMP code for these two runtime libraries.785CmdArgs.push_back("-fopenmp");786Args.AddAllArgs(CmdArgs, options::OPT_fopenmp_version_EQ);787788if (Args.hasArg(options::OPT_fopenmp_force_usm))789CmdArgs.push_back("-fopenmp-force-usm");790791// FIXME: Clang supports a whole bunch more flags here.792break;793default:794// By default, if Clang doesn't know how to generate useful OpenMP code795// for a specific runtime library, we just don't pass the '-fopenmp' flag796// down to the actual compilation.797// FIXME: It would be better to have a mode which *only* omits IR798// generation based on the OpenMP support so that we get consistent799// semantic analysis, etc.800const Arg *A = Args.getLastArg(options::OPT_fopenmp_EQ);801D.Diag(diag::warn_drv_unsupported_openmp_library)802<< A->getSpelling() << A->getValue();803break;804}805}806807// Pass the path to compiler resource files.808CmdArgs.push_back("-resource-dir");809CmdArgs.push_back(D.ResourceDir.c_str());810811// Offloading related options812addOffloadOptions(C, Inputs, JA, Args, CmdArgs);813814// Forward -Xflang arguments to -fc1815Args.AddAllArgValues(CmdArgs, options::OPT_Xflang);816817CodeGenOptions::FramePointerKind FPKeepKind =818getFramePointerKind(Args, Triple);819820const char *FPKeepKindStr = nullptr;821switch (FPKeepKind) {822case CodeGenOptions::FramePointerKind::None:823FPKeepKindStr = "-mframe-pointer=none";824break;825case CodeGenOptions::FramePointerKind::Reserved:826FPKeepKindStr = "-mframe-pointer=reserved";827break;828case CodeGenOptions::FramePointerKind::NonLeaf:829FPKeepKindStr = "-mframe-pointer=non-leaf";830break;831case CodeGenOptions::FramePointerKind::All:832FPKeepKindStr = "-mframe-pointer=all";833break;834}835assert(FPKeepKindStr && "unknown FramePointerKind");836CmdArgs.push_back(FPKeepKindStr);837838// Forward -mllvm options to the LLVM option parser. In practice, this means839// forwarding to `-fc1` as that's where the LLVM parser is run.840for (const Arg *A : Args.filtered(options::OPT_mllvm)) {841A->claim();842A->render(Args, CmdArgs);843}844845for (const Arg *A : Args.filtered(options::OPT_mmlir)) {846A->claim();847A->render(Args, CmdArgs);848}849850// Remove any unsupported gfortran diagnostic options851for (const Arg *A : Args.filtered(options::OPT_flang_ignored_w_Group)) {852A->claim();853D.Diag(diag::warn_drv_unsupported_diag_option_for_flang)854<< A->getOption().getName();855}856857// Optimization level for CodeGen.858if (const Arg *A = Args.getLastArg(options::OPT_O_Group)) {859if (A->getOption().matches(options::OPT_O4)) {860CmdArgs.push_back("-O3");861D.Diag(diag::warn_O4_is_O3);862} else if (A->getOption().matches(options::OPT_Ofast)) {863CmdArgs.push_back("-O3");864} else {865A->render(Args, CmdArgs);866}867}868869assert((Output.isFilename() || Output.isNothing()) && "Invalid output.");870if (Output.isFilename()) {871CmdArgs.push_back("-o");872CmdArgs.push_back(Output.getFilename());873}874875assert(Input.isFilename() && "Invalid input.");876877if (Args.getLastArg(options::OPT_save_temps_EQ))878Args.AddLastArg(CmdArgs, options::OPT_save_temps_EQ);879880addDashXForInput(Args, Input, CmdArgs);881882CmdArgs.push_back(Input.getFilename());883884// TODO: Replace flang-new with flang once the new driver replaces the885// throwaway driver886const char *Exec = Args.MakeArgString(D.GetProgramPath("flang-new", TC));887C.addCommand(std::make_unique<Command>(JA, *this,888ResponseFileSupport::AtFileUTF8(),889Exec, CmdArgs, Inputs, Output));890}891892Flang::Flang(const ToolChain &TC) : Tool("flang-new", "flang frontend", TC) {}893894Flang::~Flang() {}895896897