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 "Cuda.h"
12
13#include "clang/Basic/CodeGenOptions.h"
14#include "clang/Basic/MakeSupport.h"
15#include "clang/Driver/CommonArgs.h"
16#include "clang/Options/OptionUtils.h"
17#include "clang/Options/Options.h"
18#include "llvm/Frontend/Debug/Options.h"
19#include "llvm/Support/Path.h"
20#include "llvm/TargetParser/Host.h"
21#include "llvm/TargetParser/RISCVISAInfo.h"
22#include "llvm/TargetParser/RISCVTargetParser.h"
23
24#include <cassert>
25
26using namespace clang::driver;
27using namespace clang::driver::tools;
28using namespace clang;
29using namespace llvm::opt;
30
31/// Add -x lang to \p CmdArgs for \p Input.
32static void addDashXForInput(const ArgList &Args, const InputInfo &Input,
33 ArgStringList &CmdArgs) {
34 CmdArgs.push_back(Elt: "-x");
35 // Map the driver type to the frontend type.
36 CmdArgs.push_back(Elt: types::getTypeName(Id: Input.getType()));
37}
38
39// Translate the dependency-file options into the arguments understood by
40// `flang -fc1`. The options handled here:
41// -M Emit only the dependencies and skip code generation. They are
42// written to stdout unless -MF redirects them.
43// -MM Treated identically to -M. The -MM/-M split exists to omit system
44// headers, but Fortran has no notion of system vs user headers, so
45// there is nothing for -MM to exclude.
46// -MD Compile normally and produce the object file, while also writing the
47// dependency file. Its name defaults to the -o value, or the input
48// file name when -o is absent, with the extension replaced by .d.
49// -MMD Treated identically to -MD, for the same reason -MM equals -M.
50// -MF Set the path of the dependency file to write.
51// -MT Set the dependency target name (the part before the colon).
52// -MQ Like -MT, but additionally quotes characters special to Make.
53static void renderDependencyGenerationOptions(Compilation &C,
54 const JobAction &JA,
55 const ArgList &Args,
56 const InputInfo &Output,
57 const InputInfoList &Inputs,
58 ArgStringList &CmdArgs) {
59 Arg *ArgM = Args.getLastArg(Ids: options::OPT_M, Ids: options::OPT_MM);
60 Arg *ArgMD = Args.getLastArg(Ids: options::OPT_MD, Ids: options::OPT_MMD);
61
62 if (!ArgM && !ArgMD)
63 return;
64
65 // Drop warnings for -M/-MM so they don't mix into the dependency output.
66 if (ArgM)
67 CmdArgs.push_back(Elt: "-w");
68 else
69 ArgM = ArgMD;
70
71 // Emit "-MT <target>", quoting Make metacharacters when requested.
72 auto addTarget = [&](StringRef Target, bool Quote) {
73 CmdArgs.push_back(Elt: "-MT");
74 if (Quote) {
75 SmallString<128> Quoted;
76 clang::quoteMakeTarget(Target, Res&: Quoted);
77 CmdArgs.push_back(Elt: Args.MakeArgString(Str: Quoted));
78 } else {
79 CmdArgs.push_back(Elt: Args.MakeArgString(Str: Target));
80 }
81 };
82
83 // Decide where to write the dependency file.
84 const char *DepFile;
85 if (Arg *MF = Args.getLastArg(Ids: options::OPT_MF)) {
86 // -MF gives the path explicitly.
87 DepFile = MF->getValue();
88 C.addFailureResultFile(Name: DepFile, JA: &JA);
89 } else if (Output.getType() == types::TY_Dependencies) {
90 // Plain -M/-MM: the dependency file is the output, so use its name
91 DepFile = Output.getFilename();
92 } else if (!ArgMD) {
93 // -M/-MM with no -o: write the dependencies to stdout.
94 DepFile = "-";
95 } else {
96 // -MD/-MMD: name it after -o, else the input, with a .d extension.
97 SmallString<128> P;
98 if (Arg *OutputOpt = Args.getLastArg(Ids: options::OPT_o))
99 P = OutputOpt->getValue();
100 else
101 P = llvm::sys::path::filename(path: Inputs[0].getBaseInput());
102 llvm::sys::path::replace_extension(path&: P, extension: "d");
103 DepFile = Args.MakeArgString(Str: P);
104 C.addFailureResultFile(Name: DepFile, JA: &JA);
105 }
106 CmdArgs.push_back(Elt: "-dependency-file");
107 CmdArgs.push_back(Elt: DepFile);
108
109 // Render the explicit target(s). -MT is verbatim, -MQ is Make-quoted.
110 bool HasTarget = false;
111 for (const Arg *A : Args.filtered(Ids: options::OPT_MT, Ids: options::OPT_MQ)) {
112 HasTarget = true;
113 A->claim();
114 addTarget(A->getValue(), A->getOption().matches(ID: options::OPT_MQ));
115 }
116
117 // With no explicit target, default to the object file. In -M/-MM mode -o
118 // names the dependency file, not the target, so derive <base>.o instead.
119 if (!HasTarget) {
120 Arg *OutputOpt = Args.getLastArg(Ids: options::OPT_o);
121 if (OutputOpt && Output.getType() != types::TY_Dependencies) {
122 addTarget(OutputOpt->getValue(), /*Quote=*/true);
123 } else {
124 SmallString<128> P(llvm::sys::path::filename(path: Inputs[0].getBaseInput()));
125 llvm::sys::path::replace_extension(path&: P, extension: "o");
126 addTarget(P, /*Quote=*/true);
127 }
128 }
129}
130
131void Flang::addFortranDialectOptions(const ArgList &Args,
132 ArgStringList &CmdArgs) const {
133 Args.addAllArgs(Output&: CmdArgs,
134 Ids: {options::OPT_ffixed_form,
135 options::OPT_ffree_form,
136 options::OPT_ffixed_line_length_EQ,
137 options::OPT_fopenacc,
138 options::OPT_finput_charset_EQ,
139 options::OPT_fimplicit_none,
140 options::OPT_fimplicit_none_ext,
141 options::OPT_fno_implicit_none,
142 options::OPT_fbackslash,
143 options::OPT_fno_backslash,
144 options::OPT_flogical_abbreviations,
145 options::OPT_fno_logical_abbreviations,
146 options::OPT_fxor_operator,
147 options::OPT_fno_xor_operator,
148 options::OPT_falternative_parameter_statement,
149 options::OPT_fdefault_integer_4,
150 options::OPT_fdefault_real_4,
151 options::OPT_fdefault_real_8,
152 options::OPT_fdefault_integer_8,
153 options::OPT_fdefault_double_8,
154 options::OPT_flarge_sizes,
155 options::OPT_fno_automatic,
156 options::OPT_fhermetic_module_files,
157 options::OPT_frealloc_lhs,
158 options::OPT_fno_realloc_lhs,
159 options::OPT_fsave_main_program,
160 options::OPT_fd_lines_as_code,
161 options::OPT_fd_lines_as_comments,
162 options::OPT_fno_save_main_program,
163 options::OPT_fprefer_intrinsic_module_use_association,
164 options::OPT_fno_prefer_intrinsic_module_use_association});
165}
166
167void Flang::addPreprocessingOptions(const ArgList &Args,
168 ArgStringList &CmdArgs) const {
169 Args.addAllArgs(Output&: CmdArgs,
170 Ids: {options::OPT_P, options::OPT_D, options::OPT_U,
171 options::OPT_I, options::OPT_cpp, options::OPT_nocpp});
172}
173
174/// @C shouldLoopVersion
175///
176/// Check if Loop Versioning should be enabled.
177/// We look for the last of one of the following:
178/// -Ofast, -O4, -O<number> and -f[no-]version-loops-for-stride.
179/// Loop versioning is disabled if the last option is
180/// -fno-version-loops-for-stride.
181/// Loop versioning is enabled if the last option is one of:
182/// -floop-versioning
183/// -Ofast
184/// -O4
185/// -O3
186/// For all other cases, loop versioning is disabled.
187///
188/// The gfortran compiler automatically enables the option for -O3 or -Ofast.
189///
190/// @return true if loop-versioning should be enabled, otherwise false.
191static bool shouldLoopVersion(const ArgList &Args) {
192 const Arg *LoopVersioningArg = Args.getLastArg(
193 Ids: options::OPT_Ofast, Ids: options::OPT_O, Ids: options::OPT_O4,
194 Ids: options::OPT_floop_versioning, Ids: options::OPT_fno_loop_versioning);
195 if (!LoopVersioningArg)
196 return false;
197
198 if (LoopVersioningArg->getOption().matches(ID: options::OPT_fno_loop_versioning))
199 return false;
200
201 if (LoopVersioningArg->getOption().matches(ID: options::OPT_floop_versioning))
202 return true;
203
204 if (LoopVersioningArg->getOption().matches(ID: options::OPT_Ofast) ||
205 LoopVersioningArg->getOption().matches(ID: options::OPT_O4))
206 return true;
207
208 if (LoopVersioningArg->getOption().matches(ID: options::OPT_O)) {
209 StringRef S(LoopVersioningArg->getValue());
210 unsigned OptLevel = 0;
211 // Note -Os or Oz woould "fail" here, so return false. Which is the
212 // desiered behavior.
213 if (S.getAsInteger(Radix: 10, Result&: OptLevel))
214 return false;
215
216 return OptLevel > 2;
217 }
218
219 llvm_unreachable("We should not end up here");
220 return false;
221}
222
223void Flang::addDebugOptions(const llvm::opt::ArgList &Args, const JobAction &JA,
224 const InputInfo &Output, const InputInfo &Input,
225 llvm::opt::ArgStringList &CmdArgs) const {
226 const auto &TC = getToolChain();
227 const Driver &D = TC.getDriver();
228 Args.addAllArgs(Output&: CmdArgs,
229 Ids: {options::OPT_module_dir,
230 options::OPT_fdebug_module_writer,
231 options::OPT_fintrinsic_modules_path,
232 options::OPT_pedantic,
233 options::OPT_std_EQ,
234 options::OPT_W_Joined,
235 options::OPT_fconvert_EQ,
236 options::OPT_fpass_plugin_EQ,
237 options::OPT_funderscoring,
238 options::OPT_fno_underscoring,
239 options::OPT_funsigned,
240 options::OPT_fno_unsigned,
241 options::OPT_fenumeration_type,
242 options::OPT_fno_enumeration_type,
243 options::OPT_fout_of_bounds_subscripts,
244 options::OPT_fno_out_of_bounds_subscripts,
245 options::OPT_fopenacc_default_none_scalars_strict,
246 options::OPT_fno_openacc_default_none_scalars_strict,
247 options::OPT_fopenacc_multiple_names_in_routine,
248 options::OPT_fno_openacc_multiple_names_in_routine,
249 options::OPT_finstrument_functions});
250
251 llvm::codegenoptions::DebugInfoKind DebugInfoKind;
252 bool hasDwarfNArg = getDwarfNArg(Args) != nullptr;
253 if (Args.hasArg(Ids: options::OPT_gN_Group)) {
254 Arg *gNArg = Args.getLastArg(Ids: options::OPT_gN_Group);
255 DebugInfoKind = debugLevelToInfoKind(A: *gNArg);
256 } else if (Args.hasArg(Ids: options::OPT_g_Flag) || hasDwarfNArg) {
257 DebugInfoKind = llvm::codegenoptions::FullDebugInfo;
258 } else {
259 DebugInfoKind = llvm::codegenoptions::NoDebugInfo;
260 }
261 addDebugInfoKind(CmdArgs, DebugInfoKind);
262 // Pass on the DWARF version when debug information is being generated, or
263 // when -gdwarf-N names a version. Leaving it out means the version stays
264 // unset and the backend falls back to dwarf::DWARF_VERSION (4) instead of
265 // honouring toolchain default like clang does.
266 //
267 // Note that both conditions are needed to match clang for cases like
268 // "-gdwarf-5 -g0".
269 if (hasDwarfNArg || DebugInfoKind != llvm::codegenoptions::NoDebugInfo) {
270 const unsigned DwarfVersion = getDwarfVersion(TC: getToolChain(), Args);
271 CmdArgs.push_back(
272 Elt: Args.MakeArgString(Str: "-dwarf-version=" + Twine(DwarfVersion)));
273 }
274 if (Args.hasArg(Ids: options::OPT_gsplit_dwarf) ||
275 Args.hasArg(Ids: options::OPT_gsplit_dwarf_EQ)) {
276 // FIXME: -gsplit-dwarf on AIX is currently unimplemented.
277 if (TC.getTriple().isOSAIX()) {
278 D.Diag(DiagID: diag::err_drv_unsupported_opt_for_target)
279 << Args.getLastArg(Ids: options::OPT_gsplit_dwarf)->getSpelling()
280 << TC.getTriple().str();
281 return;
282 }
283 if (DebugInfoKind == llvm::codegenoptions::NoDebugInfo)
284 return;
285
286 Arg *SplitDWARFArg;
287 DwarfFissionKind DwarfFission = getDebugFissionKind(D, Args, Arg&: SplitDWARFArg);
288
289 if (DwarfFission == DwarfFissionKind::None ||
290 !checkDebugInfoOption(A: SplitDWARFArg, Args, D, TC))
291 return;
292
293 if (!TC.getTriple().isOSBinFormatELF() &&
294 !TC.getTriple().isOSBinFormatWasm() &&
295 !TC.getTriple().isOSBinFormatCOFF()) {
296 D.Diag(DiagID: diag::warn_drv_unsupported_debug_info_opt_for_target)
297 << SplitDWARFArg->getSpelling() << TC.getTriple().str();
298 return;
299 }
300
301 if (!isa<AssembleJobAction>(Val: JA) && !isa<CompileJobAction>(Val: JA) &&
302 isa<BackendJobAction>(Val: JA))
303 return;
304
305 const char *SplitDWARFOut = SplitDebugName(JA, Args, Input, Output);
306 CmdArgs.push_back(Elt: "-split-dwarf-file");
307 CmdArgs.push_back(Elt: SplitDWARFOut);
308 if (DwarfFission == DwarfFissionKind::Split) {
309 CmdArgs.push_back(Elt: "-split-dwarf-output");
310 CmdArgs.push_back(Elt: SplitDWARFOut);
311 }
312 }
313
314 // Handle compressed debug sections (-gz).
315 renderDebugInfoCompressionArgs(Args, CmdArgs, D, TC);
316
317 addDebugInfoForProfilingArgs(D, TC, Args, CmdArgs);
318}
319
320void Flang::addCodegenOptions(const ArgList &Args,
321 ArgStringList &CmdArgs) const {
322 Arg *stackArrays =
323 Args.getLastArg(Ids: options::OPT_Ofast, Ids: options::OPT_fstack_arrays,
324 Ids: options::OPT_fno_stack_arrays);
325 if (stackArrays &&
326 !stackArrays->getOption().matches(ID: options::OPT_fno_stack_arrays))
327 CmdArgs.push_back(Elt: "-fstack-arrays");
328
329 if (Args.hasFlag(Pos: options::OPT_fsafe_trampoline,
330 Neg: options::OPT_fno_safe_trampoline, Default: false)) {
331 const llvm::Triple &T = getToolChain().getTriple();
332 if (T.getArch() == llvm::Triple::x86_64 ||
333 T.getArch() == llvm::Triple::aarch64 ||
334 T.getArch() == llvm::Triple::aarch64_be) {
335 CmdArgs.push_back(Elt: "-fsafe-trampoline");
336 } else {
337 getToolChain().getDriver().Diag(
338 DiagID: diag::warn_drv_unsupported_option_for_target)
339 << "-fsafe-trampoline" << T.str();
340 }
341 }
342
343 // -fno-protect-parens is the default for -Ofast.
344 if (!Args.hasFlag(Pos: options::OPT_fprotect_parens,
345 Neg: options::OPT_fno_protect_parens,
346 /*Default=*/!Args.hasArg(Ids: options::OPT_Ofast)))
347 CmdArgs.push_back(Elt: "-fno-protect-parens");
348
349 if (Args.hasFlag(Pos: options::OPT_funsafe_cray_pointers,
350 Neg: options::OPT_fno_unsafe_cray_pointers, Default: false)) {
351 // TODO: currently passed as MLIR option
352 CmdArgs.push_back(Elt: "-mmlir");
353 CmdArgs.push_back(Elt: "-unsafe-cray-pointers");
354 }
355
356 Args.addOptInFlag(Output&: CmdArgs, Pos: options::OPT_fexperimental_loop_fusion,
357 Neg: options::OPT_fno_experimental_loop_fusion);
358 Args.AddLastArg(Output&: CmdArgs, Ids: options::OPT_ffp_sum_reassociation,
359 Ids: options::OPT_fno_fp_sum_reassociation);
360
361 handleInterchangeLoopsArgs(Args, CmdArgs);
362 handleVectorizeLoopsArgs(Args, CmdArgs);
363 handleVectorizeSLPArgs(Args, CmdArgs);
364
365 if (shouldLoopVersion(Args))
366 CmdArgs.push_back(Elt: "-fversion-loops-for-stride");
367
368 for (const auto &arg :
369 Args.getAllArgValues(Id: options::OPT_frepack_arrays_contiguity_EQ))
370 if (arg != "whole" && arg != "innermost") {
371 getToolChain().getDriver().Diag(DiagID: diag::err_drv_unsupported_option_argument)
372 << "-frepack-arrays-contiguity=" << arg;
373 }
374
375 Args.addAllArgs(
376 Output&: CmdArgs,
377 Ids: {options::OPT_fdo_concurrent_to_openmp_EQ,
378 options::OPT_fno_ppc_native_vec_elem_order,
379 options::OPT_fppc_native_vec_elem_order, options::OPT_finit_global_zero,
380 options::OPT_fno_init_global_zero, options::OPT_frepack_arrays,
381 options::OPT_fno_repack_arrays,
382 options::OPT_frepack_arrays_contiguity_EQ,
383 options::OPT_fstack_repack_arrays, options::OPT_fno_stack_repack_arrays,
384 options::OPT_ftime_report, options::OPT_ftime_report_EQ,
385 options::OPT_funroll_loops, options::OPT_fno_unroll_loops,
386 options::OPT_relaxed_c_loc});
387
388 Args.addOptOutFlag(Output&: CmdArgs, Pos: options::OPT_foptimize_sibling_calls,
389 Neg: options::OPT_fno_optimize_sibling_calls);
390
391 const llvm::Triple &Triple = getToolChain().getEffectiveTriple();
392 addSeparateSectionFlags(Triple, Args, CmdArgs);
393
394 if (Args.hasArg(Ids: options::OPT_fcoarray))
395 CmdArgs.push_back(Elt: "-fcoarray");
396}
397
398void Flang::addLTOOptions(const ArgList &Args, ArgStringList &CmdArgs) const {
399 const ToolChain &TC = getToolChain();
400 LTOKind LTOMode = TC.getLTOMode(Args);
401 // LTO mode is parsed by the Clang driver library.
402 assert(LTOMode != LTOK_Unknown && "Unknown LTO mode.");
403 if (LTOMode == LTOK_Full)
404 CmdArgs.push_back(Elt: "-flto=full");
405 else if (LTOMode == LTOK_Thin)
406 CmdArgs.push_back(Elt: "-flto=thin");
407
408 if (Args.hasFlag(Pos: options::OPT_fsplit_lto_unit,
409 Neg: options::OPT_fno_split_lto_unit, /*Default=*/false))
410 CmdArgs.push_back(Elt: "-fsplit-lto-unit");
411
412 Args.addAllArgs(Output&: CmdArgs, Ids: {options::OPT_ffat_lto_objects,
413 options::OPT_fno_fat_lto_objects});
414}
415
416void Flang::addPicOptions(const ArgList &Args, ArgStringList &CmdArgs) const {
417 // ParsePICArgs parses -fPIC/-fPIE and their variants and returns a tuple of
418 // (RelocationModel, PICLevel, IsPIE).
419 llvm::Reloc::Model RelocationModel;
420 unsigned PICLevel;
421 bool IsPIE;
422 std::tie(args&: RelocationModel, args&: PICLevel, args&: IsPIE) =
423 ParsePICArgs(ToolChain: getToolChain(), Args);
424
425 if (auto *RMName = RelocationModelName(Model: RelocationModel)) {
426 CmdArgs.push_back(Elt: "-mrelocation-model");
427 CmdArgs.push_back(Elt: RMName);
428 }
429 if (PICLevel > 0) {
430 CmdArgs.push_back(Elt: "-pic-level");
431 CmdArgs.push_back(Elt: PICLevel == 1 ? "1" : "2");
432 if (IsPIE)
433 CmdArgs.push_back(Elt: "-pic-is-pie");
434 }
435}
436
437void Flang::AddAArch64TargetArgs(const ArgList &Args,
438 ArgStringList &CmdArgs) const {
439 // Handle -msve_vector_bits=<bits>
440 if (Arg *A = Args.getLastArg(Ids: options::OPT_msve_vector_bits_EQ)) {
441 StringRef Val = A->getValue();
442 const Driver &D = getToolChain().getDriver();
443 if (Val == "128" || Val == "256" || Val == "512" || Val == "1024" ||
444 Val == "2048" || Val == "128+" || Val == "256+" || Val == "512+" ||
445 Val == "1024+" || Val == "2048+") {
446 unsigned Bits = 0;
447 if (!Val.consume_back(Suffix: "+")) {
448 [[maybe_unused]] bool Invalid = Val.getAsInteger(Radix: 10, Result&: Bits);
449 assert(!Invalid && "Failed to parse value");
450 CmdArgs.push_back(
451 Elt: Args.MakeArgString(Str: "-mvscale-max=" + llvm::Twine(Bits / 128)));
452 }
453
454 [[maybe_unused]] bool Invalid = Val.getAsInteger(Radix: 10, Result&: Bits);
455 assert(!Invalid && "Failed to parse value");
456 CmdArgs.push_back(
457 Elt: Args.MakeArgString(Str: "-mvscale-min=" + llvm::Twine(Bits / 128)));
458 // Silently drop requests for vector-length agnostic code as it's implied.
459 } else if (Val != "scalable")
460 // Handle the unsupported values passed to msve-vector-bits.
461 D.Diag(DiagID: diag::err_drv_unsupported_option_argument)
462 << A->getSpelling() << Val;
463 }
464}
465
466void Flang::AddLoongArch64TargetArgs(const ArgList &Args,
467 ArgStringList &CmdArgs) const {
468 const Driver &D = getToolChain().getDriver();
469 // Currently, flang only support `-mabi=lp64d` in LoongArch64.
470 if (const Arg *A = Args.getLastArg(Ids: options::OPT_mabi_EQ)) {
471 StringRef V = A->getValue();
472 if (V != "lp64d") {
473 D.Diag(DiagID: diag::err_drv_argument_not_allowed_with) << "-mabi" << V;
474 }
475 }
476
477 if (const Arg *A = Args.getLastArg(Ids: options::OPT_mannotate_tablejump,
478 Ids: options::OPT_mno_annotate_tablejump)) {
479 if (A->getOption().matches(ID: options::OPT_mannotate_tablejump)) {
480 CmdArgs.push_back(Elt: "-mllvm");
481 CmdArgs.push_back(Elt: "-loongarch-annotate-tablejump");
482 }
483 }
484}
485
486void Flang::AddPPCTargetArgs(const ArgList &Args,
487 ArgStringList &CmdArgs) const {
488 const Driver &D = getToolChain().getDriver();
489 bool VecExtabi = false;
490
491 if (const Arg *A = Args.getLastArg(Ids: options::OPT_mabi_EQ)) {
492 StringRef V = A->getValue();
493 if (V == "vec-extabi")
494 VecExtabi = true;
495 else if (V == "vec-default")
496 VecExtabi = false;
497 else
498 D.Diag(DiagID: diag::err_drv_unsupported_option_argument)
499 << A->getSpelling() << V;
500 }
501
502 const llvm::Triple &T = getToolChain().getTriple();
503 if (VecExtabi) {
504 if (!T.isOSAIX()) {
505 D.Diag(DiagID: diag::err_drv_unsupported_opt_for_target)
506 << "-mabi=vec-extabi" << T.str();
507 }
508 CmdArgs.push_back(Elt: "-mabi=vec-extabi");
509 }
510}
511
512void Flang::AddRISCVTargetArgs(const ArgList &Args,
513 ArgStringList &CmdArgs) const {
514 const Driver &D = getToolChain().getDriver();
515 const llvm::Triple &Triple = getToolChain().getTriple();
516
517 StringRef ABIName = riscv::getRISCVABI(Args, Triple);
518 if (ABIName == "lp64" || ABIName == "lp64f" || ABIName == "lp64d")
519 CmdArgs.push_back(Elt: Args.MakeArgString(Str: "-mabi=" + ABIName));
520 else
521 D.Diag(DiagID: diag::err_drv_unsupported_option_argument) << "-mabi=" << ABIName;
522
523 // Handle -mrvv-vector-bits=<bits>
524 if (Arg *A = Args.getLastArg(Ids: options::OPT_mrvv_vector_bits_EQ)) {
525 StringRef Val = A->getValue();
526
527 // Get minimum VLen from march.
528 unsigned MinVLen = 0;
529 std::string Arch = riscv::getRISCVArch(Args, Triple);
530 auto ISAInfo = llvm::RISCVISAInfo::parseArchString(
531 Arch, /*EnableExperimentalExtensions*/ EnableExperimentalExtension: true);
532 // Ignore parsing error.
533 if (!errorToBool(Err: ISAInfo.takeError()))
534 MinVLen = (*ISAInfo)->getMinVLen();
535
536 // If the value is "zvl", use MinVLen from march. Otherwise, try to parse
537 // as integer as long as we have a MinVLen.
538 unsigned Bits = 0;
539 if (Val == "zvl" && MinVLen >= llvm::RISCV::RVVBitsPerBlock) {
540 Bits = MinVLen;
541 } else if (!Val.getAsInteger(Radix: 10, Result&: Bits)) {
542 // Only accept power of 2 values beteen RVVBitsPerBlock and 65536 that
543 // at least MinVLen.
544 if (Bits < MinVLen || Bits < llvm::RISCV::RVVBitsPerBlock ||
545 Bits > 65536 || !llvm::isPowerOf2_32(Value: Bits))
546 Bits = 0;
547 }
548
549 // If we got a valid value try to use it.
550 if (Bits != 0) {
551 unsigned VScaleMin = Bits / llvm::RISCV::RVVBitsPerBlock;
552 CmdArgs.push_back(
553 Elt: Args.MakeArgString(Str: "-mvscale-max=" + llvm::Twine(VScaleMin)));
554 CmdArgs.push_back(
555 Elt: Args.MakeArgString(Str: "-mvscale-min=" + llvm::Twine(VScaleMin)));
556 } else if (Val != "scalable") {
557 // Handle the unsupported values passed to mrvv-vector-bits.
558 D.Diag(DiagID: diag::err_drv_unsupported_option_argument)
559 << A->getSpelling() << Val;
560 }
561 }
562}
563
564void Flang::AddX86_64TargetArgs(const ArgList &Args,
565 ArgStringList &CmdArgs) const {
566 if (Arg *A = Args.getLastArg(Ids: options::OPT_masm_EQ)) {
567 StringRef Value = A->getValue();
568 if (Value == "intel" || Value == "att") {
569 CmdArgs.push_back(Elt: Args.MakeArgString(Str: "-mllvm"));
570 CmdArgs.push_back(Elt: Args.MakeArgString(Str: "-x86-asm-syntax=" + Value));
571 } else {
572 getToolChain().getDriver().Diag(DiagID: diag::err_drv_unsupported_option_argument)
573 << A->getSpelling() << Value;
574 }
575 }
576}
577
578static void addVSDefines(const ToolChain &TC, const ArgList &Args,
579 ArgStringList &CmdArgs) {
580
581 unsigned ver = 0;
582 const VersionTuple vt = TC.computeMSVCVersion(D: nullptr, Args);
583 ver = vt.getMajor() * 10000000 + vt.getMinor().value_or(u: 0) * 100000 +
584 vt.getSubminor().value_or(u: 0);
585 CmdArgs.push_back(Elt: Args.MakeArgString(Str: "-D_MSC_VER=" + Twine(ver / 100000)));
586 CmdArgs.push_back(Elt: Args.MakeArgString(Str: "-D_MSC_FULL_VER=" + Twine(ver)));
587 CmdArgs.push_back(Elt: Args.MakeArgString(Str: "-D_WIN32"));
588
589 const llvm::Triple &triple = TC.getTriple();
590 if (triple.isAArch64()) {
591 CmdArgs.push_back(Elt: "-D_M_ARM64=1");
592 } else if (triple.isX86() && triple.isArch32Bit()) {
593 CmdArgs.push_back(Elt: "-D_M_IX86=600");
594 } else if (triple.isX86() && triple.isArch64Bit()) {
595 CmdArgs.push_back(Elt: "-D_M_X64=100");
596 } else {
597 llvm_unreachable(
598 "Flang on Windows only supports X86_32, X86_64 and AArch64");
599 }
600}
601
602static void processVSRuntimeLibrary(const ToolChain &TC, const ArgList &Args,
603 ArgStringList &CmdArgs) {
604 assert(TC.getTriple().isKnownWindowsMSVCEnvironment() &&
605 "can only add VS runtime library on Windows!");
606
607 // Flang/Clang (including clang-cl) -compiled programs targeting the MSVC ABI
608 // should only depend on msv(u)crt. LLVM still emits libgcc/compiler-rt
609 // functions in some cases like 128-bit integer math (__udivti3, __modti3,
610 // __fixsfti, __floattidf, ...) that msvc does not support. We are injecting a
611 // dependency to Compiler-RT's builtin library where these are implemented.
612 CmdArgs.push_back(Elt: Args.MakeArgString(
613 Str: "--dependent-lib=" + TC.getCompilerRTBasename(Args, Component: "builtins")));
614
615 unsigned RTOptionID = options::OPT__SLASH_MT;
616 if (auto *rtl = Args.getLastArg(Ids: options::OPT_fms_runtime_lib_EQ)) {
617 RTOptionID = llvm::StringSwitch<unsigned>(rtl->getValue())
618 .Case(S: "static", Value: options::OPT__SLASH_MT)
619 .Case(S: "static_dbg", Value: options::OPT__SLASH_MTd)
620 .Case(S: "dll", Value: options::OPT__SLASH_MD)
621 .Case(S: "dll_dbg", Value: options::OPT__SLASH_MDd)
622 .Default(Value: options::OPT__SLASH_MT);
623 }
624 switch (RTOptionID) {
625 case options::OPT__SLASH_MT:
626 CmdArgs.push_back(Elt: "-D_MT");
627 CmdArgs.push_back(Elt: "--dependent-lib=libcmt");
628 CmdArgs.push_back(Elt: "--dependent-lib=flang_rt.runtime.static.lib");
629 break;
630 case options::OPT__SLASH_MTd:
631 CmdArgs.push_back(Elt: "-D_MT");
632 CmdArgs.push_back(Elt: "-D_DEBUG");
633 CmdArgs.push_back(Elt: "--dependent-lib=libcmtd");
634 CmdArgs.push_back(Elt: "--dependent-lib=flang_rt.runtime.static_dbg.lib");
635 break;
636 case options::OPT__SLASH_MD:
637 CmdArgs.push_back(Elt: "-D_MT");
638 CmdArgs.push_back(Elt: "-D_DLL");
639 CmdArgs.push_back(Elt: "--dependent-lib=msvcrt");
640 CmdArgs.push_back(Elt: "--dependent-lib=flang_rt.runtime.dynamic.lib");
641 break;
642 case options::OPT__SLASH_MDd:
643 CmdArgs.push_back(Elt: "-D_MT");
644 CmdArgs.push_back(Elt: "-D_DEBUG");
645 CmdArgs.push_back(Elt: "-D_DLL");
646 CmdArgs.push_back(Elt: "--dependent-lib=msvcrtd");
647 CmdArgs.push_back(Elt: "--dependent-lib=flang_rt.runtime.dynamic_dbg.lib");
648 break;
649 }
650}
651
652void Flang::AddAMDGPUTargetArgs(const ArgList &Args, ArgStringList &CmdArgs,
653 BoundArch BA,
654 Action::OffloadKind DeviceOffloadKind) const {
655 if (Arg *A = Args.getLastArg(Ids: options::OPT_mcode_object_version_EQ)) {
656 StringRef Val = A->getValue();
657 CmdArgs.push_back(Elt: Args.MakeArgString(Str: "-mcode-object-version=" + Val));
658 CmdArgs.push_back(Elt: Args.MakeArgString(Str: "-mllvm"));
659 CmdArgs.push_back(
660 Elt: Args.MakeArgString(Str: "--amdhsa-code-object-version=" + Val));
661 }
662
663 const ToolChain &TC = getToolChain();
664 TC.addClangTargetOptions(DriverArgs: Args, CC1Args&: CmdArgs, BA, DeviceOffloadKind);
665}
666
667void Flang::AddNVPTXTargetArgs(const ArgList &Args, ArgStringList &CmdArgs,
668 BoundArch BA,
669 Action::OffloadKind DeviceOffloadKind) const {
670 // we cannot use addClangTargetOptions, as it appends unsupported args for
671 // flang: -fcuda-is-device, -fno-threadsafe-statics,
672 // -fcuda-allow-variadic-functions and -target-sdk-version Instead we manually
673 // detect the CUDA installation and link libdevice
674 const ToolChain &TC = getToolChain();
675 const Driver &D = TC.getDriver();
676 const llvm::Triple &Triple = TC.getEffectiveTriple();
677
678 if (!Args.hasFlag(Pos: options::OPT_offloadlib, Neg: options::OPT_no_offloadlib, Default: true))
679 return;
680
681 // Detect CUDA installation and link libdevice
682 CudaInstallationDetector CudaInstallation(D, Triple, Args);
683 if (!CudaInstallation.isValid()) {
684 D.Diag(DiagID: diag::err_drv_no_cuda_installation);
685 return;
686 }
687
688 StringRef GpuArch = Args.getLastArgValue(Id: options::OPT_march_EQ);
689 if (GpuArch.empty()) {
690 D.Diag(DiagID: diag::err_drv_offload_missing_gpu_arch) << "NVPTX" << "flang";
691 return;
692 }
693
694 std::string LibDeviceFile = CudaInstallation.getLibDeviceFile(Gpu: GpuArch);
695 if (LibDeviceFile.empty()) {
696 D.Diag(DiagID: diag::err_drv_no_cuda_libdevice) << GpuArch;
697 return;
698 }
699
700 CmdArgs.push_back(Elt: "-mlink-builtin-bitcode");
701 CmdArgs.push_back(Elt: Args.MakeArgString(Str: LibDeviceFile));
702}
703
704void Flang::addTargetOptions(const ArgList &Args, ArgStringList &CmdArgs,
705 BoundArch BA,
706 Action::OffloadKind DeviceOffloadKind) const {
707 const ToolChain &TC = getToolChain();
708 const llvm::Triple &Triple = TC.getEffectiveTriple();
709 const Driver &D = TC.getDriver();
710
711 std::string CPU = getCPUName(D, Args, T: Triple);
712 if (!CPU.empty()) {
713 CmdArgs.push_back(Elt: "-target-cpu");
714 CmdArgs.push_back(Elt: Args.MakeArgString(Str: CPU));
715 }
716
717 addOutlineAtomicsArgs(D, TC: getToolChain(), Args, CmdArgs, Triple);
718
719 // Add the target features.
720 switch (TC.getArch()) {
721 default:
722 getTargetFeatures(D, Triple, Args, CmdArgs, /*ForAs*/ ForAS: false);
723 break;
724 case llvm::Triple::aarch64:
725 getTargetFeatures(D, Triple, Args, CmdArgs, /*ForAs*/ ForAS: false);
726 AddAArch64TargetArgs(Args, CmdArgs);
727 break;
728 case llvm::Triple::amdgpu:
729 case llvm::Triple::r600:
730 getTargetFeatures(D, Triple, Args, CmdArgs, /*ForAs*/ ForAS: false);
731 AddAMDGPUTargetArgs(Args, CmdArgs, BA, DeviceOffloadKind);
732 break;
733 case llvm::Triple::nvptx:
734 case llvm::Triple::nvptx64:
735 AddNVPTXTargetArgs(Args, CmdArgs, BA, DeviceOffloadKind);
736 break;
737 case llvm::Triple::riscv64:
738 getTargetFeatures(D, Triple, Args, CmdArgs, /*ForAs*/ ForAS: false);
739 AddRISCVTargetArgs(Args, CmdArgs);
740 break;
741 case llvm::Triple::x86_64:
742 getTargetFeatures(D, Triple, Args, CmdArgs, /*ForAs*/ ForAS: false);
743 AddX86_64TargetArgs(Args, CmdArgs);
744 break;
745 case llvm::Triple::ppc:
746 case llvm::Triple::ppc64:
747 case llvm::Triple::ppc64le:
748 getTargetFeatures(D, Triple, Args, CmdArgs, /*ForAs*/ ForAS: false);
749 AddPPCTargetArgs(Args, CmdArgs);
750 break;
751 case llvm::Triple::loongarch64:
752 getTargetFeatures(D, Triple, Args, CmdArgs, /*ForAs*/ ForAS: false);
753 AddLoongArch64TargetArgs(Args, CmdArgs);
754 break;
755 }
756
757 if (Arg *A = Args.getLastArg(Ids: options::OPT_fveclib)) {
758 StringRef Name = A->getValue();
759 if (Name == "SVML") {
760 if (Triple.getArch() != llvm::Triple::x86 &&
761 Triple.getArch() != llvm::Triple::x86_64)
762 D.Diag(DiagID: diag::err_drv_unsupported_opt_for_target)
763 << Name << Triple.getArchName();
764 } else if (Name == "AMDLIBM") {
765 if (Triple.getArch() != llvm::Triple::x86 &&
766 Triple.getArch() != llvm::Triple::x86_64)
767 D.Diag(DiagID: diag::err_drv_unsupported_opt_for_target)
768 << Name << Triple.getArchName();
769 } else if (Name == "libmvec") {
770 if (Triple.getArch() != llvm::Triple::x86 &&
771 Triple.getArch() != llvm::Triple::x86_64 &&
772 Triple.getArch() != llvm::Triple::aarch64 &&
773 Triple.getArch() != llvm::Triple::aarch64_be)
774 D.Diag(DiagID: diag::err_drv_unsupported_opt_for_target)
775 << Name << Triple.getArchName();
776 } else if (Name == "SLEEF" || Name == "ArmPL") {
777 if (Triple.getArch() != llvm::Triple::aarch64 &&
778 Triple.getArch() != llvm::Triple::aarch64_be)
779 D.Diag(DiagID: diag::err_drv_unsupported_opt_for_target)
780 << Name << Triple.getArchName();
781 }
782
783 if (Triple.isOSDarwin()) {
784 // flang doesn't currently suport nostdlib, nodefaultlibs. Adding these
785 // here incase they are added someday
786 if (!Args.hasArg(Ids: options::OPT_nostdlib, Ids: options::OPT_nodefaultlibs)) {
787 if (A->getValue() == StringRef{"Accelerate"}) {
788 CmdArgs.push_back(Elt: "-framework");
789 CmdArgs.push_back(Elt: "Accelerate");
790 }
791 }
792 }
793 A->render(Args, Output&: CmdArgs);
794 }
795
796 if (Triple.isKnownWindowsMSVCEnvironment()) {
797 processVSRuntimeLibrary(TC, Args, CmdArgs);
798 addVSDefines(TC, Args, CmdArgs);
799 }
800
801 // TODO: Add target specific flags, ABI, mtune option etc.
802 if (const Arg *A = Args.getLastArg(Ids: options::OPT_mtune_EQ)) {
803 CmdArgs.push_back(Elt: "-tune-cpu");
804 if (A->getValue() == StringRef{"native"})
805 CmdArgs.push_back(Elt: Args.MakeArgString(Str: llvm::sys::getHostCPUName()));
806 else
807 CmdArgs.push_back(Elt: A->getValue());
808 }
809
810 Args.addAllArgs(Output&: CmdArgs,
811 Ids: {options::OPT_fverbose_asm, options::OPT_fno_verbose_asm,
812 options::OPT_fatomic_ignore_denormal_mode,
813 options::OPT_fno_atomic_ignore_denormal_mode,
814 options::OPT_fatomic_fine_grained_memory,
815 options::OPT_fno_atomic_fine_grained_memory,
816 options::OPT_fatomic_remote_memory,
817 options::OPT_fno_atomic_remote_memory,
818 options::OPT_munsafe_fp_atomics});
819}
820
821void Flang::addOffloadOptions(Compilation &C, const InputInfoList &Inputs,
822 const JobAction &JA, const ArgList &Args,
823 ArgStringList &CmdArgs) const {
824 bool IsOpenMPDevice = JA.isDeviceOffloading(OKind: Action::OFK_OpenMP);
825 bool IsHostOffloadingAction = JA.isHostOffloading(OKind: Action::OFK_OpenMP) ||
826 JA.isHostOffloading(OKind: C.getActiveOffloadKinds());
827
828 // Tell the frontend when it is compiling for an offloading device, regardless
829 // of offloading programming model.
830 if (JA.getOffloadingDeviceKind() > Action::OFK_Host)
831 CmdArgs.push_back(Elt: "-foffload-device");
832
833 // Skips the primary input file, which is the input file that the compilation
834 // proccess will be executed upon (e.g. the host bitcode file) and
835 // adds other secondary input (e.g. device bitcode files for embedding to the
836 // -fembed-offload-object argument or the host IR file for proccessing
837 // during device compilation to the fopenmp-host-ir-file-path argument via
838 // OpenMPDeviceInput). This is condensed logic from the ConstructJob
839 // function inside of the Clang driver for pushing on further input arguments
840 // needed for offloading during various phases of compilation.
841 for (size_t i = 1; i < Inputs.size(); ++i) {
842 if (Inputs[i].getType() == types::TY_Nothing) {
843 // contains nothing, so it's skippable
844 } else if (IsHostOffloadingAction) {
845 CmdArgs.push_back(
846 Elt: Args.MakeArgString(Str: "-fembed-offload-object=" +
847 getToolChain().getInputFilename(Input: Inputs[i])));
848 } else if (IsOpenMPDevice) {
849 if (Inputs[i].getFilename()) {
850 CmdArgs.push_back(Elt: "-fopenmp-host-ir-file-path");
851 CmdArgs.push_back(Elt: Args.MakeArgString(Str: Inputs[i].getFilename()));
852 } else {
853 llvm_unreachable("missing openmp host-ir file for device offloading");
854 }
855 } else {
856 llvm_unreachable(
857 "unexpectedly given multiple inputs or given unknown input");
858 }
859 }
860
861 // When in OpenMP offloading mode, forward assumptions information about
862 // thread and team counts in the target device. The host needs to know about
863 // this to prevent the SPMD to SPMD-no-loop promotion being done differently
864 // for host and device on the same target region.
865 if (Args.hasFlag(Pos: options::OPT_fopenmp_assume_teams_oversubscription,
866 Neg: options::OPT_fno_openmp_assume_teams_oversubscription,
867 /*Default=*/false))
868 CmdArgs.push_back(Elt: "-fopenmp-assume-teams-oversubscription");
869 if (Args.hasFlag(Pos: options::OPT_fopenmp_assume_threads_oversubscription,
870 Neg: options::OPT_fno_openmp_assume_threads_oversubscription,
871 /*Default=*/false))
872 CmdArgs.push_back(Elt: "-fopenmp-assume-threads-oversubscription");
873
874 if (IsOpenMPDevice) {
875 // -fopenmp-is-target-device is passed along to tell the frontend that it is
876 // generating code for a device, so that only the relevant code is emitted.
877 CmdArgs.push_back(Elt: "-fopenmp-is-target-device");
878
879 // -fopenmp-target-fast implies -fopenmp-assume-no-thread-state and
880 // -fopenmp-assume-no-nested-parallelism, and forces -O3 unless an
881 // explicit optimization level was requested.
882 bool TargetFastUsed =
883 Args.hasFlag(Pos: options::OPT_fopenmp_target_fast,
884 Neg: options::OPT_fno_openmp_target_fast, Default: false);
885
886 if (TargetFastUsed && !Args.hasArg(Ids: options::OPT_O_Group))
887 CmdArgs.push_back(Elt: "-O3");
888
889 // When in OpenMP offloading mode, enable debugging on the device.
890 Args.AddAllArgs(Output&: CmdArgs, Id0: options::OPT_fopenmp_target_debug_EQ);
891 if (Args.hasFlag(Pos: options::OPT_fopenmp_target_debug,
892 Neg: options::OPT_fno_openmp_target_debug, /*Default=*/false))
893 CmdArgs.push_back(Elt: "-fopenmp-target-debug");
894
895 // Handle -fopenmp-assume-no-thread-state (implied by target-fast)
896 if (Args.hasFlag(Pos: options::OPT_fopenmp_assume_no_thread_state,
897 Neg: options::OPT_fno_openmp_assume_no_thread_state,
898 /*Default=*/TargetFastUsed))
899 CmdArgs.push_back(Elt: "-fopenmp-assume-no-thread-state");
900
901 // Handle -fopenmp-assume-no-nested-parallelism (implied by target-fast)
902 if (Args.hasFlag(Pos: options::OPT_fopenmp_assume_no_nested_parallelism,
903 Neg: options::OPT_fno_openmp_assume_no_nested_parallelism,
904 /*Default=*/TargetFastUsed))
905 CmdArgs.push_back(Elt: "-fopenmp-assume-no-nested-parallelism");
906
907 if (!Args.hasFlag(Pos: options::OPT_offloadlib, Neg: options::OPT_no_offloadlib,
908 Default: true))
909 CmdArgs.push_back(Elt: "-nogpulib");
910 }
911
912 addOpenMPHostOffloadingArgs(C, JA, Args, CmdArgs);
913}
914
915static void addFloatingPointOptions(const Driver &D, const ArgList &Args,
916 ArgStringList &CmdArgs) {
917 StringRef FPContract;
918 StringRef LastSeenFfpContractOption;
919 StringRef LastFpContractOverrideOption;
920 bool HonorINFs = true;
921 bool HonorNaNs = true;
922 bool ApproxFunc = false;
923 bool SignedZeros = true;
924 bool AssociativeMath = false;
925 bool ReciprocalMath = false;
926
927 StringRef LastComplexRangeOption;
928 LangOptions::ComplexRangeKind Range = LangOptions::ComplexRangeKind::CX_None;
929
930 for (const Arg *A : Args) {
931 auto optId = A->getOption().getID();
932 switch (optId) {
933 // if this isn't an FP option, skip the claim below
934 default:
935 continue;
936
937 case options::OPT_fcomplex_arithmetic_EQ: {
938 LangOptions::ComplexRangeKind NewRange;
939 StringRef Val = A->getValue();
940 if (Val == "full")
941 NewRange = LangOptions::ComplexRangeKind::CX_Full;
942 else if (Val == "improved")
943 NewRange = LangOptions::ComplexRangeKind::CX_Improved;
944 else if (Val == "basic")
945 NewRange = LangOptions::ComplexRangeKind::CX_Basic;
946 else {
947 D.Diag(DiagID: diag::err_drv_unsupported_option_argument)
948 << A->getSpelling() << Val;
949 break;
950 }
951
952 setComplexRange(D, NewOpt: Args.MakeArgString(Str: A->getSpelling() + Val), NewRange,
953 LastOpt&: LastComplexRangeOption, Range);
954 break;
955 }
956 case options::OPT_fhonor_infinities:
957 HonorINFs = true;
958 break;
959 case options::OPT_fno_honor_infinities:
960 HonorINFs = false;
961 break;
962 case options::OPT_fhonor_nans:
963 HonorNaNs = true;
964 break;
965 case options::OPT_fno_honor_nans:
966 HonorNaNs = false;
967 break;
968 case options::OPT_fapprox_func:
969 ApproxFunc = true;
970 break;
971 case options::OPT_fno_approx_func:
972 ApproxFunc = false;
973 break;
974 case options::OPT_fsigned_zeros:
975 SignedZeros = true;
976 break;
977 case options::OPT_fno_signed_zeros:
978 SignedZeros = false;
979 break;
980 case options::OPT_fassociative_math:
981 AssociativeMath = true;
982 break;
983 case options::OPT_fno_associative_math:
984 AssociativeMath = false;
985 break;
986 case options::OPT_freciprocal_math:
987 ReciprocalMath = true;
988 break;
989 case options::OPT_fno_reciprocal_math:
990 ReciprocalMath = false;
991 break;
992 case options::OPT_ffp_contract: {
993 StringRef Val = A->getValue();
994 if (Val == "fast" || Val == "off") {
995 if (Val != FPContract && LastFpContractOverrideOption != "") {
996 D.Diag(DiagID: clang::diag::warn_drv_overriding_option)
997 << LastFpContractOverrideOption
998 << Args.MakeArgString(Str: "-ffp-contract=" + Val);
999 }
1000 FPContract = Val;
1001 LastSeenFfpContractOption = Val;
1002 } else if (Val == "on") {
1003 // Warn instead of error because users might have makefiles written for
1004 // gfortran (which accepts -ffp-contract=on)
1005 D.Diag(DiagID: diag::warn_drv_unsupported_option_for_flang)
1006 << Val << A->getOption().getName() << "off";
1007 FPContract = "off";
1008 LastSeenFfpContractOption = "off";
1009 } else {
1010 // Clang's "fast-honor-pragmas" option is not supported because it is
1011 // non-standard
1012 D.Diag(DiagID: diag::err_drv_unsupported_option_argument)
1013 << A->getSpelling() << Val;
1014 }
1015 LastFpContractOverrideOption = "";
1016 break;
1017 }
1018 case options::OPT_Ofast:
1019 [[fallthrough]];
1020 case options::OPT_ffast_math:
1021 HonorINFs = false;
1022 HonorNaNs = false;
1023 AssociativeMath = true;
1024 ReciprocalMath = true;
1025 ApproxFunc = true;
1026 SignedZeros = false;
1027 FPContract = "fast";
1028 if (A->getOption().getID() == options::OPT_Ofast)
1029 LastFpContractOverrideOption = "-Ofast";
1030 else
1031 LastFpContractOverrideOption = "-ffast-math";
1032 setComplexRange(D, NewOpt: A->getSpelling(),
1033 NewRange: LangOptions::ComplexRangeKind::CX_Basic,
1034 LastOpt&: LastComplexRangeOption, Range);
1035 break;
1036 case options::OPT_fno_fast_math:
1037 HonorINFs = true;
1038 HonorNaNs = true;
1039 AssociativeMath = false;
1040 ReciprocalMath = false;
1041 ApproxFunc = false;
1042 SignedZeros = true;
1043 // -fno-fast-math should undo -ffast-math so I return FPContract to the
1044 // default. If -ffp-contract= was explicitly specified, restore the
1045 // user-requested value from LastSeenFfpContractOption so that
1046 // -ffp-contract=off -fno-fast-math --> -ffp-contract=off
1047 if (LastSeenFfpContractOption != "")
1048 FPContract = LastSeenFfpContractOption;
1049 else
1050 FPContract = "";
1051 setComplexRange(D, NewOpt: A->getSpelling(),
1052 NewRange: LangOptions::ComplexRangeKind::CX_None,
1053 LastOpt&: LastComplexRangeOption, Range);
1054 LastFpContractOverrideOption = "";
1055 break;
1056 }
1057
1058 // If we handled this option claim it
1059 A->claim();
1060 }
1061
1062 StringRef Recip = parseMRecipOption(Diags&: D.getDiags(), Args);
1063 if (!Recip.empty())
1064 CmdArgs.push_back(Elt: Args.MakeArgString(Str: "-mrecip=" + Recip));
1065
1066 if (Range != LangOptions::ComplexRangeKind::CX_None) {
1067 std::string ComplexRangeStr = renderComplexRangeOption(Range);
1068 CmdArgs.push_back(Elt: Args.MakeArgString(Str: ComplexRangeStr));
1069 CmdArgs.push_back(Elt: Args.MakeArgString(Str: "-fcomplex-arithmetic=" +
1070 complexRangeKindToStr(Range)));
1071 }
1072
1073 if (llvm::opt::Arg *A =
1074 Args.getLastArg(Ids: clang::options::OPT_ffast_real_mod,
1075 Ids: clang::options::OPT_fno_fast_real_mod)) {
1076 if (A->getOption().matches(ID: clang::options::OPT_ffast_real_mod))
1077 CmdArgs.push_back(Elt: "-ffast-real-mod");
1078 else if (A->getOption().matches(ID: clang::options::OPT_fno_fast_real_mod))
1079 CmdArgs.push_back(Elt: "-fno-fast-real-mod");
1080 }
1081
1082 if (!HonorINFs && !HonorNaNs && AssociativeMath && ReciprocalMath &&
1083 ApproxFunc && !SignedZeros &&
1084 (FPContract == "fast" || FPContract.empty())) {
1085 CmdArgs.push_back(Elt: "-ffast-math");
1086 return;
1087 }
1088
1089 if (!FPContract.empty())
1090 CmdArgs.push_back(Elt: Args.MakeArgString(Str: "-ffp-contract=" + FPContract));
1091
1092 if (!HonorINFs)
1093 CmdArgs.push_back(Elt: "-menable-no-infs");
1094
1095 if (!HonorNaNs)
1096 CmdArgs.push_back(Elt: "-menable-no-nans");
1097
1098 if (ApproxFunc)
1099 CmdArgs.push_back(Elt: "-fapprox-func");
1100
1101 if (!SignedZeros)
1102 CmdArgs.push_back(Elt: "-fno-signed-zeros");
1103
1104 if (AssociativeMath && !SignedZeros)
1105 CmdArgs.push_back(Elt: "-mreassociate");
1106
1107 if (ReciprocalMath)
1108 CmdArgs.push_back(Elt: "-freciprocal-math");
1109}
1110
1111// Add options related to IEEE Floating point modes
1112//
1113// Initial halting mode:
1114// Validate -ffpe-trap= and forward it to -fc1. This is handled separately from
1115// addFloatingPointOptions() on purpose: -ffpe-trap= is not part of the
1116// fast-math option set, so it must not be skipped by that function's
1117// -ffast-math fast path. The value check and the target-support warnings depend
1118// only on the option value and the target triple (no frontend-only state), so
1119// they are done here in the driver rather than deferred to -fc1; -fc1 only
1120// translates the list into its LangOptions bitmask.
1121//
1122// TODO:
1123// Rounding modes
1124// Underflow mode
1125static void addIEEEFPModesOptions(const Driver &D, const ArgList &Args,
1126 ArgStringList &CmdArgs,
1127 const llvm::Triple &Triple) {
1128 const Arg *A = Args.getLastArg(Ids: options::OPT_ffpe_trap_EQ);
1129 if (!A)
1130 return;
1131
1132 // The value is a comma-separated list of exception mnemonics. "none" and an
1133 // empty list request no halting and reset any earlier request in the list;
1134 // any other unrecognized mnemonic is an error.
1135 llvm::SmallVector<StringRef, 6> Traps;
1136 StringRef(A->getValue())
1137 .split(A&: Traps, Separator: ',', /*MaxSplit=*/-1, /*KeepEmpty=*/false);
1138
1139 bool RequestsTrap = false;
1140 bool RequestsDenormal = false;
1141 for (StringRef Trap : Traps) {
1142 if (Trap == "none") {
1143 RequestsTrap = false;
1144 RequestsDenormal = false;
1145 continue;
1146 }
1147 bool IsKnown = llvm::StringSwitch<bool>(Trap)
1148 .Cases(CaseStrings: {"invalid", "zero", "overflow", "underflow",
1149 "inexact", "denormal"},
1150 Value: true)
1151 .Default(Value: false);
1152 if (!IsKnown) {
1153 D.Diag(DiagID: diag::err_drv_unsupported_option_argument)
1154 << A->getSpelling() << Trap;
1155 return;
1156 }
1157 RequestsTrap = true;
1158 RequestsDenormal |= (Trap == "denormal");
1159 }
1160
1161 // Run-time halting is implemented in flang-rt only where the target's
1162 // floating-point environment can trap: it relies on glibc's feenableexcept
1163 // (in practice Linux), and "denormal" additionally requires an x86 target.
1164 // Warn (conservatively) when the target cannot honor the request; the runtime
1165 // otherwise ignores it. The denormal-specific warning names just
1166 // "-ffpe-trap=denormal" to point at the unsupported mnemonic.
1167 if (RequestsTrap && !Triple.isX86() && !Triple.isOSLinux())
1168 D.Diag(DiagID: diag::warn_drv_unsupported_option_for_target)
1169 << A->getAsString(Args) << Triple.str();
1170 else if (RequestsDenormal && !Triple.isX86())
1171 D.Diag(DiagID: diag::warn_drv_unsupported_option_for_target)
1172 << "-ffpe-trap=denormal" << Triple.str();
1173
1174 A->render(Args, Output&: CmdArgs);
1175}
1176
1177static void renderRemarksOptions(const ArgList &Args, ArgStringList &CmdArgs,
1178 const InputInfo &Input) {
1179 StringRef Format = "yaml";
1180 if (const Arg *A = Args.getLastArg(Ids: options::OPT_fsave_optimization_record_EQ))
1181 Format = A->getValue();
1182
1183 CmdArgs.push_back(Elt: "-opt-record-file");
1184
1185 const Arg *A = Args.getLastArg(Ids: options::OPT_foptimization_record_file_EQ);
1186 if (A) {
1187 CmdArgs.push_back(Elt: A->getValue());
1188 } else {
1189 SmallString<128> F;
1190
1191 if (Args.hasArg(Ids: options::OPT_c) || Args.hasArg(Ids: options::OPT_S)) {
1192 if (Arg *FinalOutput = Args.getLastArg(Ids: options::OPT_o))
1193 F = FinalOutput->getValue();
1194 }
1195
1196 if (F.empty()) {
1197 // Use the input filename.
1198 F = llvm::sys::path::stem(path: Input.getBaseInput());
1199 }
1200
1201 SmallString<32> Extension;
1202 Extension += "opt.";
1203 Extension += Format;
1204
1205 llvm::sys::path::replace_extension(path&: F, extension: Extension);
1206 CmdArgs.push_back(Elt: Args.MakeArgString(Str: F));
1207 }
1208
1209 if (const Arg *A =
1210 Args.getLastArg(Ids: options::OPT_foptimization_record_passes_EQ)) {
1211 CmdArgs.push_back(Elt: "-opt-record-passes");
1212 CmdArgs.push_back(Elt: A->getValue());
1213 }
1214
1215 if (!Format.empty()) {
1216 CmdArgs.push_back(Elt: "-opt-record-format");
1217 CmdArgs.push_back(Elt: Format.data());
1218 }
1219}
1220
1221static void addPGOAndCoverageFlags(const ToolChain &TC, const JobAction &JA,
1222 const ArgList &Args,
1223 ArgStringList &CmdArgs) {
1224 const Driver &D = TC.getDriver();
1225 const llvm::Triple &T = TC.getTriple();
1226
1227 bool IsCudaDevice = JA.isDeviceOffloading(OKind: Action::OFK_Cuda);
1228 bool IsHIPDevice = JA.isDeviceOffloading(OKind: Action::OFK_HIP);
1229
1230 if (T.isOSAIX()) {
1231 if (Arg *ProfileSampleUseArg = getLastProfileSampleUseArg(Args))
1232 D.Diag(DiagID: diag::err_drv_unsupported_opt_for_target)
1233 << ProfileSampleUseArg->getSpelling() << TC.getTriple().str();
1234 }
1235
1236 if (!(IsCudaDevice || IsHIPDevice)) {
1237 // recognise options: -fprofile-sample-use= and -fno-profile-sample-use=
1238 if (Arg *A = getLastProfileSampleUseArg(Args)) {
1239 if (Arg *PGOArg = Args.getLastArg(Ids: options::OPT_fprofile_generate,
1240 Ids: options::OPT_fprofile_generate_EQ)) {
1241 D.Diag(DiagID: diag::err_drv_argument_not_allowed_with)
1242 << PGOArg->getAsString(Args) << A->getAsString(Args);
1243 }
1244
1245 StringRef fname = A->getValue();
1246 if (!llvm::sys::fs::exists(Path: fname))
1247 D.Diag(DiagID: diag::err_drv_no_such_file) << fname;
1248 else
1249 A->render(Args, Output&: CmdArgs);
1250 }
1251 }
1252
1253 //-fpseudo-probe-for-profiling
1254 if (Args.hasFlag(Pos: options::OPT_fpseudo_probe_for_profiling,
1255 Neg: options::OPT_fno_pseudo_probe_for_profiling, Default: false))
1256 CmdArgs.push_back(Elt: "-fpseudo-probe-for-profiling");
1257
1258 // TODO: Consider reusing Clang's addPGOAndCoverageFlags() for
1259 // -fprofile-generate and other similar options handling instead of
1260 // duplicating driver logic here.
1261 if (Arg *PGOGenerateArg = Args.getLastArg(
1262 Ids: options::OPT_fprofile_generate, Ids: options::OPT_fprofile_generate_EQ,
1263 Ids: options::OPT_fno_profile_generate)) {
1264 if (!PGOGenerateArg->getOption().matches(ID: options::OPT_fno_profile_generate))
1265 PGOGenerateArg->render(Args, Output&: CmdArgs);
1266 }
1267
1268 addSplitMachineFunctionsArgs(D: TC.getDriver(), Args, CmdArgs, Triple: TC.getTriple());
1269 Args.addAllArgs(Output&: CmdArgs, Ids: {options::OPT_fprofile_use_EQ});
1270}
1271
1272void Flang::ConstructJob(Compilation &C, const JobAction &JA,
1273 const InputInfo &Output, const InputInfoList &Inputs,
1274 const ArgList &Args, const char *LinkingOutput) const {
1275 const auto &TC = getToolChain();
1276 const llvm::Triple &Triple = TC.getEffectiveTriple();
1277 const std::string &TripleStr = Triple.getTriple();
1278
1279 const Driver &D = TC.getDriver();
1280 ArgStringList CmdArgs;
1281
1282 // Invoke ourselves in -fc1 mode.
1283 CmdArgs.push_back(Elt: "-fc1");
1284
1285 // Add the "effective" target triple.
1286 CmdArgs.push_back(Elt: "-triple");
1287 CmdArgs.push_back(Elt: Args.MakeArgString(Str: TripleStr));
1288
1289 if (isa<PreprocessJobAction>(Val: JA)) {
1290 if (Output.getType() == types::TY_Dependencies) {
1291 CmdArgs.push_back(Elt: "-fsyntax-only");
1292 } else {
1293 CmdArgs.push_back(Elt: "-E");
1294 if (Args.getLastArg(Ids: options::OPT_dM))
1295 CmdArgs.push_back(Elt: "-dM");
1296 }
1297 } else if (isa<CompileJobAction>(Val: JA) || isa<BackendJobAction>(Val: JA)) {
1298 if (JA.getType() == types::TY_Nothing) {
1299 CmdArgs.push_back(Elt: "-fsyntax-only");
1300 } else if (JA.getType() == types::TY_AST) {
1301 CmdArgs.push_back(Elt: "-emit-ast");
1302 } else if (JA.getType() == types::TY_LLVM_IR ||
1303 JA.getType() == types::TY_LTO_IR) {
1304 CmdArgs.push_back(Elt: "-emit-llvm");
1305 } else if (JA.getType() == types::TY_LLVM_BC ||
1306 JA.getType() == types::TY_LTO_BC) {
1307 CmdArgs.push_back(Elt: "-emit-llvm-bc");
1308 } else if (JA.getType() == types::TY_PP_Asm) {
1309 CmdArgs.push_back(Elt: "-S");
1310 } else {
1311 assert(false && "Unexpected output type!");
1312 }
1313 } else if (isa<AssembleJobAction>(Val: JA)) {
1314 CmdArgs.push_back(Elt: "-emit-obj");
1315 } else if (isa<PrecompileJobAction>(Val: JA)) {
1316 // The precompile job action is only needed for options such as -mcpu=help.
1317 // Those will already have been handled by the fc1 driver.
1318 } else {
1319 assert(false && "Unexpected action class for Flang tool.");
1320 }
1321
1322 // We support some options that are invalid for Fortran and have no effect.
1323 // These are solely for compatibility with other compilers. Emit a warning if
1324 // any such options are provided, then proceed normally.
1325 for (options::ID Opt : {options::OPT_fbuiltin, options::OPT_fno_builtin})
1326 if (const Arg *A = Args.getLastArg(Ids: Opt))
1327 D.Diag(DiagID: diag::warn_drv_invalid_argument_for_flang) << A->getSpelling();
1328
1329 // Warn about options that are ignored by flang. These are options that are
1330 // accepted by gfortran, but have no equivalent in flang.
1331 for (const Arg *A :
1332 Args.filtered(Ids: options::OPT_clang_ignored_gcc_optimization_f_Group)) {
1333 D.Diag(DiagID: diag::warn_ignored_gcc_optimization) << A->getAsString(Args);
1334 A->claim();
1335 }
1336
1337 // -fkeep-inline-functions/-fno-keep-inline-functions are real Clang options
1338 // but are not supported by Flang; warn and ignore them.
1339 for (options::ID Opt : {options::OPT_fkeep_inline_functions,
1340 options::OPT_fno_keep_inline_functions}) {
1341 if (const Arg *A = Args.getLastArg(Ids: Opt)) {
1342 D.Diag(DiagID: diag::warn_ignored_gcc_optimization) << A->getAsString(Args);
1343 A->claim();
1344 }
1345 }
1346
1347 const InputInfo &Input = Inputs[0];
1348 types::ID InputType = Input.getType();
1349
1350 // Add preprocessing options like -I, -D, etc. if we are using the
1351 // preprocessor (i.e. skip when dealing with e.g. binary files).
1352 if (types::getPreprocessedType(Id: InputType) != types::TY_INVALID)
1353 addPreprocessingOptions(Args, CmdArgs);
1354
1355 addFortranDialectOptions(Args, CmdArgs);
1356
1357 // 'flang -E' always produces output that is suitable for use as fixed form
1358 // Fortran. However it is only valid free form source if the original is also
1359 // free form. Ensure this logic does not incorrectly assume fixed-form for
1360 // cases where it shouldn't, such as `flang -x f95 foo.f90`.
1361 bool isAtemporaryPreprocessedFile =
1362 Input.isFilename() &&
1363 llvm::sys::path::extension(path: Input.getFilename())
1364 .ends_with(Suffix: types::getTypeTempSuffix(Id: InputType, /*CLStyle=*/false));
1365 if (InputType == types::TY_PP_Fortran && isAtemporaryPreprocessedFile &&
1366 !Args.getLastArg(Ids: options::OPT_ffixed_form, Ids: options::OPT_ffree_form))
1367 CmdArgs.push_back(Elt: "-ffixed-form");
1368
1369 handleColorDiagnosticsArgs(D, Args, CmdArgs);
1370
1371 addLTOOptions(Args, CmdArgs);
1372
1373 // -fPIC and related options.
1374 addPicOptions(Args, CmdArgs);
1375
1376 // Floating point related options
1377 addFloatingPointOptions(D, Args, CmdArgs);
1378
1379 // Initial floating-point exception halting mode. Handled separately so it is
1380 // not skipped by the -ffast-math fast path in addFloatingPointOptions().
1381 addIEEEFPModesOptions(D, Args, CmdArgs, Triple);
1382
1383 // Integer MOD/MODULO zero-divisor check. Forwarded here with -ffpe-trap=
1384 // rather than in addFloatingPointOptions() so -ffast-math does not drop it.
1385 Args.AddLastArg(Output&: CmdArgs, Ids: options::OPT_fcheck_integer_mod_zero_divisor);
1386
1387 // Add target args, features, etc.
1388 addTargetOptions(Args, CmdArgs, BA: JA.getOffloadingArch(),
1389 DeviceOffloadKind: JA.getOffloadingDeviceKind());
1390
1391 if (!TC.useIntegratedAs())
1392 CmdArgs.push_back(Elt: "-no-integrated-as");
1393
1394 llvm::Reloc::Model RelocationModel =
1395 std::get<0>(t: ParsePICArgs(ToolChain: getToolChain(), Args));
1396 // Add MCModel information
1397 addMCModel(D, Args, Triple, RelocationModel, CmdArgs);
1398
1399 // Add Codegen options
1400 addCodegenOptions(Args, CmdArgs);
1401
1402 // Add R Group options
1403 Args.AddAllArgs(Output&: CmdArgs, Id0: options::OPT_R_Group);
1404
1405 // Remarks can be enabled with any of the `-f.*optimization-record.*` flags.
1406 if (willEmitRemarks(Args))
1407 renderRemarksOptions(Args, CmdArgs, Input);
1408
1409 // Add debug compile options
1410 addDebugOptions(Args, JA, Output, Input, CmdArgs);
1411
1412 // Disable all warnings
1413 // TODO: Handle interactions between -w, -pedantic, -Wall, -WOption
1414 Args.AddLastArg(Output&: CmdArgs, Ids: options::OPT_w);
1415
1416 addPGOAndCoverageFlags(TC, JA, Args, CmdArgs);
1417
1418 // Forward flags for OpenMP. We don't do this if the current action is an
1419 // device offloading action other than OpenMP.
1420 if (Args.hasFlag(Pos: options::OPT_fopenmp, PosAlias: options::OPT_fopenmp_EQ,
1421 Neg: options::OPT_fno_openmp, Default: false) &&
1422 (JA.isDeviceOffloading(OKind: Action::OFK_None) ||
1423 JA.isDeviceOffloading(OKind: Action::OFK_OpenMP))) {
1424 switch (D.getOpenMPRuntime(Args)) {
1425 case Driver::OMPRT_OMP:
1426 case Driver::OMPRT_IOMP5:
1427 // Clang can generate useful OpenMP code for these two runtime libraries.
1428 CmdArgs.push_back(Elt: "-fopenmp");
1429 Args.AddAllArgs(Output&: CmdArgs, Id0: options::OPT_fopenmp_version_EQ);
1430
1431 if (Args.hasArg(Ids: options::OPT_fopenmp_force_usm))
1432 CmdArgs.push_back(Elt: "-fopenmp-force-usm");
1433 Args.AddLastArg(Output&: CmdArgs, Ids: options::OPT_fopenmp_simd,
1434 Ids: options::OPT_fno_openmp_simd);
1435
1436 // FIXME: Clang supports a whole bunch more flags here.
1437 break;
1438 default:
1439 // By default, if Clang doesn't know how to generate useful OpenMP code
1440 // for a specific runtime library, we just don't pass the '-fopenmp' flag
1441 // down to the actual compilation.
1442 // FIXME: It would be better to have a mode which *only* omits IR
1443 // generation based on the OpenMP support so that we get consistent
1444 // semantic analysis, etc.
1445 const Arg *A = Args.getLastArg(Ids: options::OPT_fopenmp_EQ);
1446 D.Diag(DiagID: diag::warn_drv_unsupported_openmp_library)
1447 << A->getSpelling() << A->getValue();
1448 break;
1449 }
1450 } else {
1451 Args.AddLastArg(Output&: CmdArgs, Ids: options::OPT_fopenmp_simd,
1452 Ids: options::OPT_fno_openmp_simd);
1453 }
1454
1455 // Pass the path to compiler resource files.
1456 CmdArgs.push_back(Elt: "-resource-dir");
1457 CmdArgs.push_back(Elt: D.ResourceDir.c_str());
1458
1459 // Default intrinsic module dirs must be added after any user-provided dirs in
1460 // -fintrinsic-modules-path since the default dirs have lower precedence than
1461 // user-provided dirs
1462 if (std::optional<std::string> IntrModPath =
1463 TC.getDefaultIntrinsicModuleDir()) {
1464 CmdArgs.push_back(Elt: "-fintrinsic-modules-path");
1465 CmdArgs.push_back(Elt: Args.MakeArgString(Str: *IntrModPath));
1466 }
1467
1468 // Ideally, every target triple has its own set of builtin modules since they
1469 // are compiled with platform-dependent conditionals such as `#if __x86_64__`.
1470 // However, getting the builtin modules for offload targets requires building
1471 // the flang-rt and openmp for those targets as well:
1472 // -DLLVM_RUNTIME_TARGETS=default;amdgcn-amd-amdhsa;nvptx64-nvidia-cuda.
1473 // To reduce friction when build systems have not yet been updated, we also
1474 // add the host's builtin module to the search path (with lower priority), in
1475 // case a module file has not been found for the offload targets itself.
1476 // FIXME: This workaround may mix module files targeting different triples and
1477 // should eventually be removed.
1478 auto &&HostTCs =
1479 C.getOffloadToolChains<clang::driver::OffloadAction ::OFK_Host>();
1480 for (auto [OKind, HostTC] : llvm::make_range(x: HostTCs.first, y: HostTCs.second)) {
1481 if (HostTC == &TC)
1482 continue;
1483
1484 if (std::optional<std::string> IntrModPath =
1485 HostTC->getDefaultIntrinsicModuleDir()) {
1486 CmdArgs.push_back(Elt: "-fintrinsic-modules-path");
1487 CmdArgs.push_back(Elt: Args.MakeArgString(Str: *IntrModPath));
1488 }
1489 }
1490
1491 // Offloading related options
1492 addOffloadOptions(C, Inputs, JA, Args, CmdArgs);
1493
1494 // Forward -Xflang arguments to -fc1
1495 Args.AddAllArgValues(Output&: CmdArgs, Id0: options::OPT_Xflang);
1496
1497 CodeGenOptions::FramePointerKind FPKeepKind =
1498 getFramePointerKind(Args, Triple);
1499
1500 const char *FPKeepKindStr = nullptr;
1501 switch (FPKeepKind) {
1502 case CodeGenOptions::FramePointerKind::None:
1503 FPKeepKindStr = "-mframe-pointer=none";
1504 break;
1505 case CodeGenOptions::FramePointerKind::Reserved:
1506 FPKeepKindStr = "-mframe-pointer=reserved";
1507 break;
1508 case CodeGenOptions::FramePointerKind::NonLeafNoReserve:
1509 FPKeepKindStr = "-mframe-pointer=non-leaf-no-reserve";
1510 break;
1511 case CodeGenOptions::FramePointerKind::NonLeaf:
1512 FPKeepKindStr = "-mframe-pointer=non-leaf";
1513 break;
1514 case CodeGenOptions::FramePointerKind::All:
1515 FPKeepKindStr = "-mframe-pointer=all";
1516 break;
1517 }
1518 assert(FPKeepKindStr && "unknown FramePointerKind");
1519 CmdArgs.push_back(Elt: FPKeepKindStr);
1520
1521 // Forward -mllvm options to the LLVM option parser. In practice, this means
1522 // forwarding to `-fc1` as that's where the LLVM parser is run.
1523 for (const Arg *A : Args.filtered(Ids: options::OPT_mllvm)) {
1524 A->claim();
1525 A->render(Args, Output&: CmdArgs);
1526 }
1527
1528 for (const Arg *A : Args.filtered(Ids: options::OPT_mmlir)) {
1529 A->claim();
1530 A->render(Args, Output&: CmdArgs);
1531 }
1532
1533 // Remove any unsupported gfortran diagnostic options
1534 for (const Arg *A : Args.filtered(Ids: options::OPT_flang_ignored_w_Group)) {
1535 A->claim();
1536 D.Diag(DiagID: diag::warn_drv_unsupported_diag_option_for_flang)
1537 << A->getOption().getName();
1538 }
1539
1540 // Optimization level for CodeGen.
1541 if (const Arg *A = Args.getLastArg(Ids: options::OPT_O_Group)) {
1542 if (A->getOption().matches(ID: options::OPT_O4)) {
1543 CmdArgs.push_back(Elt: "-O3");
1544 D.Diag(DiagID: diag::warn_O4_is_O3);
1545 } else if (A->getOption().matches(ID: options::OPT_Ofast)) {
1546 CmdArgs.push_back(Elt: "-O3");
1547 D.Diag(DiagID: diag::warn_drv_deprecated_arg_ofast_for_flang);
1548 } else {
1549 A->render(Args, Output&: CmdArgs);
1550 }
1551 }
1552
1553 renderGlobalISelOptions(D, Args, CmdArgs, Triple);
1554 renderCommonIntegerOverflowOptions(Args, CmdArgs, IsMSVCCompat: false);
1555
1556 assert((Output.isFilename() || Output.isNothing()) && "Invalid output.");
1557 if (Output.isFilename()) {
1558 CmdArgs.push_back(Elt: "-o");
1559 CmdArgs.push_back(Elt: Output.getFilename());
1560 }
1561
1562 if (Args.getLastArg(Ids: options::OPT_save_temps_EQ))
1563 Args.AddLastArg(Output&: CmdArgs, Ids: options::OPT_save_temps_EQ);
1564
1565 renderDependencyGenerationOptions(C, JA, Args, Output, Inputs, CmdArgs);
1566
1567 addDashXForInput(Args, Input, CmdArgs);
1568
1569 bool FRecordCmdLine = false;
1570 bool GRecordCmdLine = false;
1571 bool DXRecordCmdLine = false;
1572 if (shouldRecordCommandLine(TC, Args, FRecordCommandLine&: FRecordCmdLine, GRecordCommandLine&: GRecordCmdLine,
1573 DXRecordCommandLine&: DXRecordCmdLine)) {
1574 const char *CmdLine = renderEscapedCommandLine(TC, Args);
1575 if (FRecordCmdLine) {
1576 CmdArgs.push_back(Elt: "-record-command-line");
1577 CmdArgs.push_back(Elt: CmdLine);
1578 }
1579 if (TC.UseDwarfDebugFlags() || GRecordCmdLine) {
1580 CmdArgs.push_back(Elt: "-dwarf-debug-flags");
1581 CmdArgs.push_back(Elt: CmdLine);
1582 }
1583 }
1584
1585 // The input could be Ty_Nothing when "querying" options such as -mcpu=help
1586 // are used.
1587 ArrayRef<InputInfo> FrontendInputs = Input;
1588 if (Input.isNothing())
1589 FrontendInputs = {};
1590
1591 for (const InputInfo &Input : FrontendInputs) {
1592 if (Input.isFilename())
1593 CmdArgs.push_back(Elt: Input.getFilename());
1594 else
1595 Input.getInputArg().renderAsInput(Args, Output&: CmdArgs);
1596 }
1597
1598 // Handle "clang --driver-mode=flang" case
1599 bool isClangDriverWithFlangMode = false;
1600 std::string DriverName = D.Name;
1601 if (const char *PA = D.getPrependArg())
1602 DriverName = PA;
1603 if (DriverName.find(s: "clang") != std::string::npos && D.IsFlangMode())
1604 isClangDriverWithFlangMode = true;
1605
1606 const char *Exec = isClangDriverWithFlangMode
1607 ? Args.MakeArgString(Str: D.GetProgramPath(Name: "flang", TC))
1608 : D.getDriverProgramPath();
1609 C.addCommand(Cmd: std::make_unique<Command>(args: JA, args: *this,
1610 args: ResponseFileSupport::AtFileUTF8(),
1611 args&: Exec, args&: CmdArgs, args: Inputs, args: Output));
1612}
1613
1614Flang::Flang(const ToolChain &TC) : Tool("flang", "flang frontend", TC) {}
1615
1616Flang::~Flang() {}
1617