1 //===-- Flang.cpp - Flang+LLVM ToolChain Implementations --------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
10 #include "Arch/RISCV.h"
11 #include "CommonArgs.h"
13 #include "clang/Basic/CodeGenOptions.h"
14 #include "clang/Driver/Options.h"
15 #include "llvm/Frontend/Debug/Options.h"
16 #include "llvm/Support/FileSystem.h"
17 #include "llvm/Support/Path.h"
18 #include "llvm/TargetParser/Host.h"
19 #include "llvm/TargetParser/RISCVISAInfo.h"
20 #include "llvm/TargetParser/RISCVTargetParser.h"
24 using namespace clang::driver
;
25 using namespace clang::driver::tools
;
26 using namespace clang
;
27 using namespace llvm::opt
;
29 /// Add -x lang to \p CmdArgs for \p Input.
30 static void addDashXForInput(const ArgList
&Args
, const InputInfo
&Input
,
31 ArgStringList
&CmdArgs
) {
32 CmdArgs
.push_back("-x");
33 // Map the driver type to the frontend type.
34 CmdArgs
.push_back(types::getTypeName(Input
.getType()));
37 void Flang::addFortranDialectOptions(const ArgList
&Args
,
38 ArgStringList
&CmdArgs
) const {
39 Args
.addAllArgs(CmdArgs
, {options::OPT_ffixed_form
,
40 options::OPT_ffree_form
,
41 options::OPT_ffixed_line_length_EQ
,
42 options::OPT_fopenacc
,
43 options::OPT_finput_charset_EQ
,
44 options::OPT_fimplicit_none
,
45 options::OPT_fno_implicit_none
,
46 options::OPT_fbackslash
,
47 options::OPT_fno_backslash
,
48 options::OPT_flogical_abbreviations
,
49 options::OPT_fno_logical_abbreviations
,
50 options::OPT_fxor_operator
,
51 options::OPT_fno_xor_operator
,
52 options::OPT_falternative_parameter_statement
,
53 options::OPT_fdefault_real_8
,
54 options::OPT_fdefault_integer_8
,
55 options::OPT_fdefault_double_8
,
56 options::OPT_flarge_sizes
,
57 options::OPT_fno_automatic
,
58 options::OPT_fhermetic_module_files
});
61 void Flang::addPreprocessingOptions(const ArgList
&Args
,
62 ArgStringList
&CmdArgs
) const {
63 Args
.addAllArgs(CmdArgs
,
64 {options::OPT_P
, options::OPT_D
, options::OPT_U
,
65 options::OPT_I
, options::OPT_cpp
, options::OPT_nocpp
});
68 /// @C shouldLoopVersion
70 /// Check if Loop Versioning should be enabled.
71 /// We look for the last of one of the following:
72 /// -Ofast, -O4, -O<number> and -f[no-]version-loops-for-stride.
73 /// Loop versioning is disabled if the last option is
74 /// -fno-version-loops-for-stride.
75 /// Loop versioning is enabled if the last option is one of:
80 /// For all other cases, loop versioning is is disabled.
82 /// The gfortran compiler automatically enables the option for -O3 or -Ofast.
84 /// @return true if loop-versioning should be enabled, otherwise false.
85 static bool shouldLoopVersion(const ArgList
&Args
) {
86 const Arg
*LoopVersioningArg
= Args
.getLastArg(
87 options::OPT_Ofast
, options::OPT_O
, options::OPT_O4
,
88 options::OPT_floop_versioning
, options::OPT_fno_loop_versioning
);
89 if (!LoopVersioningArg
)
92 if (LoopVersioningArg
->getOption().matches(options::OPT_fno_loop_versioning
))
95 if (LoopVersioningArg
->getOption().matches(options::OPT_floop_versioning
))
98 if (LoopVersioningArg
->getOption().matches(options::OPT_Ofast
) ||
99 LoopVersioningArg
->getOption().matches(options::OPT_O4
))
102 if (LoopVersioningArg
->getOption().matches(options::OPT_O
)) {
103 StringRef
S(LoopVersioningArg
->getValue());
104 unsigned OptLevel
= 0;
105 // Note -Os or Oz woould "fail" here, so return false. Which is the
106 // desiered behavior.
107 if (S
.getAsInteger(10, OptLevel
))
113 llvm_unreachable("We should not end up here");
117 void Flang::addOtherOptions(const ArgList
&Args
, ArgStringList
&CmdArgs
) const {
118 Args
.addAllArgs(CmdArgs
,
119 {options::OPT_module_dir
, options::OPT_fdebug_module_writer
,
120 options::OPT_fintrinsic_modules_path
, options::OPT_pedantic
,
121 options::OPT_std_EQ
, options::OPT_W_Joined
,
122 options::OPT_fconvert_EQ
, options::OPT_fpass_plugin_EQ
,
123 options::OPT_funderscoring
, options::OPT_fno_underscoring
});
125 llvm::codegenoptions::DebugInfoKind DebugInfoKind
;
126 if (Args
.hasArg(options::OPT_gN_Group
)) {
127 Arg
*gNArg
= Args
.getLastArg(options::OPT_gN_Group
);
128 DebugInfoKind
= debugLevelToInfoKind(*gNArg
);
129 } else if (Args
.hasArg(options::OPT_g_Flag
)) {
130 DebugInfoKind
= llvm::codegenoptions::FullDebugInfo
;
132 DebugInfoKind
= llvm::codegenoptions::NoDebugInfo
;
134 addDebugInfoKind(CmdArgs
, DebugInfoKind
);
137 void Flang::addCodegenOptions(const ArgList
&Args
,
138 ArgStringList
&CmdArgs
) const {
140 Args
.getLastArg(options::OPT_Ofast
, options::OPT_fstack_arrays
,
141 options::OPT_fno_stack_arrays
);
143 !stackArrays
->getOption().matches(options::OPT_fno_stack_arrays
))
144 CmdArgs
.push_back("-fstack-arrays");
146 if (shouldLoopVersion(Args
))
147 CmdArgs
.push_back("-fversion-loops-for-stride");
149 Args
.addAllArgs(CmdArgs
, {options::OPT_flang_experimental_hlfir
,
150 options::OPT_flang_deprecated_no_hlfir
,
151 options::OPT_fno_ppc_native_vec_elem_order
,
152 options::OPT_fppc_native_vec_elem_order
});
155 void Flang::addPicOptions(const ArgList
&Args
, ArgStringList
&CmdArgs
) const {
156 // ParsePICArgs parses -fPIC/-fPIE and their variants and returns a tuple of
157 // (RelocationModel, PICLevel, IsPIE).
158 llvm::Reloc::Model RelocationModel
;
161 std::tie(RelocationModel
, PICLevel
, IsPIE
) =
162 ParsePICArgs(getToolChain(), Args
);
164 if (auto *RMName
= RelocationModelName(RelocationModel
)) {
165 CmdArgs
.push_back("-mrelocation-model");
166 CmdArgs
.push_back(RMName
);
169 CmdArgs
.push_back("-pic-level");
170 CmdArgs
.push_back(PICLevel
== 1 ? "1" : "2");
172 CmdArgs
.push_back("-pic-is-pie");
176 void Flang::AddAArch64TargetArgs(const ArgList
&Args
,
177 ArgStringList
&CmdArgs
) const {
178 // Handle -msve_vector_bits=<bits>
179 if (Arg
*A
= Args
.getLastArg(options::OPT_msve_vector_bits_EQ
)) {
180 StringRef Val
= A
->getValue();
181 const Driver
&D
= getToolChain().getDriver();
182 if (Val
== "128" || Val
== "256" || Val
== "512" || Val
== "1024" ||
183 Val
== "2048" || Val
== "128+" || Val
== "256+" || Val
== "512+" ||
184 Val
== "1024+" || Val
== "2048+") {
186 if (!Val
.consume_back("+")) {
187 [[maybe_unused
]] bool Invalid
= Val
.getAsInteger(10, Bits
);
188 assert(!Invalid
&& "Failed to parse value");
190 Args
.MakeArgString("-mvscale-max=" + llvm::Twine(Bits
/ 128)));
193 [[maybe_unused
]] bool Invalid
= Val
.getAsInteger(10, Bits
);
194 assert(!Invalid
&& "Failed to parse value");
196 Args
.MakeArgString("-mvscale-min=" + llvm::Twine(Bits
/ 128)));
197 // Silently drop requests for vector-length agnostic code as it's implied.
198 } else if (Val
!= "scalable")
199 // Handle the unsupported values passed to msve-vector-bits.
200 D
.Diag(diag::err_drv_unsupported_option_argument
)
201 << A
->getSpelling() << Val
;
205 void Flang::AddLoongArch64TargetArgs(const ArgList
&Args
,
206 ArgStringList
&CmdArgs
) const {
207 const Driver
&D
= getToolChain().getDriver();
208 // Currently, flang only support `-mabi=lp64d` in LoongArch64.
209 if (const Arg
*A
= Args
.getLastArg(options::OPT_mabi_EQ
)) {
210 StringRef V
= A
->getValue();
212 D
.Diag(diag::err_drv_argument_not_allowed_with
) << "-mabi" << V
;
216 if (const Arg
*A
= Args
.getLastArg(options::OPT_mannotate_tablejump
,
217 options::OPT_mno_annotate_tablejump
)) {
218 if (A
->getOption().matches(options::OPT_mannotate_tablejump
)) {
219 CmdArgs
.push_back("-mllvm");
220 CmdArgs
.push_back("-loongarch-annotate-tablejump");
225 void Flang::AddPPCTargetArgs(const ArgList
&Args
,
226 ArgStringList
&CmdArgs
) const {
227 const Driver
&D
= getToolChain().getDriver();
228 bool VecExtabi
= false;
230 if (const Arg
*A
= Args
.getLastArg(options::OPT_mabi_EQ
)) {
231 StringRef V
= A
->getValue();
232 if (V
== "vec-extabi")
234 else if (V
== "vec-default")
237 D
.Diag(diag::err_drv_unsupported_option_argument
)
238 << A
->getSpelling() << V
;
241 const llvm::Triple
&T
= getToolChain().getTriple();
244 D
.Diag(diag::err_drv_unsupported_opt_for_target
)
245 << "-mabi=vec-extabi" << T
.str();
247 CmdArgs
.push_back("-mabi=vec-extabi");
251 void Flang::AddRISCVTargetArgs(const ArgList
&Args
,
252 ArgStringList
&CmdArgs
) const {
253 const llvm::Triple
&Triple
= getToolChain().getTriple();
254 // Handle -mrvv-vector-bits=<bits>
255 if (Arg
*A
= Args
.getLastArg(options::OPT_mrvv_vector_bits_EQ
)) {
256 StringRef Val
= A
->getValue();
257 const Driver
&D
= getToolChain().getDriver();
259 // Get minimum VLen from march.
260 unsigned MinVLen
= 0;
261 std::string Arch
= riscv::getRISCVArch(Args
, Triple
);
262 auto ISAInfo
= llvm::RISCVISAInfo::parseArchString(
263 Arch
, /*EnableExperimentalExtensions*/ true);
264 // Ignore parsing error.
265 if (!errorToBool(ISAInfo
.takeError()))
266 MinVLen
= (*ISAInfo
)->getMinVLen();
268 // If the value is "zvl", use MinVLen from march. Otherwise, try to parse
269 // as integer as long as we have a MinVLen.
271 if (Val
== "zvl" && MinVLen
>= llvm::RISCV::RVVBitsPerBlock
) {
273 } else if (!Val
.getAsInteger(10, Bits
)) {
274 // Only accept power of 2 values beteen RVVBitsPerBlock and 65536 that
276 if (Bits
< MinVLen
|| Bits
< llvm::RISCV::RVVBitsPerBlock
||
277 Bits
> 65536 || !llvm::isPowerOf2_32(Bits
))
281 // If we got a valid value try to use it.
283 unsigned VScaleMin
= Bits
/ llvm::RISCV::RVVBitsPerBlock
;
285 Args
.MakeArgString("-mvscale-max=" + llvm::Twine(VScaleMin
)));
287 Args
.MakeArgString("-mvscale-min=" + llvm::Twine(VScaleMin
)));
288 } else if (Val
!= "scalable") {
289 // Handle the unsupported values passed to mrvv-vector-bits.
290 D
.Diag(diag::err_drv_unsupported_option_argument
)
291 << A
->getSpelling() << Val
;
296 void Flang::AddX86_64TargetArgs(const ArgList
&Args
,
297 ArgStringList
&CmdArgs
) const {
298 if (Arg
*A
= Args
.getLastArg(options::OPT_masm_EQ
)) {
299 StringRef Value
= A
->getValue();
300 if (Value
== "intel" || Value
== "att") {
301 CmdArgs
.push_back(Args
.MakeArgString("-mllvm"));
302 CmdArgs
.push_back(Args
.MakeArgString("-x86-asm-syntax=" + Value
));
304 getToolChain().getDriver().Diag(diag::err_drv_unsupported_option_argument
)
305 << A
->getSpelling() << Value
;
310 static void addVSDefines(const ToolChain
&TC
, const ArgList
&Args
,
311 ArgStringList
&CmdArgs
) {
314 const VersionTuple vt
= TC
.computeMSVCVersion(nullptr, Args
);
315 ver
= vt
.getMajor() * 10000000 + vt
.getMinor().value_or(0) * 100000 +
316 vt
.getSubminor().value_or(0);
317 CmdArgs
.push_back(Args
.MakeArgString("-D_MSC_VER=" + Twine(ver
/ 100000)));
318 CmdArgs
.push_back(Args
.MakeArgString("-D_MSC_FULL_VER=" + Twine(ver
)));
319 CmdArgs
.push_back(Args
.MakeArgString("-D_WIN32"));
321 const llvm::Triple
&triple
= TC
.getTriple();
322 if (triple
.isAArch64()) {
323 CmdArgs
.push_back("-D_M_ARM64=1");
324 } else if (triple
.isX86() && triple
.isArch32Bit()) {
325 CmdArgs
.push_back("-D_M_IX86=600");
326 } else if (triple
.isX86() && triple
.isArch64Bit()) {
327 CmdArgs
.push_back("-D_M_X64=100");
330 "Flang on Windows only supports X86_32, X86_64 and AArch64");
334 static void processVSRuntimeLibrary(const ToolChain
&TC
, const ArgList
&Args
,
335 ArgStringList
&CmdArgs
) {
336 assert(TC
.getTriple().isKnownWindowsMSVCEnvironment() &&
337 "can only add VS runtime library on Windows!");
338 // if -fno-fortran-main has been passed, skip linking Fortran_main.a
339 if (TC
.getTriple().isKnownWindowsMSVCEnvironment()) {
340 CmdArgs
.push_back(Args
.MakeArgString(
341 "--dependent-lib=" + TC
.getCompilerRTBasename(Args
, "builtins")));
343 unsigned RTOptionID
= options::OPT__SLASH_MT
;
344 if (auto *rtl
= Args
.getLastArg(options::OPT_fms_runtime_lib_EQ
)) {
345 RTOptionID
= llvm::StringSwitch
<unsigned>(rtl
->getValue())
346 .Case("static", options::OPT__SLASH_MT
)
347 .Case("static_dbg", options::OPT__SLASH_MTd
)
348 .Case("dll", options::OPT__SLASH_MD
)
349 .Case("dll_dbg", options::OPT__SLASH_MDd
)
350 .Default(options::OPT__SLASH_MT
);
352 switch (RTOptionID
) {
353 case options::OPT__SLASH_MT
:
354 CmdArgs
.push_back("-D_MT");
355 CmdArgs
.push_back("--dependent-lib=libcmt");
356 CmdArgs
.push_back("--dependent-lib=FortranRuntime.static.lib");
357 CmdArgs
.push_back("--dependent-lib=FortranDecimal.static.lib");
359 case options::OPT__SLASH_MTd
:
360 CmdArgs
.push_back("-D_MT");
361 CmdArgs
.push_back("-D_DEBUG");
362 CmdArgs
.push_back("--dependent-lib=libcmtd");
363 CmdArgs
.push_back("--dependent-lib=FortranRuntime.static_dbg.lib");
364 CmdArgs
.push_back("--dependent-lib=FortranDecimal.static_dbg.lib");
366 case options::OPT__SLASH_MD
:
367 CmdArgs
.push_back("-D_MT");
368 CmdArgs
.push_back("-D_DLL");
369 CmdArgs
.push_back("--dependent-lib=msvcrt");
370 CmdArgs
.push_back("--dependent-lib=FortranRuntime.dynamic.lib");
371 CmdArgs
.push_back("--dependent-lib=FortranDecimal.dynamic.lib");
373 case options::OPT__SLASH_MDd
:
374 CmdArgs
.push_back("-D_MT");
375 CmdArgs
.push_back("-D_DEBUG");
376 CmdArgs
.push_back("-D_DLL");
377 CmdArgs
.push_back("--dependent-lib=msvcrtd");
378 CmdArgs
.push_back("--dependent-lib=FortranRuntime.dynamic_dbg.lib");
379 CmdArgs
.push_back("--dependent-lib=FortranDecimal.dynamic_dbg.lib");
384 void Flang::AddAMDGPUTargetArgs(const ArgList
&Args
,
385 ArgStringList
&CmdArgs
) const {
386 if (Arg
*A
= Args
.getLastArg(options::OPT_mcode_object_version_EQ
)) {
387 StringRef Val
= A
->getValue();
388 CmdArgs
.push_back(Args
.MakeArgString("-mcode-object-version=" + Val
));
391 const ToolChain
&TC
= getToolChain();
392 TC
.addClangTargetOptions(Args
, CmdArgs
, Action::OffloadKind::OFK_OpenMP
);
395 void Flang::addTargetOptions(const ArgList
&Args
,
396 ArgStringList
&CmdArgs
) const {
397 const ToolChain
&TC
= getToolChain();
398 const llvm::Triple
&Triple
= TC
.getEffectiveTriple();
399 const Driver
&D
= TC
.getDriver();
401 std::string CPU
= getCPUName(D
, Args
, Triple
);
403 CmdArgs
.push_back("-target-cpu");
404 CmdArgs
.push_back(Args
.MakeArgString(CPU
));
407 addOutlineAtomicsArgs(D
, getToolChain(), Args
, CmdArgs
, Triple
);
409 // Add the target features.
410 switch (TC
.getArch()) {
413 case llvm::Triple::aarch64
:
414 getTargetFeatures(D
, Triple
, Args
, CmdArgs
, /*ForAs*/ false);
415 AddAArch64TargetArgs(Args
, CmdArgs
);
418 case llvm::Triple::r600
:
419 case llvm::Triple::amdgcn
:
420 getTargetFeatures(D
, Triple
, Args
, CmdArgs
, /*ForAs*/ false);
421 AddAMDGPUTargetArgs(Args
, CmdArgs
);
423 case llvm::Triple::riscv64
:
424 getTargetFeatures(D
, Triple
, Args
, CmdArgs
, /*ForAs*/ false);
425 AddRISCVTargetArgs(Args
, CmdArgs
);
427 case llvm::Triple::x86_64
:
428 getTargetFeatures(D
, Triple
, Args
, CmdArgs
, /*ForAs*/ false);
429 AddX86_64TargetArgs(Args
, CmdArgs
);
431 case llvm::Triple::ppc
:
432 case llvm::Triple::ppc64
:
433 case llvm::Triple::ppc64le
:
434 AddPPCTargetArgs(Args
, CmdArgs
);
436 case llvm::Triple::loongarch64
:
437 getTargetFeatures(D
, Triple
, Args
, CmdArgs
, /*ForAs*/ false);
438 AddLoongArch64TargetArgs(Args
, CmdArgs
);
442 if (Arg
*A
= Args
.getLastArg(options::OPT_fveclib
)) {
443 StringRef Name
= A
->getValue();
444 if (Name
== "SVML") {
445 if (Triple
.getArch() != llvm::Triple::x86
&&
446 Triple
.getArch() != llvm::Triple::x86_64
)
447 D
.Diag(diag::err_drv_unsupported_opt_for_target
)
448 << Name
<< Triple
.getArchName();
449 } else if (Name
== "LIBMVEC-X86") {
450 if (Triple
.getArch() != llvm::Triple::x86
&&
451 Triple
.getArch() != llvm::Triple::x86_64
)
452 D
.Diag(diag::err_drv_unsupported_opt_for_target
)
453 << Name
<< Triple
.getArchName();
454 } else if (Name
== "SLEEF" || Name
== "ArmPL") {
455 if (Triple
.getArch() != llvm::Triple::aarch64
&&
456 Triple
.getArch() != llvm::Triple::aarch64_be
)
457 D
.Diag(diag::err_drv_unsupported_opt_for_target
)
458 << Name
<< Triple
.getArchName();
461 if (Triple
.isOSDarwin()) {
462 // flang doesn't currently suport nostdlib, nodefaultlibs. Adding these
463 // here incase they are added someday
464 if (!Args
.hasArg(options::OPT_nostdlib
, options::OPT_nodefaultlibs
)) {
465 if (A
->getValue() == StringRef
{"Accelerate"}) {
466 CmdArgs
.push_back("-framework");
467 CmdArgs
.push_back("Accelerate");
471 A
->render(Args
, CmdArgs
);
474 if (Triple
.isKnownWindowsMSVCEnvironment()) {
475 processVSRuntimeLibrary(TC
, Args
, CmdArgs
);
476 addVSDefines(TC
, Args
, CmdArgs
);
479 // TODO: Add target specific flags, ABI, mtune option etc.
480 if (const Arg
*A
= Args
.getLastArg(options::OPT_mtune_EQ
)) {
481 CmdArgs
.push_back("-tune-cpu");
482 if (A
->getValue() == StringRef
{"native"})
483 CmdArgs
.push_back(Args
.MakeArgString(llvm::sys::getHostCPUName()));
485 CmdArgs
.push_back(A
->getValue());
489 void Flang::addOffloadOptions(Compilation
&C
, const InputInfoList
&Inputs
,
490 const JobAction
&JA
, const ArgList
&Args
,
491 ArgStringList
&CmdArgs
) const {
492 bool IsOpenMPDevice
= JA
.isDeviceOffloading(Action::OFK_OpenMP
);
493 bool IsHostOffloadingAction
= JA
.isHostOffloading(Action::OFK_OpenMP
) ||
494 JA
.isHostOffloading(C
.getActiveOffloadKinds());
496 // Skips the primary input file, which is the input file that the compilation
497 // proccess will be executed upon (e.g. the host bitcode file) and
498 // adds other secondary input (e.g. device bitcode files for embedding to the
499 // -fembed-offload-object argument or the host IR file for proccessing
500 // during device compilation to the fopenmp-host-ir-file-path argument via
501 // OpenMPDeviceInput). This is condensed logic from the ConstructJob
502 // function inside of the Clang driver for pushing on further input arguments
503 // needed for offloading during various phases of compilation.
504 for (size_t i
= 1; i
< Inputs
.size(); ++i
) {
505 if (Inputs
[i
].getType() == types::TY_Nothing
) {
506 // contains nothing, so it's skippable
507 } else if (IsHostOffloadingAction
) {
509 Args
.MakeArgString("-fembed-offload-object=" +
510 getToolChain().getInputFilename(Inputs
[i
])));
511 } else if (IsOpenMPDevice
) {
512 if (Inputs
[i
].getFilename()) {
513 CmdArgs
.push_back("-fopenmp-host-ir-file-path");
514 CmdArgs
.push_back(Args
.MakeArgString(Inputs
[i
].getFilename()));
516 llvm_unreachable("missing openmp host-ir file for device offloading");
520 "unexpectedly given multiple inputs or given unknown input");
524 if (IsOpenMPDevice
) {
525 // -fopenmp-is-target-device is passed along to tell the frontend that it is
526 // generating code for a device, so that only the relevant code is emitted.
527 CmdArgs
.push_back("-fopenmp-is-target-device");
529 // When in OpenMP offloading mode, enable debugging on the device.
530 Args
.AddAllArgs(CmdArgs
, options::OPT_fopenmp_target_debug_EQ
);
531 if (Args
.hasFlag(options::OPT_fopenmp_target_debug
,
532 options::OPT_fno_openmp_target_debug
, /*Default=*/false))
533 CmdArgs
.push_back("-fopenmp-target-debug");
535 // When in OpenMP offloading mode, forward assumptions information about
536 // thread and team counts in the device.
537 if (Args
.hasFlag(options::OPT_fopenmp_assume_teams_oversubscription
,
538 options::OPT_fno_openmp_assume_teams_oversubscription
,
540 CmdArgs
.push_back("-fopenmp-assume-teams-oversubscription");
541 if (Args
.hasFlag(options::OPT_fopenmp_assume_threads_oversubscription
,
542 options::OPT_fno_openmp_assume_threads_oversubscription
,
544 CmdArgs
.push_back("-fopenmp-assume-threads-oversubscription");
545 if (Args
.hasArg(options::OPT_fopenmp_assume_no_thread_state
))
546 CmdArgs
.push_back("-fopenmp-assume-no-thread-state");
547 if (Args
.hasArg(options::OPT_fopenmp_assume_no_nested_parallelism
))
548 CmdArgs
.push_back("-fopenmp-assume-no-nested-parallelism");
549 if (Args
.hasArg(options::OPT_nogpulib
))
550 CmdArgs
.push_back("-nogpulib");
553 addOpenMPHostOffloadingArgs(C
, JA
, Args
, CmdArgs
);
556 static void addFloatingPointOptions(const Driver
&D
, const ArgList
&Args
,
557 ArgStringList
&CmdArgs
) {
558 StringRef FPContract
;
559 bool HonorINFs
= true;
560 bool HonorNaNs
= true;
561 bool ApproxFunc
= false;
562 bool SignedZeros
= true;
563 bool AssociativeMath
= false;
564 bool ReciprocalMath
= false;
566 if (const Arg
*A
= Args
.getLastArg(options::OPT_ffp_contract
)) {
567 const StringRef Val
= A
->getValue();
568 if (Val
== "fast" || Val
== "off") {
570 } else if (Val
== "on") {
571 // Warn instead of error because users might have makefiles written for
572 // gfortran (which accepts -ffp-contract=on)
573 D
.Diag(diag::warn_drv_unsupported_option_for_flang
)
574 << Val
<< A
->getOption().getName() << "off";
577 // Clang's "fast-honor-pragmas" option is not supported because it is
579 D
.Diag(diag::err_drv_unsupported_option_argument
)
580 << A
->getSpelling() << Val
;
583 for (const Arg
*A
: Args
) {
584 auto optId
= A
->getOption().getID();
586 // if this isn't an FP option, skip the claim below
590 case options::OPT_fhonor_infinities
:
593 case options::OPT_fno_honor_infinities
:
596 case options::OPT_fhonor_nans
:
599 case options::OPT_fno_honor_nans
:
602 case options::OPT_fapprox_func
:
605 case options::OPT_fno_approx_func
:
608 case options::OPT_fsigned_zeros
:
611 case options::OPT_fno_signed_zeros
:
614 case options::OPT_fassociative_math
:
615 AssociativeMath
= true;
617 case options::OPT_fno_associative_math
:
618 AssociativeMath
= false;
620 case options::OPT_freciprocal_math
:
621 ReciprocalMath
= true;
623 case options::OPT_fno_reciprocal_math
:
624 ReciprocalMath
= false;
626 case options::OPT_Ofast
:
628 case options::OPT_ffast_math
:
631 AssociativeMath
= true;
632 ReciprocalMath
= true;
637 case options::OPT_fno_fast_math
:
640 AssociativeMath
= false;
641 ReciprocalMath
= false;
644 // -fno-fast-math should undo -ffast-math so I return FPContract to the
645 // default. It is important to check it is "fast" (the default) so that
646 // --ffp-contract=off -fno-fast-math --> -ffp-contract=off
647 if (FPContract
== "fast")
652 // If we handled this option claim it
656 if (!HonorINFs
&& !HonorNaNs
&& AssociativeMath
&& ReciprocalMath
&&
657 ApproxFunc
&& !SignedZeros
&&
658 (FPContract
== "fast" || FPContract
.empty())) {
659 CmdArgs
.push_back("-ffast-math");
663 if (!FPContract
.empty())
664 CmdArgs
.push_back(Args
.MakeArgString("-ffp-contract=" + FPContract
));
667 CmdArgs
.push_back("-menable-no-infs");
670 CmdArgs
.push_back("-menable-no-nans");
673 CmdArgs
.push_back("-fapprox-func");
676 CmdArgs
.push_back("-fno-signed-zeros");
678 if (AssociativeMath
&& !SignedZeros
)
679 CmdArgs
.push_back("-mreassociate");
682 CmdArgs
.push_back("-freciprocal-math");
685 static void renderRemarksOptions(const ArgList
&Args
, ArgStringList
&CmdArgs
,
686 const InputInfo
&Input
) {
687 StringRef Format
= "yaml";
688 if (const Arg
*A
= Args
.getLastArg(options::OPT_fsave_optimization_record_EQ
))
689 Format
= A
->getValue();
691 CmdArgs
.push_back("-opt-record-file");
693 const Arg
*A
= Args
.getLastArg(options::OPT_foptimization_record_file_EQ
);
695 CmdArgs
.push_back(A
->getValue());
699 if (Args
.hasArg(options::OPT_c
) || Args
.hasArg(options::OPT_S
)) {
700 if (Arg
*FinalOutput
= Args
.getLastArg(options::OPT_o
))
701 F
= FinalOutput
->getValue();
705 // Use the input filename.
706 F
= llvm::sys::path::stem(Input
.getBaseInput());
709 SmallString
<32> Extension
;
713 llvm::sys::path::replace_extension(F
, Extension
);
714 CmdArgs
.push_back(Args
.MakeArgString(F
));
718 Args
.getLastArg(options::OPT_foptimization_record_passes_EQ
)) {
719 CmdArgs
.push_back("-opt-record-passes");
720 CmdArgs
.push_back(A
->getValue());
723 if (!Format
.empty()) {
724 CmdArgs
.push_back("-opt-record-format");
725 CmdArgs
.push_back(Format
.data());
729 void Flang::ConstructJob(Compilation
&C
, const JobAction
&JA
,
730 const InputInfo
&Output
, const InputInfoList
&Inputs
,
731 const ArgList
&Args
, const char *LinkingOutput
) const {
732 const auto &TC
= getToolChain();
733 const llvm::Triple
&Triple
= TC
.getEffectiveTriple();
734 const std::string
&TripleStr
= Triple
.getTriple();
736 const Driver
&D
= TC
.getDriver();
737 ArgStringList CmdArgs
;
738 DiagnosticsEngine
&Diags
= D
.getDiags();
740 // Invoke ourselves in -fc1 mode.
741 CmdArgs
.push_back("-fc1");
743 // Add the "effective" target triple.
744 CmdArgs
.push_back("-triple");
745 CmdArgs
.push_back(Args
.MakeArgString(TripleStr
));
747 if (isa
<PreprocessJobAction
>(JA
)) {
748 CmdArgs
.push_back("-E");
749 if (Args
.getLastArg(options::OPT_dM
)) {
750 CmdArgs
.push_back("-dM");
752 } else if (isa
<CompileJobAction
>(JA
) || isa
<BackendJobAction
>(JA
)) {
753 if (JA
.getType() == types::TY_Nothing
) {
754 CmdArgs
.push_back("-fsyntax-only");
755 } else if (JA
.getType() == types::TY_AST
) {
756 CmdArgs
.push_back("-emit-ast");
757 } else if (JA
.getType() == types::TY_LLVM_IR
||
758 JA
.getType() == types::TY_LTO_IR
) {
759 CmdArgs
.push_back("-emit-llvm");
760 } else if (JA
.getType() == types::TY_LLVM_BC
||
761 JA
.getType() == types::TY_LTO_BC
) {
762 CmdArgs
.push_back("-emit-llvm-bc");
763 } else if (JA
.getType() == types::TY_PP_Asm
) {
764 CmdArgs
.push_back("-S");
766 assert(false && "Unexpected output type!");
768 } else if (isa
<AssembleJobAction
>(JA
)) {
769 CmdArgs
.push_back("-emit-obj");
770 } else if (isa
<PrecompileJobAction
>(JA
)) {
771 // The precompile job action is only needed for options such as -mcpu=help.
772 // Those will already have been handled by the fc1 driver.
774 assert(false && "Unexpected action class for Flang tool.");
777 const InputInfo
&Input
= Inputs
[0];
778 types::ID InputType
= Input
.getType();
780 // Add preprocessing options like -I, -D, etc. if we are using the
781 // preprocessor (i.e. skip when dealing with e.g. binary files).
782 if (types::getPreprocessedType(InputType
) != types::TY_INVALID
)
783 addPreprocessingOptions(Args
, CmdArgs
);
785 addFortranDialectOptions(Args
, CmdArgs
);
787 // 'flang -E' always produces output that is suitable for use as fixed form
788 // Fortran. However it is only valid free form source if the original is also
790 if (InputType
== types::TY_PP_Fortran
&&
791 !Args
.getLastArg(options::OPT_ffixed_form
, options::OPT_ffree_form
))
792 CmdArgs
.push_back("-ffixed-form");
794 handleColorDiagnosticsArgs(D
, Args
, CmdArgs
);
796 // LTO mode is parsed by the Clang driver library.
797 LTOKind LTOMode
= D
.getLTOMode();
798 assert(LTOMode
!= LTOK_Unknown
&& "Unknown LTO mode.");
799 if (LTOMode
== LTOK_Full
)
800 CmdArgs
.push_back("-flto=full");
801 else if (LTOMode
== LTOK_Thin
) {
803 Diags
.getCustomDiagID(DiagnosticsEngine::Warning
,
804 "the option '-flto=thin' is a work in progress"));
805 CmdArgs
.push_back("-flto=thin");
808 // -fPIC and related options.
809 addPicOptions(Args
, CmdArgs
);
811 // Floating point related options
812 addFloatingPointOptions(D
, Args
, CmdArgs
);
814 // Add target args, features, etc.
815 addTargetOptions(Args
, CmdArgs
);
817 llvm::Reloc::Model RelocationModel
=
818 std::get
<0>(ParsePICArgs(getToolChain(), Args
));
819 // Add MCModel information
820 addMCModel(D
, Args
, Triple
, RelocationModel
, CmdArgs
);
822 // Add Codegen options
823 addCodegenOptions(Args
, CmdArgs
);
825 // Add R Group options
826 Args
.AddAllArgs(CmdArgs
, options::OPT_R_Group
);
828 // Remarks can be enabled with any of the `-f.*optimization-record.*` flags.
829 if (willEmitRemarks(Args
))
830 renderRemarksOptions(Args
, CmdArgs
, Input
);
832 // Add other compile options
833 addOtherOptions(Args
, CmdArgs
);
835 // Disable all warnings
836 // TODO: Handle interactions between -w, -pedantic, -Wall, -WOption
837 Args
.AddLastArg(CmdArgs
, options::OPT_w
);
839 // Forward flags for OpenMP. We don't do this if the current action is an
840 // device offloading action other than OpenMP.
841 if (Args
.hasFlag(options::OPT_fopenmp
, options::OPT_fopenmp_EQ
,
842 options::OPT_fno_openmp
, false) &&
843 (JA
.isDeviceOffloading(Action::OFK_None
) ||
844 JA
.isDeviceOffloading(Action::OFK_OpenMP
))) {
845 switch (D
.getOpenMPRuntime(Args
)) {
846 case Driver::OMPRT_OMP
:
847 case Driver::OMPRT_IOMP5
:
848 // Clang can generate useful OpenMP code for these two runtime libraries.
849 CmdArgs
.push_back("-fopenmp");
850 Args
.AddAllArgs(CmdArgs
, options::OPT_fopenmp_version_EQ
);
852 if (Args
.hasArg(options::OPT_fopenmp_force_usm
))
853 CmdArgs
.push_back("-fopenmp-force-usm");
854 // TODO: OpenMP support isn't "done" yet, so for now we warn that it
856 D
.Diag(diag::warn_openmp_experimental
);
858 // FIXME: Clang supports a whole bunch more flags here.
861 // By default, if Clang doesn't know how to generate useful OpenMP code
862 // for a specific runtime library, we just don't pass the '-fopenmp' flag
863 // down to the actual compilation.
864 // FIXME: It would be better to have a mode which *only* omits IR
865 // generation based on the OpenMP support so that we get consistent
866 // semantic analysis, etc.
867 const Arg
*A
= Args
.getLastArg(options::OPT_fopenmp_EQ
);
868 D
.Diag(diag::warn_drv_unsupported_openmp_library
)
869 << A
->getSpelling() << A
->getValue();
874 // Pass the path to compiler resource files.
875 CmdArgs
.push_back("-resource-dir");
876 CmdArgs
.push_back(D
.ResourceDir
.c_str());
878 // Offloading related options
879 addOffloadOptions(C
, Inputs
, JA
, Args
, CmdArgs
);
881 // Forward -Xflang arguments to -fc1
882 Args
.AddAllArgValues(CmdArgs
, options::OPT_Xflang
);
884 CodeGenOptions::FramePointerKind FPKeepKind
=
885 getFramePointerKind(Args
, Triple
);
887 const char *FPKeepKindStr
= nullptr;
888 switch (FPKeepKind
) {
889 case CodeGenOptions::FramePointerKind::None
:
890 FPKeepKindStr
= "-mframe-pointer=none";
892 case CodeGenOptions::FramePointerKind::Reserved
:
893 FPKeepKindStr
= "-mframe-pointer=reserved";
895 case CodeGenOptions::FramePointerKind::NonLeaf
:
896 FPKeepKindStr
= "-mframe-pointer=non-leaf";
898 case CodeGenOptions::FramePointerKind::All
:
899 FPKeepKindStr
= "-mframe-pointer=all";
902 assert(FPKeepKindStr
&& "unknown FramePointerKind");
903 CmdArgs
.push_back(FPKeepKindStr
);
905 // Forward -mllvm options to the LLVM option parser. In practice, this means
906 // forwarding to `-fc1` as that's where the LLVM parser is run.
907 for (const Arg
*A
: Args
.filtered(options::OPT_mllvm
)) {
909 A
->render(Args
, CmdArgs
);
912 for (const Arg
*A
: Args
.filtered(options::OPT_mmlir
)) {
914 A
->render(Args
, CmdArgs
);
917 // Remove any unsupported gfortran diagnostic options
918 for (const Arg
*A
: Args
.filtered(options::OPT_flang_ignored_w_Group
)) {
920 D
.Diag(diag::warn_drv_unsupported_diag_option_for_flang
)
921 << A
->getOption().getName();
924 // Optimization level for CodeGen.
925 if (const Arg
*A
= Args
.getLastArg(options::OPT_O_Group
)) {
926 if (A
->getOption().matches(options::OPT_O4
)) {
927 CmdArgs
.push_back("-O3");
928 D
.Diag(diag::warn_O4_is_O3
);
929 } else if (A
->getOption().matches(options::OPT_Ofast
)) {
930 CmdArgs
.push_back("-O3");
932 A
->render(Args
, CmdArgs
);
936 renderCommonIntegerOverflowOptions(Args
, CmdArgs
);
938 assert((Output
.isFilename() || Output
.isNothing()) && "Invalid output.");
939 if (Output
.isFilename()) {
940 CmdArgs
.push_back("-o");
941 CmdArgs
.push_back(Output
.getFilename());
944 if (Args
.getLastArg(options::OPT_save_temps_EQ
))
945 Args
.AddLastArg(CmdArgs
, options::OPT_save_temps_EQ
);
947 addDashXForInput(Args
, Input
, CmdArgs
);
949 bool FRecordCmdLine
= false;
950 bool GRecordCmdLine
= false;
951 if (shouldRecordCommandLine(TC
, Args
, FRecordCmdLine
, GRecordCmdLine
)) {
952 const char *CmdLine
= renderEscapedCommandLine(TC
, Args
);
953 if (FRecordCmdLine
) {
954 CmdArgs
.push_back("-record-command-line");
955 CmdArgs
.push_back(CmdLine
);
957 if (TC
.UseDwarfDebugFlags() || GRecordCmdLine
) {
958 CmdArgs
.push_back("-dwarf-debug-flags");
959 CmdArgs
.push_back(CmdLine
);
963 // The input could be Ty_Nothing when "querying" options such as -mcpu=help
965 ArrayRef
<InputInfo
> FrontendInputs
= Input
;
966 if (Input
.isNothing())
969 for (const InputInfo
&Input
: FrontendInputs
) {
970 if (Input
.isFilename())
971 CmdArgs
.push_back(Input
.getFilename());
973 Input
.getInputArg().renderAsInput(Args
, CmdArgs
);
976 const char *Exec
= Args
.MakeArgString(D
.GetProgramPath("flang", TC
));
977 C
.addCommand(std::make_unique
<Command
>(JA
, *this,
978 ResponseFileSupport::AtFileUTF8(),
979 Exec
, CmdArgs
, Inputs
, Output
));
982 Flang::Flang(const ToolChain
&TC
) : Tool("flang", "flang frontend", TC
) {}