xref: /freebsd-src/contrib/llvm-project/clang/lib/Driver/ToolChains/Flang.cpp (revision 06c3fb2749bda94cb5201f81ffdb8fa6c3161b2e)
1480093f4SDimitry Andric //===-- Flang.cpp - Flang+LLVM ToolChain Implementations --------*- C++ -*-===//
2480093f4SDimitry Andric //
3480093f4SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4480093f4SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5480093f4SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6480093f4SDimitry Andric //
7480093f4SDimitry Andric //===----------------------------------------------------------------------===//
8480093f4SDimitry Andric 
9480093f4SDimitry Andric 
10480093f4SDimitry Andric #include "Flang.h"
11480093f4SDimitry Andric #include "CommonArgs.h"
12480093f4SDimitry Andric 
13480093f4SDimitry Andric #include "clang/Driver/Options.h"
14*06c3fb27SDimitry Andric #include "llvm/Frontend/Debug/Options.h"
15480093f4SDimitry Andric 
16480093f4SDimitry Andric #include <cassert>
17480093f4SDimitry Andric 
18480093f4SDimitry Andric using namespace clang::driver;
19480093f4SDimitry Andric using namespace clang::driver::tools;
20480093f4SDimitry Andric using namespace clang;
21480093f4SDimitry Andric using namespace llvm::opt;
22480093f4SDimitry Andric 
2381ad6265SDimitry Andric /// Add -x lang to \p CmdArgs for \p Input.
2481ad6265SDimitry Andric static void addDashXForInput(const ArgList &Args, const InputInfo &Input,
2581ad6265SDimitry Andric                              ArgStringList &CmdArgs) {
2681ad6265SDimitry Andric   CmdArgs.push_back("-x");
2781ad6265SDimitry Andric   // Map the driver type to the frontend type.
2881ad6265SDimitry Andric   CmdArgs.push_back(types::getTypeName(Input.getType()));
2981ad6265SDimitry Andric }
3081ad6265SDimitry Andric 
31bdd1243dSDimitry Andric void Flang::addFortranDialectOptions(const ArgList &Args,
32fe6060f1SDimitry Andric                                      ArgStringList &CmdArgs) const {
33*06c3fb27SDimitry Andric   Args.AddAllArgs(CmdArgs, {options::OPT_ffixed_form,
34*06c3fb27SDimitry Andric                             options::OPT_ffree_form,
35*06c3fb27SDimitry Andric                             options::OPT_ffixed_line_length_EQ,
36*06c3fb27SDimitry Andric                             options::OPT_fopenmp,
37*06c3fb27SDimitry Andric                             options::OPT_fopenmp_version_EQ,
38*06c3fb27SDimitry Andric                             options::OPT_fopenacc,
39*06c3fb27SDimitry Andric                             options::OPT_finput_charset_EQ,
40*06c3fb27SDimitry Andric                             options::OPT_fimplicit_none,
41*06c3fb27SDimitry Andric                             options::OPT_fno_implicit_none,
42*06c3fb27SDimitry Andric                             options::OPT_fbackslash,
43*06c3fb27SDimitry Andric                             options::OPT_fno_backslash,
44fe6060f1SDimitry Andric                             options::OPT_flogical_abbreviations,
45fe6060f1SDimitry Andric                             options::OPT_fno_logical_abbreviations,
46*06c3fb27SDimitry Andric                             options::OPT_fxor_operator,
47*06c3fb27SDimitry Andric                             options::OPT_fno_xor_operator,
48fe6060f1SDimitry Andric                             options::OPT_falternative_parameter_statement,
49*06c3fb27SDimitry Andric                             options::OPT_fdefault_real_8,
50*06c3fb27SDimitry Andric                             options::OPT_fdefault_integer_8,
51*06c3fb27SDimitry Andric                             options::OPT_fdefault_double_8,
52*06c3fb27SDimitry Andric                             options::OPT_flarge_sizes,
534824e7fdSDimitry Andric                             options::OPT_fno_automatic});
54fe6060f1SDimitry Andric }
55fe6060f1SDimitry Andric 
56bdd1243dSDimitry Andric void Flang::addPreprocessingOptions(const ArgList &Args,
57e8d8bef9SDimitry Andric                                     ArgStringList &CmdArgs) const {
58349cc55cSDimitry Andric   Args.AddAllArgs(CmdArgs,
59349cc55cSDimitry Andric                   {options::OPT_P, options::OPT_D, options::OPT_U,
60349cc55cSDimitry Andric                    options::OPT_I, options::OPT_cpp, options::OPT_nocpp});
61fe6060f1SDimitry Andric }
62fe6060f1SDimitry Andric 
63*06c3fb27SDimitry Andric /// @C shouldLoopVersion
64*06c3fb27SDimitry Andric ///
65*06c3fb27SDimitry Andric /// Check if Loop Versioning should be enabled.
66*06c3fb27SDimitry Andric /// We look for the last of one of the following:
67*06c3fb27SDimitry Andric ///   -Ofast, -O4, -O<number> and -f[no-]version-loops-for-stride.
68*06c3fb27SDimitry Andric /// Loop versioning is disabled if the last option is
69*06c3fb27SDimitry Andric ///  -fno-version-loops-for-stride.
70*06c3fb27SDimitry Andric /// Loop versioning is enabled if the last option is one of:
71*06c3fb27SDimitry Andric ///  -floop-versioning
72*06c3fb27SDimitry Andric ///  -Ofast
73*06c3fb27SDimitry Andric ///  -O4
74*06c3fb27SDimitry Andric ///  -O3
75*06c3fb27SDimitry Andric /// For all other cases, loop versioning is is disabled.
76*06c3fb27SDimitry Andric ///
77*06c3fb27SDimitry Andric /// The gfortran compiler automatically enables the option for -O3 or -Ofast.
78*06c3fb27SDimitry Andric ///
79*06c3fb27SDimitry Andric /// @return true if loop-versioning should be enabled, otherwise false.
80*06c3fb27SDimitry Andric static bool shouldLoopVersion(const ArgList &Args) {
81*06c3fb27SDimitry Andric   const Arg *LoopVersioningArg = Args.getLastArg(
82*06c3fb27SDimitry Andric       options::OPT_Ofast, options::OPT_O, options::OPT_O4,
83*06c3fb27SDimitry Andric       options::OPT_floop_versioning, options::OPT_fno_loop_versioning);
84*06c3fb27SDimitry Andric   if (!LoopVersioningArg)
85*06c3fb27SDimitry Andric     return false;
86*06c3fb27SDimitry Andric 
87*06c3fb27SDimitry Andric   if (LoopVersioningArg->getOption().matches(options::OPT_fno_loop_versioning))
88*06c3fb27SDimitry Andric     return false;
89*06c3fb27SDimitry Andric 
90*06c3fb27SDimitry Andric   if (LoopVersioningArg->getOption().matches(options::OPT_floop_versioning))
91*06c3fb27SDimitry Andric     return true;
92*06c3fb27SDimitry Andric 
93*06c3fb27SDimitry Andric   if (LoopVersioningArg->getOption().matches(options::OPT_Ofast) ||
94*06c3fb27SDimitry Andric       LoopVersioningArg->getOption().matches(options::OPT_O4))
95*06c3fb27SDimitry Andric     return true;
96*06c3fb27SDimitry Andric 
97*06c3fb27SDimitry Andric   if (LoopVersioningArg->getOption().matches(options::OPT_O)) {
98*06c3fb27SDimitry Andric     StringRef S(LoopVersioningArg->getValue());
99*06c3fb27SDimitry Andric     unsigned OptLevel = 0;
100*06c3fb27SDimitry Andric     // Note -Os or Oz woould "fail" here, so return false. Which is the
101*06c3fb27SDimitry Andric     // desiered behavior.
102*06c3fb27SDimitry Andric     if (S.getAsInteger(10, OptLevel))
103*06c3fb27SDimitry Andric       return false;
104*06c3fb27SDimitry Andric 
105*06c3fb27SDimitry Andric     return OptLevel > 2;
106*06c3fb27SDimitry Andric   }
107*06c3fb27SDimitry Andric 
108*06c3fb27SDimitry Andric   llvm_unreachable("We should not end up here");
109*06c3fb27SDimitry Andric   return false;
110*06c3fb27SDimitry Andric }
111*06c3fb27SDimitry Andric 
112bdd1243dSDimitry Andric void Flang::addOtherOptions(const ArgList &Args, ArgStringList &CmdArgs) const {
113fe6060f1SDimitry Andric   Args.AddAllArgs(CmdArgs,
114fe6060f1SDimitry Andric                   {options::OPT_module_dir, options::OPT_fdebug_module_writer,
115fe6060f1SDimitry Andric                    options::OPT_fintrinsic_modules_path, options::OPT_pedantic,
116bdd1243dSDimitry Andric                    options::OPT_std_EQ, options::OPT_W_Joined,
117*06c3fb27SDimitry Andric                    options::OPT_fconvert_EQ, options::OPT_fpass_plugin_EQ,
118*06c3fb27SDimitry Andric                    options::OPT_funderscoring, options::OPT_fno_underscoring});
119*06c3fb27SDimitry Andric 
120*06c3fb27SDimitry Andric   llvm::codegenoptions::DebugInfoKind DebugInfoKind;
121*06c3fb27SDimitry Andric   if (Args.hasArg(options::OPT_gN_Group)) {
122*06c3fb27SDimitry Andric     Arg *gNArg = Args.getLastArg(options::OPT_gN_Group);
123*06c3fb27SDimitry Andric     DebugInfoKind = debugLevelToInfoKind(*gNArg);
124*06c3fb27SDimitry Andric   } else if (Args.hasArg(options::OPT_g_Flag)) {
125*06c3fb27SDimitry Andric     DebugInfoKind = llvm::codegenoptions::DebugLineTablesOnly;
126*06c3fb27SDimitry Andric   } else {
127*06c3fb27SDimitry Andric     DebugInfoKind = llvm::codegenoptions::NoDebugInfo;
128*06c3fb27SDimitry Andric   }
129*06c3fb27SDimitry Andric   addDebugInfoKind(CmdArgs, DebugInfoKind);
130*06c3fb27SDimitry Andric }
131*06c3fb27SDimitry Andric 
132*06c3fb27SDimitry Andric void Flang::addCodegenOptions(const ArgList &Args,
133*06c3fb27SDimitry Andric                               ArgStringList &CmdArgs) const {
134*06c3fb27SDimitry Andric   Arg *stackArrays =
135*06c3fb27SDimitry Andric       Args.getLastArg(options::OPT_Ofast, options::OPT_fstack_arrays,
136*06c3fb27SDimitry Andric                       options::OPT_fno_stack_arrays);
137*06c3fb27SDimitry Andric   if (stackArrays &&
138*06c3fb27SDimitry Andric       !stackArrays->getOption().matches(options::OPT_fno_stack_arrays))
139*06c3fb27SDimitry Andric     CmdArgs.push_back("-fstack-arrays");
140*06c3fb27SDimitry Andric 
141*06c3fb27SDimitry Andric   if (Args.hasArg(options::OPT_flang_experimental_hlfir))
142*06c3fb27SDimitry Andric     CmdArgs.push_back("-flang-experimental-hlfir");
143*06c3fb27SDimitry Andric   if (Args.hasArg(options::OPT_flang_experimental_polymorphism))
144*06c3fb27SDimitry Andric     CmdArgs.push_back("-flang-experimental-polymorphism");
145*06c3fb27SDimitry Andric   if (shouldLoopVersion(Args))
146*06c3fb27SDimitry Andric     CmdArgs.push_back("-fversion-loops-for-stride");
147bdd1243dSDimitry Andric }
148bdd1243dSDimitry Andric 
149bdd1243dSDimitry Andric void Flang::addPicOptions(const ArgList &Args, ArgStringList &CmdArgs) const {
150bdd1243dSDimitry Andric   // ParsePICArgs parses -fPIC/-fPIE and their variants and returns a tuple of
151bdd1243dSDimitry Andric   // (RelocationModel, PICLevel, IsPIE).
152bdd1243dSDimitry Andric   llvm::Reloc::Model RelocationModel;
153bdd1243dSDimitry Andric   unsigned PICLevel;
154bdd1243dSDimitry Andric   bool IsPIE;
155bdd1243dSDimitry Andric   std::tie(RelocationModel, PICLevel, IsPIE) =
156bdd1243dSDimitry Andric       ParsePICArgs(getToolChain(), Args);
157bdd1243dSDimitry Andric 
158bdd1243dSDimitry Andric   if (auto *RMName = RelocationModelName(RelocationModel)) {
159bdd1243dSDimitry Andric     CmdArgs.push_back("-mrelocation-model");
160bdd1243dSDimitry Andric     CmdArgs.push_back(RMName);
161bdd1243dSDimitry Andric   }
162bdd1243dSDimitry Andric   if (PICLevel > 0) {
163bdd1243dSDimitry Andric     CmdArgs.push_back("-pic-level");
164bdd1243dSDimitry Andric     CmdArgs.push_back(PICLevel == 1 ? "1" : "2");
165bdd1243dSDimitry Andric     if (IsPIE)
166bdd1243dSDimitry Andric       CmdArgs.push_back("-pic-is-pie");
167bdd1243dSDimitry Andric   }
168bdd1243dSDimitry Andric }
169bdd1243dSDimitry Andric 
170bdd1243dSDimitry Andric void Flang::addTargetOptions(const ArgList &Args,
171bdd1243dSDimitry Andric                              ArgStringList &CmdArgs) const {
172bdd1243dSDimitry Andric   const ToolChain &TC = getToolChain();
173bdd1243dSDimitry Andric   const llvm::Triple &Triple = TC.getEffectiveTriple();
174bdd1243dSDimitry Andric   const Driver &D = TC.getDriver();
175bdd1243dSDimitry Andric 
176bdd1243dSDimitry Andric   std::string CPU = getCPUName(D, Args, Triple);
177bdd1243dSDimitry Andric   if (!CPU.empty()) {
178bdd1243dSDimitry Andric     CmdArgs.push_back("-target-cpu");
179bdd1243dSDimitry Andric     CmdArgs.push_back(Args.MakeArgString(CPU));
180bdd1243dSDimitry Andric   }
181bdd1243dSDimitry Andric 
182bdd1243dSDimitry Andric   // Add the target features.
183bdd1243dSDimitry Andric   switch (TC.getArch()) {
184bdd1243dSDimitry Andric   default:
185bdd1243dSDimitry Andric     break;
186*06c3fb27SDimitry Andric   case llvm::Triple::r600:
187*06c3fb27SDimitry Andric   case llvm::Triple::amdgcn:
188bdd1243dSDimitry Andric   case llvm::Triple::aarch64:
189*06c3fb27SDimitry Andric   case llvm::Triple::riscv64:
190bdd1243dSDimitry Andric   case llvm::Triple::x86_64:
191bdd1243dSDimitry Andric     getTargetFeatures(D, Triple, Args, CmdArgs, /*ForAs*/ false);
192bdd1243dSDimitry Andric     break;
193bdd1243dSDimitry Andric   }
194bdd1243dSDimitry Andric 
195bdd1243dSDimitry Andric   // TODO: Add target specific flags, ABI, mtune option etc.
196bdd1243dSDimitry Andric }
197bdd1243dSDimitry Andric 
198*06c3fb27SDimitry Andric void Flang::addOffloadOptions(Compilation &C, const InputInfoList &Inputs,
199*06c3fb27SDimitry Andric                               const JobAction &JA, const ArgList &Args,
200*06c3fb27SDimitry Andric                               ArgStringList &CmdArgs) const {
201*06c3fb27SDimitry Andric   bool IsOpenMPDevice = JA.isDeviceOffloading(Action::OFK_OpenMP);
202*06c3fb27SDimitry Andric   bool IsHostOffloadingAction = JA.isHostOffloading(Action::OFK_OpenMP) ||
203*06c3fb27SDimitry Andric                                 JA.isHostOffloading(C.getActiveOffloadKinds());
204*06c3fb27SDimitry Andric 
205*06c3fb27SDimitry Andric   // Skips the primary input file, which is the input file that the compilation
206*06c3fb27SDimitry Andric   // proccess will be executed upon (e.g. the host bitcode file) and
207*06c3fb27SDimitry Andric   // adds other secondary input (e.g. device bitcode files for embedding to the
208*06c3fb27SDimitry Andric   // -fembed-offload-object argument or the host IR file for proccessing
209*06c3fb27SDimitry Andric   // during device compilation to the fopenmp-host-ir-file-path argument via
210*06c3fb27SDimitry Andric   // OpenMPDeviceInput). This is condensed logic from the ConstructJob
211*06c3fb27SDimitry Andric   // function inside of the Clang driver for pushing on further input arguments
212*06c3fb27SDimitry Andric   // needed for offloading during various phases of compilation.
213*06c3fb27SDimitry Andric   for (size_t i = 1; i < Inputs.size(); ++i) {
214*06c3fb27SDimitry Andric     if (Inputs[i].getType() == types::TY_Nothing) {
215*06c3fb27SDimitry Andric       // contains nothing, so it's skippable
216*06c3fb27SDimitry Andric     } else if (IsHostOffloadingAction) {
217*06c3fb27SDimitry Andric       CmdArgs.push_back(
218*06c3fb27SDimitry Andric           Args.MakeArgString("-fembed-offload-object=" +
219*06c3fb27SDimitry Andric                              getToolChain().getInputFilename(Inputs[i])));
220*06c3fb27SDimitry Andric     } else if (IsOpenMPDevice) {
221*06c3fb27SDimitry Andric       if (Inputs[i].getFilename()) {
222*06c3fb27SDimitry Andric         CmdArgs.push_back("-fopenmp-host-ir-file-path");
223*06c3fb27SDimitry Andric         CmdArgs.push_back(Args.MakeArgString(Inputs[i].getFilename()));
224*06c3fb27SDimitry Andric       } else {
225*06c3fb27SDimitry Andric         llvm_unreachable("missing openmp host-ir file for device offloading");
226*06c3fb27SDimitry Andric       }
227*06c3fb27SDimitry Andric     } else {
228*06c3fb27SDimitry Andric       llvm_unreachable(
229*06c3fb27SDimitry Andric           "unexpectedly given multiple inputs or given unknown input");
230*06c3fb27SDimitry Andric     }
231*06c3fb27SDimitry Andric   }
232*06c3fb27SDimitry Andric 
233*06c3fb27SDimitry Andric   if (IsOpenMPDevice) {
234*06c3fb27SDimitry Andric     // -fopenmp-is-target-device is passed along to tell the frontend that it is
235*06c3fb27SDimitry Andric     // generating code for a device, so that only the relevant code is emitted.
236*06c3fb27SDimitry Andric     CmdArgs.push_back("-fopenmp-is-target-device");
237*06c3fb27SDimitry Andric 
238*06c3fb27SDimitry Andric     // When in OpenMP offloading mode, enable debugging on the device.
239*06c3fb27SDimitry Andric     Args.AddAllArgs(CmdArgs, options::OPT_fopenmp_target_debug_EQ);
240*06c3fb27SDimitry Andric     if (Args.hasFlag(options::OPT_fopenmp_target_debug,
241*06c3fb27SDimitry Andric                      options::OPT_fno_openmp_target_debug, /*Default=*/false))
242*06c3fb27SDimitry Andric       CmdArgs.push_back("-fopenmp-target-debug");
243*06c3fb27SDimitry Andric 
244*06c3fb27SDimitry Andric     // When in OpenMP offloading mode, forward assumptions information about
245*06c3fb27SDimitry Andric     // thread and team counts in the device.
246*06c3fb27SDimitry Andric     if (Args.hasFlag(options::OPT_fopenmp_assume_teams_oversubscription,
247*06c3fb27SDimitry Andric                      options::OPT_fno_openmp_assume_teams_oversubscription,
248*06c3fb27SDimitry Andric                      /*Default=*/false))
249*06c3fb27SDimitry Andric       CmdArgs.push_back("-fopenmp-assume-teams-oversubscription");
250*06c3fb27SDimitry Andric     if (Args.hasFlag(options::OPT_fopenmp_assume_threads_oversubscription,
251*06c3fb27SDimitry Andric                      options::OPT_fno_openmp_assume_threads_oversubscription,
252*06c3fb27SDimitry Andric                      /*Default=*/false))
253*06c3fb27SDimitry Andric       CmdArgs.push_back("-fopenmp-assume-threads-oversubscription");
254*06c3fb27SDimitry Andric     if (Args.hasArg(options::OPT_fopenmp_assume_no_thread_state))
255*06c3fb27SDimitry Andric       CmdArgs.push_back("-fopenmp-assume-no-thread-state");
256*06c3fb27SDimitry Andric     if (Args.hasArg(options::OPT_fopenmp_assume_no_nested_parallelism))
257*06c3fb27SDimitry Andric       CmdArgs.push_back("-fopenmp-assume-no-nested-parallelism");
258*06c3fb27SDimitry Andric   }
259*06c3fb27SDimitry Andric }
260*06c3fb27SDimitry Andric 
261bdd1243dSDimitry Andric static void addFloatingPointOptions(const Driver &D, const ArgList &Args,
262bdd1243dSDimitry Andric                                     ArgStringList &CmdArgs) {
263bdd1243dSDimitry Andric   StringRef FPContract;
264bdd1243dSDimitry Andric   bool HonorINFs = true;
265bdd1243dSDimitry Andric   bool HonorNaNs = true;
266bdd1243dSDimitry Andric   bool ApproxFunc = false;
267bdd1243dSDimitry Andric   bool SignedZeros = true;
268bdd1243dSDimitry Andric   bool AssociativeMath = false;
269bdd1243dSDimitry Andric   bool ReciprocalMath = false;
270bdd1243dSDimitry Andric 
271bdd1243dSDimitry Andric   if (const Arg *A = Args.getLastArg(options::OPT_ffp_contract)) {
272bdd1243dSDimitry Andric     const StringRef Val = A->getValue();
273bdd1243dSDimitry Andric     if (Val == "fast" || Val == "off") {
274bdd1243dSDimitry Andric       FPContract = Val;
275bdd1243dSDimitry Andric     } else if (Val == "on") {
276bdd1243dSDimitry Andric       // Warn instead of error because users might have makefiles written for
277bdd1243dSDimitry Andric       // gfortran (which accepts -ffp-contract=on)
278bdd1243dSDimitry Andric       D.Diag(diag::warn_drv_unsupported_option_for_flang)
279bdd1243dSDimitry Andric           << Val << A->getOption().getName() << "off";
280bdd1243dSDimitry Andric       FPContract = "off";
281bdd1243dSDimitry Andric     } else
282bdd1243dSDimitry Andric       // Clang's "fast-honor-pragmas" option is not supported because it is
283bdd1243dSDimitry Andric       // non-standard
284bdd1243dSDimitry Andric       D.Diag(diag::err_drv_unsupported_option_argument)
285bdd1243dSDimitry Andric           << A->getSpelling() << Val;
286bdd1243dSDimitry Andric   }
287bdd1243dSDimitry Andric 
288bdd1243dSDimitry Andric   for (const Arg *A : Args) {
289bdd1243dSDimitry Andric     auto optId = A->getOption().getID();
290bdd1243dSDimitry Andric     switch (optId) {
291bdd1243dSDimitry Andric     // if this isn't an FP option, skip the claim below
292bdd1243dSDimitry Andric     default:
293bdd1243dSDimitry Andric       continue;
294bdd1243dSDimitry Andric 
295bdd1243dSDimitry Andric     case options::OPT_fhonor_infinities:
296bdd1243dSDimitry Andric       HonorINFs = true;
297bdd1243dSDimitry Andric       break;
298bdd1243dSDimitry Andric     case options::OPT_fno_honor_infinities:
299bdd1243dSDimitry Andric       HonorINFs = false;
300bdd1243dSDimitry Andric       break;
301bdd1243dSDimitry Andric     case options::OPT_fhonor_nans:
302bdd1243dSDimitry Andric       HonorNaNs = true;
303bdd1243dSDimitry Andric       break;
304bdd1243dSDimitry Andric     case options::OPT_fno_honor_nans:
305bdd1243dSDimitry Andric       HonorNaNs = false;
306bdd1243dSDimitry Andric       break;
307bdd1243dSDimitry Andric     case options::OPT_fapprox_func:
308bdd1243dSDimitry Andric       ApproxFunc = true;
309bdd1243dSDimitry Andric       break;
310bdd1243dSDimitry Andric     case options::OPT_fno_approx_func:
311bdd1243dSDimitry Andric       ApproxFunc = false;
312bdd1243dSDimitry Andric       break;
313bdd1243dSDimitry Andric     case options::OPT_fsigned_zeros:
314bdd1243dSDimitry Andric       SignedZeros = true;
315bdd1243dSDimitry Andric       break;
316bdd1243dSDimitry Andric     case options::OPT_fno_signed_zeros:
317bdd1243dSDimitry Andric       SignedZeros = false;
318bdd1243dSDimitry Andric       break;
319bdd1243dSDimitry Andric     case options::OPT_fassociative_math:
320bdd1243dSDimitry Andric       AssociativeMath = true;
321bdd1243dSDimitry Andric       break;
322bdd1243dSDimitry Andric     case options::OPT_fno_associative_math:
323bdd1243dSDimitry Andric       AssociativeMath = false;
324bdd1243dSDimitry Andric       break;
325bdd1243dSDimitry Andric     case options::OPT_freciprocal_math:
326bdd1243dSDimitry Andric       ReciprocalMath = true;
327bdd1243dSDimitry Andric       break;
328bdd1243dSDimitry Andric     case options::OPT_fno_reciprocal_math:
329bdd1243dSDimitry Andric       ReciprocalMath = false;
330bdd1243dSDimitry Andric       break;
331bdd1243dSDimitry Andric     case options::OPT_Ofast:
332bdd1243dSDimitry Andric       [[fallthrough]];
333bdd1243dSDimitry Andric     case options::OPT_ffast_math:
334bdd1243dSDimitry Andric       HonorINFs = false;
335bdd1243dSDimitry Andric       HonorNaNs = false;
336bdd1243dSDimitry Andric       AssociativeMath = true;
337bdd1243dSDimitry Andric       ReciprocalMath = true;
338bdd1243dSDimitry Andric       ApproxFunc = true;
339bdd1243dSDimitry Andric       SignedZeros = false;
340bdd1243dSDimitry Andric       FPContract = "fast";
341bdd1243dSDimitry Andric       break;
342bdd1243dSDimitry Andric     case options::OPT_fno_fast_math:
343bdd1243dSDimitry Andric       HonorINFs = true;
344bdd1243dSDimitry Andric       HonorNaNs = true;
345bdd1243dSDimitry Andric       AssociativeMath = false;
346bdd1243dSDimitry Andric       ReciprocalMath = false;
347bdd1243dSDimitry Andric       ApproxFunc = false;
348bdd1243dSDimitry Andric       SignedZeros = true;
349bdd1243dSDimitry Andric       // -fno-fast-math should undo -ffast-math so I return FPContract to the
350bdd1243dSDimitry Andric       // default. It is important to check it is "fast" (the default) so that
351bdd1243dSDimitry Andric       // --ffp-contract=off -fno-fast-math --> -ffp-contract=off
352bdd1243dSDimitry Andric       if (FPContract == "fast")
353bdd1243dSDimitry Andric         FPContract = "";
354bdd1243dSDimitry Andric       break;
355bdd1243dSDimitry Andric     }
356bdd1243dSDimitry Andric 
357bdd1243dSDimitry Andric     // If we handled this option claim it
358bdd1243dSDimitry Andric     A->claim();
359bdd1243dSDimitry Andric   }
360bdd1243dSDimitry Andric 
361bdd1243dSDimitry Andric   if (!HonorINFs && !HonorNaNs && AssociativeMath && ReciprocalMath &&
362bdd1243dSDimitry Andric       ApproxFunc && !SignedZeros &&
363bdd1243dSDimitry Andric       (FPContract == "fast" || FPContract == "")) {
364bdd1243dSDimitry Andric     CmdArgs.push_back("-ffast-math");
365bdd1243dSDimitry Andric     return;
366bdd1243dSDimitry Andric   }
367bdd1243dSDimitry Andric 
368bdd1243dSDimitry Andric   if (!FPContract.empty())
369bdd1243dSDimitry Andric     CmdArgs.push_back(Args.MakeArgString("-ffp-contract=" + FPContract));
370bdd1243dSDimitry Andric 
371bdd1243dSDimitry Andric   if (!HonorINFs)
372bdd1243dSDimitry Andric     CmdArgs.push_back("-menable-no-infs");
373bdd1243dSDimitry Andric 
374bdd1243dSDimitry Andric   if (!HonorNaNs)
375bdd1243dSDimitry Andric     CmdArgs.push_back("-menable-no-nans");
376bdd1243dSDimitry Andric 
377bdd1243dSDimitry Andric   if (ApproxFunc)
378bdd1243dSDimitry Andric     CmdArgs.push_back("-fapprox-func");
379bdd1243dSDimitry Andric 
380bdd1243dSDimitry Andric   if (!SignedZeros)
381bdd1243dSDimitry Andric     CmdArgs.push_back("-fno-signed-zeros");
382bdd1243dSDimitry Andric 
383bdd1243dSDimitry Andric   if (AssociativeMath && !SignedZeros)
384bdd1243dSDimitry Andric     CmdArgs.push_back("-mreassociate");
385bdd1243dSDimitry Andric 
386bdd1243dSDimitry Andric   if (ReciprocalMath)
387bdd1243dSDimitry Andric     CmdArgs.push_back("-freciprocal-math");
388e8d8bef9SDimitry Andric }
389e8d8bef9SDimitry Andric 
390480093f4SDimitry Andric void Flang::ConstructJob(Compilation &C, const JobAction &JA,
391480093f4SDimitry Andric                          const InputInfo &Output, const InputInfoList &Inputs,
392480093f4SDimitry Andric                          const ArgList &Args, const char *LinkingOutput) const {
393480093f4SDimitry Andric   const auto &TC = getToolChain();
39481ad6265SDimitry Andric   const llvm::Triple &Triple = TC.getEffectiveTriple();
39581ad6265SDimitry Andric   const std::string &TripleStr = Triple.getTriple();
396480093f4SDimitry Andric 
39781ad6265SDimitry Andric   const Driver &D = TC.getDriver();
398480093f4SDimitry Andric   ArgStringList CmdArgs;
399*06c3fb27SDimitry Andric   DiagnosticsEngine &Diags = D.getDiags();
400480093f4SDimitry Andric 
401e8d8bef9SDimitry Andric   // Invoke ourselves in -fc1 mode.
402480093f4SDimitry Andric   CmdArgs.push_back("-fc1");
403480093f4SDimitry Andric 
404e8d8bef9SDimitry Andric   // Add the "effective" target triple.
40581ad6265SDimitry Andric   CmdArgs.push_back("-triple");
40681ad6265SDimitry Andric   CmdArgs.push_back(Args.MakeArgString(TripleStr));
407480093f4SDimitry Andric 
408480093f4SDimitry Andric   if (isa<PreprocessJobAction>(JA)) {
409480093f4SDimitry Andric       CmdArgs.push_back("-E");
410480093f4SDimitry Andric   } else if (isa<CompileJobAction>(JA) || isa<BackendJobAction>(JA)) {
411480093f4SDimitry Andric     if (JA.getType() == types::TY_Nothing) {
412480093f4SDimitry Andric       CmdArgs.push_back("-fsyntax-only");
413480093f4SDimitry Andric     } else if (JA.getType() == types::TY_AST) {
414480093f4SDimitry Andric       CmdArgs.push_back("-emit-ast");
415480093f4SDimitry Andric     } else if (JA.getType() == types::TY_LLVM_IR ||
416480093f4SDimitry Andric                JA.getType() == types::TY_LTO_IR) {
417480093f4SDimitry Andric       CmdArgs.push_back("-emit-llvm");
418480093f4SDimitry Andric     } else if (JA.getType() == types::TY_LLVM_BC ||
419480093f4SDimitry Andric                JA.getType() == types::TY_LTO_BC) {
420480093f4SDimitry Andric       CmdArgs.push_back("-emit-llvm-bc");
421480093f4SDimitry Andric     } else if (JA.getType() == types::TY_PP_Asm) {
422480093f4SDimitry Andric       CmdArgs.push_back("-S");
423480093f4SDimitry Andric     } else {
424480093f4SDimitry Andric       assert(false && "Unexpected output type!");
425480093f4SDimitry Andric     }
426480093f4SDimitry Andric   } else if (isa<AssembleJobAction>(JA)) {
427480093f4SDimitry Andric     CmdArgs.push_back("-emit-obj");
428480093f4SDimitry Andric   } else {
429480093f4SDimitry Andric     assert(false && "Unexpected action class for Flang tool.");
430480093f4SDimitry Andric   }
431480093f4SDimitry Andric 
432e8d8bef9SDimitry Andric   const InputInfo &Input = Inputs[0];
433e8d8bef9SDimitry Andric   types::ID InputType = Input.getType();
434e8d8bef9SDimitry Andric 
435e8d8bef9SDimitry Andric   // Add preprocessing options like -I, -D, etc. if we are using the
436e8d8bef9SDimitry Andric   // preprocessor (i.e. skip when dealing with e.g. binary files).
437e8d8bef9SDimitry Andric   if (types::getPreprocessedType(InputType) != types::TY_INVALID)
438bdd1243dSDimitry Andric     addPreprocessingOptions(Args, CmdArgs);
439e8d8bef9SDimitry Andric 
440bdd1243dSDimitry Andric   addFortranDialectOptions(Args, CmdArgs);
441fe6060f1SDimitry Andric 
44281ad6265SDimitry Andric   // Color diagnostics are parsed by the driver directly from argv and later
44381ad6265SDimitry Andric   // re-parsed to construct this job; claim any possible color diagnostic here
44481ad6265SDimitry Andric   // to avoid warn_drv_unused_argument.
44581ad6265SDimitry Andric   Args.getLastArg(options::OPT_fcolor_diagnostics,
44681ad6265SDimitry Andric                   options::OPT_fno_color_diagnostics);
447*06c3fb27SDimitry Andric   if (Diags.getDiagnosticOptions().ShowColors)
44881ad6265SDimitry Andric     CmdArgs.push_back("-fcolor-diagnostics");
44981ad6265SDimitry Andric 
450*06c3fb27SDimitry Andric   // LTO mode is parsed by the Clang driver library.
451*06c3fb27SDimitry Andric   LTOKind LTOMode = D.getLTOMode(/* IsOffload */ false);
452*06c3fb27SDimitry Andric   assert(LTOMode != LTOK_Unknown && "Unknown LTO mode.");
453*06c3fb27SDimitry Andric   if (LTOMode == LTOK_Full)
454*06c3fb27SDimitry Andric     CmdArgs.push_back("-flto=full");
455*06c3fb27SDimitry Andric   else if (LTOMode == LTOK_Thin) {
456*06c3fb27SDimitry Andric     Diags.Report(
457*06c3fb27SDimitry Andric         Diags.getCustomDiagID(DiagnosticsEngine::Warning,
458*06c3fb27SDimitry Andric                               "the option '-flto=thin' is a work in progress"));
459*06c3fb27SDimitry Andric     CmdArgs.push_back("-flto=thin");
460*06c3fb27SDimitry Andric   }
461*06c3fb27SDimitry Andric 
462bdd1243dSDimitry Andric   // -fPIC and related options.
463bdd1243dSDimitry Andric   addPicOptions(Args, CmdArgs);
464bdd1243dSDimitry Andric 
465bdd1243dSDimitry Andric   // Floating point related options
466bdd1243dSDimitry Andric   addFloatingPointOptions(D, Args, CmdArgs);
467bdd1243dSDimitry Andric 
468bdd1243dSDimitry Andric   // Add target args, features, etc.
469bdd1243dSDimitry Andric   addTargetOptions(Args, CmdArgs);
470bdd1243dSDimitry Andric 
471*06c3fb27SDimitry Andric   // Add Codegen options
472*06c3fb27SDimitry Andric   addCodegenOptions(Args, CmdArgs);
473*06c3fb27SDimitry Andric 
474fe6060f1SDimitry Andric   // Add other compile options
475bdd1243dSDimitry Andric   addOtherOptions(Args, CmdArgs);
476fe6060f1SDimitry Andric 
477*06c3fb27SDimitry Andric   // Offloading related options
478*06c3fb27SDimitry Andric   addOffloadOptions(C, Inputs, JA, Args, CmdArgs);
479*06c3fb27SDimitry Andric 
480fe6060f1SDimitry Andric   // Forward -Xflang arguments to -fc1
481fe6060f1SDimitry Andric   Args.AddAllArgValues(CmdArgs, options::OPT_Xflang);
482fe6060f1SDimitry Andric 
48381ad6265SDimitry Andric   // Forward -mllvm options to the LLVM option parser. In practice, this means
48481ad6265SDimitry Andric   // forwarding to `-fc1` as that's where the LLVM parser is run.
48581ad6265SDimitry Andric   for (const Arg *A : Args.filtered(options::OPT_mllvm)) {
48681ad6265SDimitry Andric     A->claim();
48781ad6265SDimitry Andric     A->render(Args, CmdArgs);
48881ad6265SDimitry Andric   }
48981ad6265SDimitry Andric 
49081ad6265SDimitry Andric   for (const Arg *A : Args.filtered(options::OPT_mmlir)) {
49181ad6265SDimitry Andric     A->claim();
49281ad6265SDimitry Andric     A->render(Args, CmdArgs);
49381ad6265SDimitry Andric   }
49481ad6265SDimitry Andric 
495*06c3fb27SDimitry Andric   // Remove any unsupported gfortran diagnostic options
496*06c3fb27SDimitry Andric   for (const Arg *A : Args.filtered(options::OPT_flang_ignored_w_Group)) {
497*06c3fb27SDimitry Andric     A->claim();
498*06c3fb27SDimitry Andric     D.Diag(diag::warn_drv_unsupported_diag_option_for_flang)
499*06c3fb27SDimitry Andric         << A->getOption().getName();
500*06c3fb27SDimitry Andric   }
501*06c3fb27SDimitry Andric 
50281ad6265SDimitry Andric   // Optimization level for CodeGen.
50381ad6265SDimitry Andric   if (const Arg *A = Args.getLastArg(options::OPT_O_Group)) {
50481ad6265SDimitry Andric     if (A->getOption().matches(options::OPT_O4)) {
50581ad6265SDimitry Andric       CmdArgs.push_back("-O3");
50681ad6265SDimitry Andric       D.Diag(diag::warn_O4_is_O3);
507bdd1243dSDimitry Andric     } else if (A->getOption().matches(options::OPT_Ofast)) {
508bdd1243dSDimitry Andric       CmdArgs.push_back("-O3");
50981ad6265SDimitry Andric     } else {
51081ad6265SDimitry Andric       A->render(Args, CmdArgs);
51181ad6265SDimitry Andric     }
51281ad6265SDimitry Andric   }
51381ad6265SDimitry Andric 
514480093f4SDimitry Andric   if (Output.isFilename()) {
515480093f4SDimitry Andric     CmdArgs.push_back("-o");
516480093f4SDimitry Andric     CmdArgs.push_back(Output.getFilename());
517480093f4SDimitry Andric   } else {
518480093f4SDimitry Andric     assert(Output.isNothing() && "Invalid output.");
519480093f4SDimitry Andric   }
520480093f4SDimitry Andric 
521480093f4SDimitry Andric   assert(Input.isFilename() && "Invalid input.");
52281ad6265SDimitry Andric 
523*06c3fb27SDimitry Andric   if (Args.getLastArg(options::OPT_save_temps_EQ))
524*06c3fb27SDimitry Andric     Args.AddLastArg(CmdArgs, options::OPT_save_temps_EQ);
525*06c3fb27SDimitry Andric 
52681ad6265SDimitry Andric   addDashXForInput(Args, Input, CmdArgs);
52781ad6265SDimitry Andric 
528480093f4SDimitry Andric   CmdArgs.push_back(Input.getFilename());
529480093f4SDimitry Andric 
530e8d8bef9SDimitry Andric   // TODO: Replace flang-new with flang once the new driver replaces the
531e8d8bef9SDimitry Andric   // throwaway driver
532e8d8bef9SDimitry Andric   const char *Exec = Args.MakeArgString(D.GetProgramPath("flang-new", TC));
533e8d8bef9SDimitry Andric   C.addCommand(std::make_unique<Command>(JA, *this,
534e8d8bef9SDimitry Andric                                          ResponseFileSupport::AtFileUTF8(),
535e8d8bef9SDimitry Andric                                          Exec, CmdArgs, Inputs, Output));
536480093f4SDimitry Andric }
537480093f4SDimitry Andric 
538e8d8bef9SDimitry Andric Flang::Flang(const ToolChain &TC) : Tool("flang-new", "flang frontend", TC) {}
539480093f4SDimitry Andric 
540480093f4SDimitry Andric Flang::~Flang() {}
541