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