xref: /llvm-project/clang/lib/Driver/ToolChains/Flang.cpp (revision 7211bf48a62bfe3a181013f412f2fa6e112ae99f)
1 //===-- Flang.cpp - Flang+LLVM ToolChain Implementations --------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "Flang.h"
10 #include "Arch/RISCV.h"
11 #include "CommonArgs.h"
12 
13 #include "clang/Basic/CodeGenOptions.h"
14 #include "clang/Driver/Options.h"
15 #include "llvm/Frontend/Debug/Options.h"
16 #include "llvm/Support/FileSystem.h"
17 #include "llvm/Support/Path.h"
18 #include "llvm/TargetParser/Host.h"
19 #include "llvm/TargetParser/RISCVISAInfo.h"
20 #include "llvm/TargetParser/RISCVTargetParser.h"
21 
22 #include <cassert>
23 
24 using namespace clang::driver;
25 using namespace clang::driver::tools;
26 using namespace clang;
27 using namespace llvm::opt;
28 
29 /// Add -x lang to \p CmdArgs for \p Input.
30 static void addDashXForInput(const ArgList &Args, const InputInfo &Input,
31                              ArgStringList &CmdArgs) {
32   CmdArgs.push_back("-x");
33   // Map the driver type to the frontend type.
34   CmdArgs.push_back(types::getTypeName(Input.getType()));
35 }
36 
37 void Flang::addFortranDialectOptions(const ArgList &Args,
38                                      ArgStringList &CmdArgs) const {
39   Args.addAllArgs(CmdArgs, {options::OPT_ffixed_form,
40                             options::OPT_ffree_form,
41                             options::OPT_ffixed_line_length_EQ,
42                             options::OPT_fopenacc,
43                             options::OPT_finput_charset_EQ,
44                             options::OPT_fimplicit_none,
45                             options::OPT_fno_implicit_none,
46                             options::OPT_fbackslash,
47                             options::OPT_fno_backslash,
48                             options::OPT_flogical_abbreviations,
49                             options::OPT_fno_logical_abbreviations,
50                             options::OPT_fxor_operator,
51                             options::OPT_fno_xor_operator,
52                             options::OPT_falternative_parameter_statement,
53                             options::OPT_fdefault_real_8,
54                             options::OPT_fdefault_integer_8,
55                             options::OPT_fdefault_double_8,
56                             options::OPT_flarge_sizes,
57                             options::OPT_fno_automatic,
58                             options::OPT_fhermetic_module_files,
59                             options::OPT_frealloc_lhs,
60                             options::OPT_fno_realloc_lhs,
61                             options::OPT_fsave_main_program,
62                             options::OPT_fno_save_main_program});
63 }
64 
65 void Flang::addPreprocessingOptions(const ArgList &Args,
66                                     ArgStringList &CmdArgs) const {
67   Args.addAllArgs(CmdArgs,
68                   {options::OPT_P, options::OPT_D, options::OPT_U,
69                    options::OPT_I, options::OPT_cpp, options::OPT_nocpp});
70 }
71 
72 /// @C shouldLoopVersion
73 ///
74 /// Check if Loop Versioning should be enabled.
75 /// We look for the last of one of the following:
76 ///   -Ofast, -O4, -O<number> and -f[no-]version-loops-for-stride.
77 /// Loop versioning is disabled if the last option is
78 ///  -fno-version-loops-for-stride.
79 /// Loop versioning is enabled if the last option is one of:
80 ///  -floop-versioning
81 ///  -Ofast
82 ///  -O4
83 ///  -O3
84 /// For all other cases, loop versioning is is disabled.
85 ///
86 /// The gfortran compiler automatically enables the option for -O3 or -Ofast.
87 ///
88 /// @return true if loop-versioning should be enabled, otherwise false.
89 static bool shouldLoopVersion(const ArgList &Args) {
90   const Arg *LoopVersioningArg = Args.getLastArg(
91       options::OPT_Ofast, options::OPT_O, options::OPT_O4,
92       options::OPT_floop_versioning, options::OPT_fno_loop_versioning);
93   if (!LoopVersioningArg)
94     return false;
95 
96   if (LoopVersioningArg->getOption().matches(options::OPT_fno_loop_versioning))
97     return false;
98 
99   if (LoopVersioningArg->getOption().matches(options::OPT_floop_versioning))
100     return true;
101 
102   if (LoopVersioningArg->getOption().matches(options::OPT_Ofast) ||
103       LoopVersioningArg->getOption().matches(options::OPT_O4))
104     return true;
105 
106   if (LoopVersioningArg->getOption().matches(options::OPT_O)) {
107     StringRef S(LoopVersioningArg->getValue());
108     unsigned OptLevel = 0;
109     // Note -Os or Oz woould "fail" here, so return false. Which is the
110     // desiered behavior.
111     if (S.getAsInteger(10, OptLevel))
112       return false;
113 
114     return OptLevel > 2;
115   }
116 
117   llvm_unreachable("We should not end up here");
118   return false;
119 }
120 
121 void Flang::addOtherOptions(const ArgList &Args, ArgStringList &CmdArgs) const {
122   Args.addAllArgs(CmdArgs,
123                   {options::OPT_module_dir, options::OPT_fdebug_module_writer,
124                    options::OPT_fintrinsic_modules_path, options::OPT_pedantic,
125                    options::OPT_std_EQ, options::OPT_W_Joined,
126                    options::OPT_fconvert_EQ, options::OPT_fpass_plugin_EQ,
127                    options::OPT_funderscoring, options::OPT_fno_underscoring,
128                    options::OPT_funsigned, options::OPT_fno_unsigned});
129 
130   llvm::codegenoptions::DebugInfoKind DebugInfoKind;
131   if (Args.hasArg(options::OPT_gN_Group)) {
132     Arg *gNArg = Args.getLastArg(options::OPT_gN_Group);
133     DebugInfoKind = debugLevelToInfoKind(*gNArg);
134   } else if (Args.hasArg(options::OPT_g_Flag)) {
135     DebugInfoKind = llvm::codegenoptions::FullDebugInfo;
136   } else {
137     DebugInfoKind = llvm::codegenoptions::NoDebugInfo;
138   }
139   addDebugInfoKind(CmdArgs, DebugInfoKind);
140 }
141 
142 void Flang::addCodegenOptions(const ArgList &Args,
143                               ArgStringList &CmdArgs) const {
144   Arg *stackArrays =
145       Args.getLastArg(options::OPT_Ofast, options::OPT_fstack_arrays,
146                       options::OPT_fno_stack_arrays);
147   if (stackArrays &&
148       !stackArrays->getOption().matches(options::OPT_fno_stack_arrays))
149     CmdArgs.push_back("-fstack-arrays");
150 
151   if (shouldLoopVersion(Args))
152     CmdArgs.push_back("-fversion-loops-for-stride");
153 
154   Args.addAllArgs(CmdArgs,
155                   {options::OPT_flang_experimental_hlfir,
156                    options::OPT_flang_deprecated_no_hlfir,
157                    options::OPT_fno_ppc_native_vec_elem_order,
158                    options::OPT_fppc_native_vec_elem_order,
159                    options::OPT_finit_global_zero,
160                    options::OPT_fno_init_global_zero, options::OPT_ftime_report,
161                    options::OPT_ftime_report_EQ, options::OPT_funroll_loops,
162                    options::OPT_fno_unroll_loops});
163 }
164 
165 void Flang::addPicOptions(const ArgList &Args, ArgStringList &CmdArgs) const {
166   // ParsePICArgs parses -fPIC/-fPIE and their variants and returns a tuple of
167   // (RelocationModel, PICLevel, IsPIE).
168   llvm::Reloc::Model RelocationModel;
169   unsigned PICLevel;
170   bool IsPIE;
171   std::tie(RelocationModel, PICLevel, IsPIE) =
172       ParsePICArgs(getToolChain(), Args);
173 
174   if (auto *RMName = RelocationModelName(RelocationModel)) {
175     CmdArgs.push_back("-mrelocation-model");
176     CmdArgs.push_back(RMName);
177   }
178   if (PICLevel > 0) {
179     CmdArgs.push_back("-pic-level");
180     CmdArgs.push_back(PICLevel == 1 ? "1" : "2");
181     if (IsPIE)
182       CmdArgs.push_back("-pic-is-pie");
183   }
184 }
185 
186 void Flang::AddAArch64TargetArgs(const ArgList &Args,
187                                  ArgStringList &CmdArgs) const {
188   // Handle -msve_vector_bits=<bits>
189   if (Arg *A = Args.getLastArg(options::OPT_msve_vector_bits_EQ)) {
190     StringRef Val = A->getValue();
191     const Driver &D = getToolChain().getDriver();
192     if (Val == "128" || Val == "256" || Val == "512" || Val == "1024" ||
193         Val == "2048" || Val == "128+" || Val == "256+" || Val == "512+" ||
194         Val == "1024+" || Val == "2048+") {
195       unsigned Bits = 0;
196       if (!Val.consume_back("+")) {
197         [[maybe_unused]] bool Invalid = Val.getAsInteger(10, Bits);
198         assert(!Invalid && "Failed to parse value");
199         CmdArgs.push_back(
200             Args.MakeArgString("-mvscale-max=" + llvm::Twine(Bits / 128)));
201       }
202 
203       [[maybe_unused]] bool Invalid = Val.getAsInteger(10, Bits);
204       assert(!Invalid && "Failed to parse value");
205       CmdArgs.push_back(
206           Args.MakeArgString("-mvscale-min=" + llvm::Twine(Bits / 128)));
207       // Silently drop requests for vector-length agnostic code as it's implied.
208     } else if (Val != "scalable")
209       // Handle the unsupported values passed to msve-vector-bits.
210       D.Diag(diag::err_drv_unsupported_option_argument)
211           << A->getSpelling() << Val;
212   }
213 }
214 
215 void Flang::AddLoongArch64TargetArgs(const ArgList &Args,
216                                      ArgStringList &CmdArgs) const {
217   const Driver &D = getToolChain().getDriver();
218   // Currently, flang only support `-mabi=lp64d` in LoongArch64.
219   if (const Arg *A = Args.getLastArg(options::OPT_mabi_EQ)) {
220     StringRef V = A->getValue();
221     if (V != "lp64d") {
222       D.Diag(diag::err_drv_argument_not_allowed_with) << "-mabi" << V;
223     }
224   }
225 
226   if (const Arg *A = Args.getLastArg(options::OPT_mannotate_tablejump,
227                                      options::OPT_mno_annotate_tablejump)) {
228     if (A->getOption().matches(options::OPT_mannotate_tablejump)) {
229       CmdArgs.push_back("-mllvm");
230       CmdArgs.push_back("-loongarch-annotate-tablejump");
231     }
232   }
233 }
234 
235 void Flang::AddPPCTargetArgs(const ArgList &Args,
236                              ArgStringList &CmdArgs) const {
237   const Driver &D = getToolChain().getDriver();
238   bool VecExtabi = false;
239 
240   if (const Arg *A = Args.getLastArg(options::OPT_mabi_EQ)) {
241     StringRef V = A->getValue();
242     if (V == "vec-extabi")
243       VecExtabi = true;
244     else if (V == "vec-default")
245       VecExtabi = false;
246     else
247       D.Diag(diag::err_drv_unsupported_option_argument)
248           << A->getSpelling() << V;
249   }
250 
251   const llvm::Triple &T = getToolChain().getTriple();
252   if (VecExtabi) {
253     if (!T.isOSAIX()) {
254       D.Diag(diag::err_drv_unsupported_opt_for_target)
255           << "-mabi=vec-extabi" << T.str();
256     }
257     CmdArgs.push_back("-mabi=vec-extabi");
258   }
259 }
260 
261 void Flang::AddRISCVTargetArgs(const ArgList &Args,
262                                ArgStringList &CmdArgs) const {
263   const llvm::Triple &Triple = getToolChain().getTriple();
264   // Handle -mrvv-vector-bits=<bits>
265   if (Arg *A = Args.getLastArg(options::OPT_mrvv_vector_bits_EQ)) {
266     StringRef Val = A->getValue();
267     const Driver &D = getToolChain().getDriver();
268 
269     // Get minimum VLen from march.
270     unsigned MinVLen = 0;
271     std::string Arch = riscv::getRISCVArch(Args, Triple);
272     auto ISAInfo = llvm::RISCVISAInfo::parseArchString(
273         Arch, /*EnableExperimentalExtensions*/ true);
274     // Ignore parsing error.
275     if (!errorToBool(ISAInfo.takeError()))
276       MinVLen = (*ISAInfo)->getMinVLen();
277 
278     // If the value is "zvl", use MinVLen from march. Otherwise, try to parse
279     // as integer as long as we have a MinVLen.
280     unsigned Bits = 0;
281     if (Val == "zvl" && MinVLen >= llvm::RISCV::RVVBitsPerBlock) {
282       Bits = MinVLen;
283     } else if (!Val.getAsInteger(10, Bits)) {
284       // Only accept power of 2 values beteen RVVBitsPerBlock and 65536 that
285       // at least MinVLen.
286       if (Bits < MinVLen || Bits < llvm::RISCV::RVVBitsPerBlock ||
287           Bits > 65536 || !llvm::isPowerOf2_32(Bits))
288         Bits = 0;
289     }
290 
291     // If we got a valid value try to use it.
292     if (Bits != 0) {
293       unsigned VScaleMin = Bits / llvm::RISCV::RVVBitsPerBlock;
294       CmdArgs.push_back(
295           Args.MakeArgString("-mvscale-max=" + llvm::Twine(VScaleMin)));
296       CmdArgs.push_back(
297           Args.MakeArgString("-mvscale-min=" + llvm::Twine(VScaleMin)));
298     } else if (Val != "scalable") {
299       // Handle the unsupported values passed to mrvv-vector-bits.
300       D.Diag(diag::err_drv_unsupported_option_argument)
301           << A->getSpelling() << Val;
302     }
303   }
304 }
305 
306 void Flang::AddX86_64TargetArgs(const ArgList &Args,
307                                 ArgStringList &CmdArgs) const {
308   if (Arg *A = Args.getLastArg(options::OPT_masm_EQ)) {
309     StringRef Value = A->getValue();
310     if (Value == "intel" || Value == "att") {
311       CmdArgs.push_back(Args.MakeArgString("-mllvm"));
312       CmdArgs.push_back(Args.MakeArgString("-x86-asm-syntax=" + Value));
313     } else {
314       getToolChain().getDriver().Diag(diag::err_drv_unsupported_option_argument)
315           << A->getSpelling() << Value;
316     }
317   }
318 }
319 
320 static void addVSDefines(const ToolChain &TC, const ArgList &Args,
321                          ArgStringList &CmdArgs) {
322 
323   unsigned ver = 0;
324   const VersionTuple vt = TC.computeMSVCVersion(nullptr, Args);
325   ver = vt.getMajor() * 10000000 + vt.getMinor().value_or(0) * 100000 +
326         vt.getSubminor().value_or(0);
327   CmdArgs.push_back(Args.MakeArgString("-D_MSC_VER=" + Twine(ver / 100000)));
328   CmdArgs.push_back(Args.MakeArgString("-D_MSC_FULL_VER=" + Twine(ver)));
329   CmdArgs.push_back(Args.MakeArgString("-D_WIN32"));
330 
331   const llvm::Triple &triple = TC.getTriple();
332   if (triple.isAArch64()) {
333     CmdArgs.push_back("-D_M_ARM64=1");
334   } else if (triple.isX86() && triple.isArch32Bit()) {
335     CmdArgs.push_back("-D_M_IX86=600");
336   } else if (triple.isX86() && triple.isArch64Bit()) {
337     CmdArgs.push_back("-D_M_X64=100");
338   } else {
339     llvm_unreachable(
340         "Flang on Windows only supports X86_32, X86_64 and AArch64");
341   }
342 }
343 
344 static void processVSRuntimeLibrary(const ToolChain &TC, const ArgList &Args,
345                                     ArgStringList &CmdArgs) {
346   assert(TC.getTriple().isKnownWindowsMSVCEnvironment() &&
347          "can only add VS runtime library on Windows!");
348   // if -fno-fortran-main has been passed, skip linking Fortran_main.a
349   if (TC.getTriple().isKnownWindowsMSVCEnvironment()) {
350     CmdArgs.push_back(Args.MakeArgString(
351         "--dependent-lib=" + TC.getCompilerRTBasename(Args, "builtins")));
352   }
353   unsigned RTOptionID = options::OPT__SLASH_MT;
354   if (auto *rtl = Args.getLastArg(options::OPT_fms_runtime_lib_EQ)) {
355     RTOptionID = llvm::StringSwitch<unsigned>(rtl->getValue())
356                      .Case("static", options::OPT__SLASH_MT)
357                      .Case("static_dbg", options::OPT__SLASH_MTd)
358                      .Case("dll", options::OPT__SLASH_MD)
359                      .Case("dll_dbg", options::OPT__SLASH_MDd)
360                      .Default(options::OPT__SLASH_MT);
361   }
362   switch (RTOptionID) {
363   case options::OPT__SLASH_MT:
364     CmdArgs.push_back("-D_MT");
365     CmdArgs.push_back("--dependent-lib=libcmt");
366     CmdArgs.push_back("--dependent-lib=FortranRuntime.static.lib");
367     CmdArgs.push_back("--dependent-lib=FortranDecimal.static.lib");
368     break;
369   case options::OPT__SLASH_MTd:
370     CmdArgs.push_back("-D_MT");
371     CmdArgs.push_back("-D_DEBUG");
372     CmdArgs.push_back("--dependent-lib=libcmtd");
373     CmdArgs.push_back("--dependent-lib=FortranRuntime.static_dbg.lib");
374     CmdArgs.push_back("--dependent-lib=FortranDecimal.static_dbg.lib");
375     break;
376   case options::OPT__SLASH_MD:
377     CmdArgs.push_back("-D_MT");
378     CmdArgs.push_back("-D_DLL");
379     CmdArgs.push_back("--dependent-lib=msvcrt");
380     CmdArgs.push_back("--dependent-lib=FortranRuntime.dynamic.lib");
381     CmdArgs.push_back("--dependent-lib=FortranDecimal.dynamic.lib");
382     break;
383   case options::OPT__SLASH_MDd:
384     CmdArgs.push_back("-D_MT");
385     CmdArgs.push_back("-D_DEBUG");
386     CmdArgs.push_back("-D_DLL");
387     CmdArgs.push_back("--dependent-lib=msvcrtd");
388     CmdArgs.push_back("--dependent-lib=FortranRuntime.dynamic_dbg.lib");
389     CmdArgs.push_back("--dependent-lib=FortranDecimal.dynamic_dbg.lib");
390     break;
391   }
392 }
393 
394 void Flang::AddAMDGPUTargetArgs(const ArgList &Args,
395                                 ArgStringList &CmdArgs) const {
396   if (Arg *A = Args.getLastArg(options::OPT_mcode_object_version_EQ)) {
397     StringRef Val = A->getValue();
398     CmdArgs.push_back(Args.MakeArgString("-mcode-object-version=" + Val));
399   }
400 
401   const ToolChain &TC = getToolChain();
402   TC.addClangTargetOptions(Args, CmdArgs, Action::OffloadKind::OFK_OpenMP);
403 }
404 
405 void Flang::addTargetOptions(const ArgList &Args,
406                              ArgStringList &CmdArgs) const {
407   const ToolChain &TC = getToolChain();
408   const llvm::Triple &Triple = TC.getEffectiveTriple();
409   const Driver &D = TC.getDriver();
410 
411   std::string CPU = getCPUName(D, Args, Triple);
412   if (!CPU.empty()) {
413     CmdArgs.push_back("-target-cpu");
414     CmdArgs.push_back(Args.MakeArgString(CPU));
415   }
416 
417   addOutlineAtomicsArgs(D, getToolChain(), Args, CmdArgs, Triple);
418 
419   // Add the target features.
420   switch (TC.getArch()) {
421   default:
422     break;
423   case llvm::Triple::aarch64:
424     getTargetFeatures(D, Triple, Args, CmdArgs, /*ForAs*/ false);
425     AddAArch64TargetArgs(Args, CmdArgs);
426     break;
427 
428   case llvm::Triple::r600:
429   case llvm::Triple::amdgcn:
430     getTargetFeatures(D, Triple, Args, CmdArgs, /*ForAs*/ false);
431     AddAMDGPUTargetArgs(Args, CmdArgs);
432     break;
433   case llvm::Triple::riscv64:
434     getTargetFeatures(D, Triple, Args, CmdArgs, /*ForAs*/ false);
435     AddRISCVTargetArgs(Args, CmdArgs);
436     break;
437   case llvm::Triple::x86_64:
438     getTargetFeatures(D, Triple, Args, CmdArgs, /*ForAs*/ false);
439     AddX86_64TargetArgs(Args, CmdArgs);
440     break;
441   case llvm::Triple::ppc:
442   case llvm::Triple::ppc64:
443   case llvm::Triple::ppc64le:
444     AddPPCTargetArgs(Args, CmdArgs);
445     break;
446   case llvm::Triple::loongarch64:
447     getTargetFeatures(D, Triple, Args, CmdArgs, /*ForAs*/ false);
448     AddLoongArch64TargetArgs(Args, CmdArgs);
449     break;
450   }
451 
452   if (Arg *A = Args.getLastArg(options::OPT_fveclib)) {
453     StringRef Name = A->getValue();
454     if (Name == "SVML") {
455       if (Triple.getArch() != llvm::Triple::x86 &&
456           Triple.getArch() != llvm::Triple::x86_64)
457         D.Diag(diag::err_drv_unsupported_opt_for_target)
458             << Name << Triple.getArchName();
459     } else if (Name == "LIBMVEC-X86") {
460       if (Triple.getArch() != llvm::Triple::x86 &&
461           Triple.getArch() != llvm::Triple::x86_64)
462         D.Diag(diag::err_drv_unsupported_opt_for_target)
463             << Name << Triple.getArchName();
464     } else if (Name == "SLEEF" || Name == "ArmPL") {
465       if (Triple.getArch() != llvm::Triple::aarch64 &&
466           Triple.getArch() != llvm::Triple::aarch64_be)
467         D.Diag(diag::err_drv_unsupported_opt_for_target)
468             << Name << Triple.getArchName();
469     }
470 
471     if (Triple.isOSDarwin()) {
472       // flang doesn't currently suport nostdlib, nodefaultlibs. Adding these
473       // here incase they are added someday
474       if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
475         if (A->getValue() == StringRef{"Accelerate"}) {
476           CmdArgs.push_back("-framework");
477           CmdArgs.push_back("Accelerate");
478         }
479       }
480     }
481     A->render(Args, CmdArgs);
482   }
483 
484   if (Triple.isKnownWindowsMSVCEnvironment()) {
485     processVSRuntimeLibrary(TC, Args, CmdArgs);
486     addVSDefines(TC, Args, CmdArgs);
487   }
488 
489   // TODO: Add target specific flags, ABI, mtune option etc.
490   if (const Arg *A = Args.getLastArg(options::OPT_mtune_EQ)) {
491     CmdArgs.push_back("-tune-cpu");
492     if (A->getValue() == StringRef{"native"})
493       CmdArgs.push_back(Args.MakeArgString(llvm::sys::getHostCPUName()));
494     else
495       CmdArgs.push_back(A->getValue());
496   }
497 }
498 
499 void Flang::addOffloadOptions(Compilation &C, const InputInfoList &Inputs,
500                               const JobAction &JA, const ArgList &Args,
501                               ArgStringList &CmdArgs) const {
502   bool IsOpenMPDevice = JA.isDeviceOffloading(Action::OFK_OpenMP);
503   bool IsHostOffloadingAction = JA.isHostOffloading(Action::OFK_OpenMP) ||
504                                 JA.isHostOffloading(C.getActiveOffloadKinds());
505 
506   // Skips the primary input file, which is the input file that the compilation
507   // proccess will be executed upon (e.g. the host bitcode file) and
508   // adds other secondary input (e.g. device bitcode files for embedding to the
509   // -fembed-offload-object argument or the host IR file for proccessing
510   // during device compilation to the fopenmp-host-ir-file-path argument via
511   // OpenMPDeviceInput). This is condensed logic from the ConstructJob
512   // function inside of the Clang driver for pushing on further input arguments
513   // needed for offloading during various phases of compilation.
514   for (size_t i = 1; i < Inputs.size(); ++i) {
515     if (Inputs[i].getType() == types::TY_Nothing) {
516       // contains nothing, so it's skippable
517     } else if (IsHostOffloadingAction) {
518       CmdArgs.push_back(
519           Args.MakeArgString("-fembed-offload-object=" +
520                              getToolChain().getInputFilename(Inputs[i])));
521     } else if (IsOpenMPDevice) {
522       if (Inputs[i].getFilename()) {
523         CmdArgs.push_back("-fopenmp-host-ir-file-path");
524         CmdArgs.push_back(Args.MakeArgString(Inputs[i].getFilename()));
525       } else {
526         llvm_unreachable("missing openmp host-ir file for device offloading");
527       }
528     } else {
529       llvm_unreachable(
530           "unexpectedly given multiple inputs or given unknown input");
531     }
532   }
533 
534   if (IsOpenMPDevice) {
535     // -fopenmp-is-target-device is passed along to tell the frontend that it is
536     // generating code for a device, so that only the relevant code is emitted.
537     CmdArgs.push_back("-fopenmp-is-target-device");
538 
539     // When in OpenMP offloading mode, enable debugging on the device.
540     Args.AddAllArgs(CmdArgs, options::OPT_fopenmp_target_debug_EQ);
541     if (Args.hasFlag(options::OPT_fopenmp_target_debug,
542                      options::OPT_fno_openmp_target_debug, /*Default=*/false))
543       CmdArgs.push_back("-fopenmp-target-debug");
544 
545     // When in OpenMP offloading mode, forward assumptions information about
546     // thread and team counts in the device.
547     if (Args.hasFlag(options::OPT_fopenmp_assume_teams_oversubscription,
548                      options::OPT_fno_openmp_assume_teams_oversubscription,
549                      /*Default=*/false))
550       CmdArgs.push_back("-fopenmp-assume-teams-oversubscription");
551     if (Args.hasFlag(options::OPT_fopenmp_assume_threads_oversubscription,
552                      options::OPT_fno_openmp_assume_threads_oversubscription,
553                      /*Default=*/false))
554       CmdArgs.push_back("-fopenmp-assume-threads-oversubscription");
555     if (Args.hasArg(options::OPT_fopenmp_assume_no_thread_state))
556       CmdArgs.push_back("-fopenmp-assume-no-thread-state");
557     if (Args.hasArg(options::OPT_fopenmp_assume_no_nested_parallelism))
558       CmdArgs.push_back("-fopenmp-assume-no-nested-parallelism");
559     if (Args.hasArg(options::OPT_nogpulib))
560       CmdArgs.push_back("-nogpulib");
561   }
562 
563   addOpenMPHostOffloadingArgs(C, JA, Args, CmdArgs);
564 }
565 
566 static void addFloatingPointOptions(const Driver &D, const ArgList &Args,
567                                     ArgStringList &CmdArgs) {
568   StringRef FPContract;
569   bool HonorINFs = true;
570   bool HonorNaNs = true;
571   bool ApproxFunc = false;
572   bool SignedZeros = true;
573   bool AssociativeMath = false;
574   bool ReciprocalMath = false;
575 
576   if (const Arg *A = Args.getLastArg(options::OPT_ffp_contract)) {
577     const StringRef Val = A->getValue();
578     if (Val == "fast" || Val == "off") {
579       FPContract = Val;
580     } else if (Val == "on") {
581       // Warn instead of error because users might have makefiles written for
582       // gfortran (which accepts -ffp-contract=on)
583       D.Diag(diag::warn_drv_unsupported_option_for_flang)
584           << Val << A->getOption().getName() << "off";
585       FPContract = "off";
586     } else
587       // Clang's "fast-honor-pragmas" option is not supported because it is
588       // non-standard
589       D.Diag(diag::err_drv_unsupported_option_argument)
590           << A->getSpelling() << Val;
591   }
592 
593   for (const Arg *A : Args) {
594     auto optId = A->getOption().getID();
595     switch (optId) {
596     // if this isn't an FP option, skip the claim below
597     default:
598       continue;
599 
600     case options::OPT_fhonor_infinities:
601       HonorINFs = true;
602       break;
603     case options::OPT_fno_honor_infinities:
604       HonorINFs = false;
605       break;
606     case options::OPT_fhonor_nans:
607       HonorNaNs = true;
608       break;
609     case options::OPT_fno_honor_nans:
610       HonorNaNs = false;
611       break;
612     case options::OPT_fapprox_func:
613       ApproxFunc = true;
614       break;
615     case options::OPT_fno_approx_func:
616       ApproxFunc = false;
617       break;
618     case options::OPT_fsigned_zeros:
619       SignedZeros = true;
620       break;
621     case options::OPT_fno_signed_zeros:
622       SignedZeros = false;
623       break;
624     case options::OPT_fassociative_math:
625       AssociativeMath = true;
626       break;
627     case options::OPT_fno_associative_math:
628       AssociativeMath = false;
629       break;
630     case options::OPT_freciprocal_math:
631       ReciprocalMath = true;
632       break;
633     case options::OPT_fno_reciprocal_math:
634       ReciprocalMath = false;
635       break;
636     case options::OPT_Ofast:
637       [[fallthrough]];
638     case options::OPT_ffast_math:
639       HonorINFs = false;
640       HonorNaNs = false;
641       AssociativeMath = true;
642       ReciprocalMath = true;
643       ApproxFunc = true;
644       SignedZeros = false;
645       FPContract = "fast";
646       break;
647     case options::OPT_fno_fast_math:
648       HonorINFs = true;
649       HonorNaNs = true;
650       AssociativeMath = false;
651       ReciprocalMath = false;
652       ApproxFunc = false;
653       SignedZeros = true;
654       // -fno-fast-math should undo -ffast-math so I return FPContract to the
655       // default. It is important to check it is "fast" (the default) so that
656       // --ffp-contract=off -fno-fast-math --> -ffp-contract=off
657       if (FPContract == "fast")
658         FPContract = "";
659       break;
660     }
661 
662     // If we handled this option claim it
663     A->claim();
664   }
665 
666   if (!HonorINFs && !HonorNaNs && AssociativeMath && ReciprocalMath &&
667       ApproxFunc && !SignedZeros &&
668       (FPContract == "fast" || FPContract.empty())) {
669     CmdArgs.push_back("-ffast-math");
670     return;
671   }
672 
673   if (!FPContract.empty())
674     CmdArgs.push_back(Args.MakeArgString("-ffp-contract=" + FPContract));
675 
676   if (!HonorINFs)
677     CmdArgs.push_back("-menable-no-infs");
678 
679   if (!HonorNaNs)
680     CmdArgs.push_back("-menable-no-nans");
681 
682   if (ApproxFunc)
683     CmdArgs.push_back("-fapprox-func");
684 
685   if (!SignedZeros)
686     CmdArgs.push_back("-fno-signed-zeros");
687 
688   if (AssociativeMath && !SignedZeros)
689     CmdArgs.push_back("-mreassociate");
690 
691   if (ReciprocalMath)
692     CmdArgs.push_back("-freciprocal-math");
693 }
694 
695 static void renderRemarksOptions(const ArgList &Args, ArgStringList &CmdArgs,
696                                  const InputInfo &Input) {
697   StringRef Format = "yaml";
698   if (const Arg *A = Args.getLastArg(options::OPT_fsave_optimization_record_EQ))
699     Format = A->getValue();
700 
701   CmdArgs.push_back("-opt-record-file");
702 
703   const Arg *A = Args.getLastArg(options::OPT_foptimization_record_file_EQ);
704   if (A) {
705     CmdArgs.push_back(A->getValue());
706   } else {
707     SmallString<128> F;
708 
709     if (Args.hasArg(options::OPT_c) || Args.hasArg(options::OPT_S)) {
710       if (Arg *FinalOutput = Args.getLastArg(options::OPT_o))
711         F = FinalOutput->getValue();
712     }
713 
714     if (F.empty()) {
715       // Use the input filename.
716       F = llvm::sys::path::stem(Input.getBaseInput());
717     }
718 
719     SmallString<32> Extension;
720     Extension += "opt.";
721     Extension += Format;
722 
723     llvm::sys::path::replace_extension(F, Extension);
724     CmdArgs.push_back(Args.MakeArgString(F));
725   }
726 
727   if (const Arg *A =
728           Args.getLastArg(options::OPT_foptimization_record_passes_EQ)) {
729     CmdArgs.push_back("-opt-record-passes");
730     CmdArgs.push_back(A->getValue());
731   }
732 
733   if (!Format.empty()) {
734     CmdArgs.push_back("-opt-record-format");
735     CmdArgs.push_back(Format.data());
736   }
737 }
738 
739 void Flang::ConstructJob(Compilation &C, const JobAction &JA,
740                          const InputInfo &Output, const InputInfoList &Inputs,
741                          const ArgList &Args, const char *LinkingOutput) const {
742   const auto &TC = getToolChain();
743   const llvm::Triple &Triple = TC.getEffectiveTriple();
744   const std::string &TripleStr = Triple.getTriple();
745 
746   const Driver &D = TC.getDriver();
747   ArgStringList CmdArgs;
748   DiagnosticsEngine &Diags = D.getDiags();
749 
750   // Invoke ourselves in -fc1 mode.
751   CmdArgs.push_back("-fc1");
752 
753   // Add the "effective" target triple.
754   CmdArgs.push_back("-triple");
755   CmdArgs.push_back(Args.MakeArgString(TripleStr));
756 
757   if (isa<PreprocessJobAction>(JA)) {
758     CmdArgs.push_back("-E");
759     if (Args.getLastArg(options::OPT_dM)) {
760       CmdArgs.push_back("-dM");
761     }
762   } else if (isa<CompileJobAction>(JA) || isa<BackendJobAction>(JA)) {
763     if (JA.getType() == types::TY_Nothing) {
764       CmdArgs.push_back("-fsyntax-only");
765     } else if (JA.getType() == types::TY_AST) {
766       CmdArgs.push_back("-emit-ast");
767     } else if (JA.getType() == types::TY_LLVM_IR ||
768                JA.getType() == types::TY_LTO_IR) {
769       CmdArgs.push_back("-emit-llvm");
770     } else if (JA.getType() == types::TY_LLVM_BC ||
771                JA.getType() == types::TY_LTO_BC) {
772       CmdArgs.push_back("-emit-llvm-bc");
773     } else if (JA.getType() == types::TY_PP_Asm) {
774       CmdArgs.push_back("-S");
775     } else {
776       assert(false && "Unexpected output type!");
777     }
778   } else if (isa<AssembleJobAction>(JA)) {
779     CmdArgs.push_back("-emit-obj");
780   } else if (isa<PrecompileJobAction>(JA)) {
781     // The precompile job action is only needed for options such as -mcpu=help.
782     // Those will already have been handled by the fc1 driver.
783   } else {
784     assert(false && "Unexpected action class for Flang tool.");
785   }
786 
787   const InputInfo &Input = Inputs[0];
788   types::ID InputType = Input.getType();
789 
790   // Add preprocessing options like -I, -D, etc. if we are using the
791   // preprocessor (i.e. skip when dealing with e.g. binary files).
792   if (types::getPreprocessedType(InputType) != types::TY_INVALID)
793     addPreprocessingOptions(Args, CmdArgs);
794 
795   addFortranDialectOptions(Args, CmdArgs);
796 
797   // 'flang -E' always produces output that is suitable for use as fixed form
798   // Fortran. However it is only valid free form source if the original is also
799   // free form.
800   if (InputType == types::TY_PP_Fortran &&
801       !Args.getLastArg(options::OPT_ffixed_form, options::OPT_ffree_form))
802     CmdArgs.push_back("-ffixed-form");
803 
804   handleColorDiagnosticsArgs(D, Args, CmdArgs);
805 
806   // LTO mode is parsed by the Clang driver library.
807   LTOKind LTOMode = D.getLTOMode();
808   assert(LTOMode != LTOK_Unknown && "Unknown LTO mode.");
809   if (LTOMode == LTOK_Full)
810     CmdArgs.push_back("-flto=full");
811   else if (LTOMode == LTOK_Thin) {
812     Diags.Report(
813         Diags.getCustomDiagID(DiagnosticsEngine::Warning,
814                               "the option '-flto=thin' is a work in progress"));
815     CmdArgs.push_back("-flto=thin");
816   }
817 
818   // -fPIC and related options.
819   addPicOptions(Args, CmdArgs);
820 
821   // Floating point related options
822   addFloatingPointOptions(D, Args, CmdArgs);
823 
824   // Add target args, features, etc.
825   addTargetOptions(Args, CmdArgs);
826 
827   llvm::Reloc::Model RelocationModel =
828       std::get<0>(ParsePICArgs(getToolChain(), Args));
829   // Add MCModel information
830   addMCModel(D, Args, Triple, RelocationModel, CmdArgs);
831 
832   // Add Codegen options
833   addCodegenOptions(Args, CmdArgs);
834 
835   // Add R Group options
836   Args.AddAllArgs(CmdArgs, options::OPT_R_Group);
837 
838   // Remarks can be enabled with any of the `-f.*optimization-record.*` flags.
839   if (willEmitRemarks(Args))
840     renderRemarksOptions(Args, CmdArgs, Input);
841 
842   // Add other compile options
843   addOtherOptions(Args, CmdArgs);
844 
845   // Disable all warnings
846   // TODO: Handle interactions between -w, -pedantic, -Wall, -WOption
847   Args.AddLastArg(CmdArgs, options::OPT_w);
848 
849   // Forward flags for OpenMP. We don't do this if the current action is an
850   // device offloading action other than OpenMP.
851   if (Args.hasFlag(options::OPT_fopenmp, options::OPT_fopenmp_EQ,
852                    options::OPT_fno_openmp, false) &&
853       (JA.isDeviceOffloading(Action::OFK_None) ||
854        JA.isDeviceOffloading(Action::OFK_OpenMP))) {
855     switch (D.getOpenMPRuntime(Args)) {
856     case Driver::OMPRT_OMP:
857     case Driver::OMPRT_IOMP5:
858       // Clang can generate useful OpenMP code for these two runtime libraries.
859       CmdArgs.push_back("-fopenmp");
860       Args.AddAllArgs(CmdArgs, options::OPT_fopenmp_version_EQ);
861 
862       if (Args.hasArg(options::OPT_fopenmp_force_usm))
863         CmdArgs.push_back("-fopenmp-force-usm");
864       // TODO: OpenMP support isn't "done" yet, so for now we warn that it
865       // is experimental.
866       D.Diag(diag::warn_openmp_experimental);
867 
868       // FIXME: Clang supports a whole bunch more flags here.
869       break;
870     default:
871       // By default, if Clang doesn't know how to generate useful OpenMP code
872       // for a specific runtime library, we just don't pass the '-fopenmp' flag
873       // down to the actual compilation.
874       // FIXME: It would be better to have a mode which *only* omits IR
875       // generation based on the OpenMP support so that we get consistent
876       // semantic analysis, etc.
877       const Arg *A = Args.getLastArg(options::OPT_fopenmp_EQ);
878       D.Diag(diag::warn_drv_unsupported_openmp_library)
879           << A->getSpelling() << A->getValue();
880       break;
881     }
882   }
883 
884   // Pass the path to compiler resource files.
885   CmdArgs.push_back("-resource-dir");
886   CmdArgs.push_back(D.ResourceDir.c_str());
887 
888   // Offloading related options
889   addOffloadOptions(C, Inputs, JA, Args, CmdArgs);
890 
891   // Forward -Xflang arguments to -fc1
892   Args.AddAllArgValues(CmdArgs, options::OPT_Xflang);
893 
894   CodeGenOptions::FramePointerKind FPKeepKind =
895       getFramePointerKind(Args, Triple);
896 
897   const char *FPKeepKindStr = nullptr;
898   switch (FPKeepKind) {
899   case CodeGenOptions::FramePointerKind::None:
900     FPKeepKindStr = "-mframe-pointer=none";
901     break;
902   case CodeGenOptions::FramePointerKind::Reserved:
903     FPKeepKindStr = "-mframe-pointer=reserved";
904     break;
905   case CodeGenOptions::FramePointerKind::NonLeaf:
906     FPKeepKindStr = "-mframe-pointer=non-leaf";
907     break;
908   case CodeGenOptions::FramePointerKind::All:
909     FPKeepKindStr = "-mframe-pointer=all";
910     break;
911   }
912   assert(FPKeepKindStr && "unknown FramePointerKind");
913   CmdArgs.push_back(FPKeepKindStr);
914 
915   // Forward -mllvm options to the LLVM option parser. In practice, this means
916   // forwarding to `-fc1` as that's where the LLVM parser is run.
917   for (const Arg *A : Args.filtered(options::OPT_mllvm)) {
918     A->claim();
919     A->render(Args, CmdArgs);
920   }
921 
922   for (const Arg *A : Args.filtered(options::OPT_mmlir)) {
923     A->claim();
924     A->render(Args, CmdArgs);
925   }
926 
927   // Remove any unsupported gfortran diagnostic options
928   for (const Arg *A : Args.filtered(options::OPT_flang_ignored_w_Group)) {
929     A->claim();
930     D.Diag(diag::warn_drv_unsupported_diag_option_for_flang)
931         << A->getOption().getName();
932   }
933 
934   // Optimization level for CodeGen.
935   if (const Arg *A = Args.getLastArg(options::OPT_O_Group)) {
936     if (A->getOption().matches(options::OPT_O4)) {
937       CmdArgs.push_back("-O3");
938       D.Diag(diag::warn_O4_is_O3);
939     } else if (A->getOption().matches(options::OPT_Ofast)) {
940       CmdArgs.push_back("-O3");
941       D.Diag(diag::warn_drv_deprecated_arg_ofast_for_flang);
942     } else {
943       A->render(Args, CmdArgs);
944     }
945   }
946 
947   renderCommonIntegerOverflowOptions(Args, CmdArgs);
948 
949   assert((Output.isFilename() || Output.isNothing()) && "Invalid output.");
950   if (Output.isFilename()) {
951     CmdArgs.push_back("-o");
952     CmdArgs.push_back(Output.getFilename());
953   }
954 
955   if (Args.getLastArg(options::OPT_save_temps_EQ))
956     Args.AddLastArg(CmdArgs, options::OPT_save_temps_EQ);
957 
958   addDashXForInput(Args, Input, CmdArgs);
959 
960   bool FRecordCmdLine = false;
961   bool GRecordCmdLine = false;
962   if (shouldRecordCommandLine(TC, Args, FRecordCmdLine, GRecordCmdLine)) {
963     const char *CmdLine = renderEscapedCommandLine(TC, Args);
964     if (FRecordCmdLine) {
965       CmdArgs.push_back("-record-command-line");
966       CmdArgs.push_back(CmdLine);
967     }
968     if (TC.UseDwarfDebugFlags() || GRecordCmdLine) {
969       CmdArgs.push_back("-dwarf-debug-flags");
970       CmdArgs.push_back(CmdLine);
971     }
972   }
973 
974   // The input could be Ty_Nothing when "querying" options such as -mcpu=help
975   // are used.
976   ArrayRef<InputInfo> FrontendInputs = Input;
977   if (Input.isNothing())
978     FrontendInputs = {};
979 
980   for (const InputInfo &Input : FrontendInputs) {
981     if (Input.isFilename())
982       CmdArgs.push_back(Input.getFilename());
983     else
984       Input.getInputArg().renderAsInput(Args, CmdArgs);
985   }
986 
987   const char *Exec = Args.MakeArgString(D.GetProgramPath("flang", TC));
988   C.addCommand(std::make_unique<Command>(JA, *this,
989                                          ResponseFileSupport::AtFileUTF8(),
990                                          Exec, CmdArgs, Inputs, Output));
991 }
992 
993 Flang::Flang(const ToolChain &TC) : Tool("flang", "flang frontend", TC) {}
994 
995 Flang::~Flang() {}
996