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 "CommonArgs.h"
12 #include "clang/Basic/CodeGenOptions.h"
13 #include "clang/Driver/Options.h"
14 #include "llvm/Frontend/Debug/Options.h"
15 #include "llvm/Support/FileSystem.h"
16 #include "llvm/Support/Path.h"
20 using namespace clang::driver
;
21 using namespace clang::driver::tools
;
22 using namespace clang
;
23 using namespace llvm::opt
;
25 /// Add -x lang to \p CmdArgs for \p Input.
26 static void addDashXForInput(const ArgList
&Args
, const InputInfo
&Input
,
27 ArgStringList
&CmdArgs
) {
28 CmdArgs
.push_back("-x");
29 // Map the driver type to the frontend type.
30 CmdArgs
.push_back(types::getTypeName(Input
.getType()));
33 void Flang::addFortranDialectOptions(const ArgList
&Args
,
34 ArgStringList
&CmdArgs
) const {
35 Args
.addAllArgs(CmdArgs
, {options::OPT_ffixed_form
,
36 options::OPT_ffree_form
,
37 options::OPT_ffixed_line_length_EQ
,
39 options::OPT_fopenmp_version_EQ
,
40 options::OPT_fopenacc
,
41 options::OPT_finput_charset_EQ
,
42 options::OPT_fimplicit_none
,
43 options::OPT_fno_implicit_none
,
44 options::OPT_fbackslash
,
45 options::OPT_fno_backslash
,
46 options::OPT_flogical_abbreviations
,
47 options::OPT_fno_logical_abbreviations
,
48 options::OPT_fxor_operator
,
49 options::OPT_fno_xor_operator
,
50 options::OPT_falternative_parameter_statement
,
51 options::OPT_fdefault_real_8
,
52 options::OPT_fdefault_integer_8
,
53 options::OPT_fdefault_double_8
,
54 options::OPT_flarge_sizes
,
55 options::OPT_fno_automatic
});
58 void Flang::addPreprocessingOptions(const ArgList
&Args
,
59 ArgStringList
&CmdArgs
) const {
60 Args
.addAllArgs(CmdArgs
,
61 {options::OPT_P
, options::OPT_D
, options::OPT_U
,
62 options::OPT_I
, options::OPT_cpp
, options::OPT_nocpp
});
65 /// @C shouldLoopVersion
67 /// Check if Loop Versioning should be enabled.
68 /// We look for the last of one of the following:
69 /// -Ofast, -O4, -O<number> and -f[no-]version-loops-for-stride.
70 /// Loop versioning is disabled if the last option is
71 /// -fno-version-loops-for-stride.
72 /// Loop versioning is enabled if the last option is one of:
77 /// For all other cases, loop versioning is is disabled.
79 /// The gfortran compiler automatically enables the option for -O3 or -Ofast.
81 /// @return true if loop-versioning should be enabled, otherwise false.
82 static bool shouldLoopVersion(const ArgList
&Args
) {
83 const Arg
*LoopVersioningArg
= Args
.getLastArg(
84 options::OPT_Ofast
, options::OPT_O
, options::OPT_O4
,
85 options::OPT_floop_versioning
, options::OPT_fno_loop_versioning
);
86 if (!LoopVersioningArg
)
89 if (LoopVersioningArg
->getOption().matches(options::OPT_fno_loop_versioning
))
92 if (LoopVersioningArg
->getOption().matches(options::OPT_floop_versioning
))
95 if (LoopVersioningArg
->getOption().matches(options::OPT_Ofast
) ||
96 LoopVersioningArg
->getOption().matches(options::OPT_O4
))
99 if (LoopVersioningArg
->getOption().matches(options::OPT_O
)) {
100 StringRef
S(LoopVersioningArg
->getValue());
101 unsigned OptLevel
= 0;
102 // Note -Os or Oz woould "fail" here, so return false. Which is the
103 // desiered behavior.
104 if (S
.getAsInteger(10, OptLevel
))
110 llvm_unreachable("We should not end up here");
114 void Flang::addOtherOptions(const ArgList
&Args
, ArgStringList
&CmdArgs
) const {
115 Args
.addAllArgs(CmdArgs
,
116 {options::OPT_module_dir
, options::OPT_fdebug_module_writer
,
117 options::OPT_fintrinsic_modules_path
, options::OPT_pedantic
,
118 options::OPT_std_EQ
, options::OPT_W_Joined
,
119 options::OPT_fconvert_EQ
, options::OPT_fpass_plugin_EQ
,
120 options::OPT_funderscoring
, options::OPT_fno_underscoring
});
122 llvm::codegenoptions::DebugInfoKind DebugInfoKind
;
123 if (Args
.hasArg(options::OPT_gN_Group
)) {
124 Arg
*gNArg
= Args
.getLastArg(options::OPT_gN_Group
);
125 DebugInfoKind
= debugLevelToInfoKind(*gNArg
);
126 } else if (Args
.hasArg(options::OPT_g_Flag
)) {
127 DebugInfoKind
= llvm::codegenoptions::DebugLineTablesOnly
;
129 DebugInfoKind
= llvm::codegenoptions::NoDebugInfo
;
131 addDebugInfoKind(CmdArgs
, DebugInfoKind
);
134 void Flang::addCodegenOptions(const ArgList
&Args
,
135 ArgStringList
&CmdArgs
) const {
137 Args
.getLastArg(options::OPT_Ofast
, options::OPT_fstack_arrays
,
138 options::OPT_fno_stack_arrays
);
140 !stackArrays
->getOption().matches(options::OPT_fno_stack_arrays
))
141 CmdArgs
.push_back("-fstack-arrays");
143 if (shouldLoopVersion(Args
))
144 CmdArgs
.push_back("-fversion-loops-for-stride");
146 Args
.addAllArgs(CmdArgs
, {options::OPT_flang_experimental_hlfir
,
147 options::OPT_flang_deprecated_no_hlfir
,
148 options::OPT_flang_experimental_polymorphism
,
149 options::OPT_fno_ppc_native_vec_elem_order
,
150 options::OPT_fppc_native_vec_elem_order
});
153 void Flang::addPicOptions(const ArgList
&Args
, ArgStringList
&CmdArgs
) const {
154 // ParsePICArgs parses -fPIC/-fPIE and their variants and returns a tuple of
155 // (RelocationModel, PICLevel, IsPIE).
156 llvm::Reloc::Model RelocationModel
;
159 std::tie(RelocationModel
, PICLevel
, IsPIE
) =
160 ParsePICArgs(getToolChain(), Args
);
162 if (auto *RMName
= RelocationModelName(RelocationModel
)) {
163 CmdArgs
.push_back("-mrelocation-model");
164 CmdArgs
.push_back(RMName
);
167 CmdArgs
.push_back("-pic-level");
168 CmdArgs
.push_back(PICLevel
== 1 ? "1" : "2");
170 CmdArgs
.push_back("-pic-is-pie");
174 void Flang::AddAArch64TargetArgs(const ArgList
&Args
,
175 ArgStringList
&CmdArgs
) const {
176 // Handle -msve_vector_bits=<bits>
177 if (Arg
*A
= Args
.getLastArg(options::OPT_msve_vector_bits_EQ
)) {
178 StringRef Val
= A
->getValue();
179 const Driver
&D
= getToolChain().getDriver();
180 if (Val
.equals("128") || Val
.equals("256") || Val
.equals("512") ||
181 Val
.equals("1024") || Val
.equals("2048") || Val
.equals("128+") ||
182 Val
.equals("256+") || Val
.equals("512+") || Val
.equals("1024+") ||
183 Val
.equals("2048+")) {
185 if (Val
.ends_with("+"))
186 Val
= Val
.substr(0, Val
.size() - 1);
188 [[maybe_unused
]] bool Invalid
= Val
.getAsInteger(10, Bits
);
189 assert(!Invalid
&& "Failed to parse value");
191 Args
.MakeArgString("-mvscale-max=" + llvm::Twine(Bits
/ 128)));
194 [[maybe_unused
]] bool Invalid
= Val
.getAsInteger(10, Bits
);
195 assert(!Invalid
&& "Failed to parse value");
197 Args
.MakeArgString("-mvscale-min=" + llvm::Twine(Bits
/ 128)));
198 // Silently drop requests for vector-length agnostic code as it's implied.
199 } else if (!Val
.equals("scalable"))
200 // Handle the unsupported values passed to msve-vector-bits.
201 D
.Diag(diag::err_drv_unsupported_option_argument
)
202 << A
->getSpelling() << Val
;
206 static void addVSDefines(const ToolChain
&TC
, const ArgList
&Args
,
207 ArgStringList
&CmdArgs
) {
210 const VersionTuple vt
= TC
.computeMSVCVersion(nullptr, Args
);
211 ver
= vt
.getMajor() * 10000000 + vt
.getMinor().value_or(0) * 100000 +
212 vt
.getSubminor().value_or(0);
213 CmdArgs
.push_back(Args
.MakeArgString("-D_MSC_VER=" + Twine(ver
/ 100000)));
214 CmdArgs
.push_back(Args
.MakeArgString("-D_MSC_FULL_VER=" + Twine(ver
)));
215 CmdArgs
.push_back(Args
.MakeArgString("-D_WIN32"));
217 llvm::Triple triple
= TC
.getTriple();
218 if (triple
.isAArch64()) {
219 CmdArgs
.push_back("-D_M_ARM64=1");
220 } else if (triple
.isX86() && triple
.isArch32Bit()) {
221 CmdArgs
.push_back("-D_M_IX86=600");
222 } else if (triple
.isX86() && triple
.isArch64Bit()) {
223 CmdArgs
.push_back("-D_M_X64=100");
226 "Flang on Windows only supports X86_32, X86_64 and AArch64");
230 static void processVSRuntimeLibrary(const ToolChain
&TC
, const ArgList
&Args
,
231 ArgStringList
&CmdArgs
) {
232 assert(TC
.getTriple().isKnownWindowsMSVCEnvironment() &&
233 "can only add VS runtime library on Windows!");
234 // if -fno-fortran-main has been passed, skip linking Fortran_main.a
235 bool LinkFortranMain
= !Args
.hasArg(options::OPT_no_fortran_main
);
236 if (TC
.getTriple().isKnownWindowsMSVCEnvironment()) {
237 CmdArgs
.push_back(Args
.MakeArgString(
238 "--dependent-lib=" + TC
.getCompilerRTBasename(Args
, "builtins")));
240 unsigned RTOptionID
= options::OPT__SLASH_MT
;
241 if (auto *rtl
= Args
.getLastArg(options::OPT_fms_runtime_lib_EQ
)) {
242 RTOptionID
= llvm::StringSwitch
<unsigned>(rtl
->getValue())
243 .Case("static", options::OPT__SLASH_MT
)
244 .Case("static_dbg", options::OPT__SLASH_MTd
)
245 .Case("dll", options::OPT__SLASH_MD
)
246 .Case("dll_dbg", options::OPT__SLASH_MDd
)
247 .Default(options::OPT__SLASH_MT
);
249 switch (RTOptionID
) {
250 case options::OPT__SLASH_MT
:
251 CmdArgs
.push_back("-D_MT");
252 CmdArgs
.push_back("--dependent-lib=libcmt");
254 CmdArgs
.push_back("--dependent-lib=Fortran_main.static.lib");
255 CmdArgs
.push_back("--dependent-lib=FortranRuntime.static.lib");
256 CmdArgs
.push_back("--dependent-lib=FortranDecimal.static.lib");
258 case options::OPT__SLASH_MTd
:
259 CmdArgs
.push_back("-D_MT");
260 CmdArgs
.push_back("-D_DEBUG");
261 CmdArgs
.push_back("--dependent-lib=libcmtd");
263 CmdArgs
.push_back("--dependent-lib=Fortran_main.static_dbg.lib");
264 CmdArgs
.push_back("--dependent-lib=FortranRuntime.static_dbg.lib");
265 CmdArgs
.push_back("--dependent-lib=FortranDecimal.static_dbg.lib");
267 case options::OPT__SLASH_MD
:
268 CmdArgs
.push_back("-D_MT");
269 CmdArgs
.push_back("-D_DLL");
270 CmdArgs
.push_back("--dependent-lib=msvcrt");
272 CmdArgs
.push_back("--dependent-lib=Fortran_main.dynamic.lib");
273 CmdArgs
.push_back("--dependent-lib=FortranRuntime.dynamic.lib");
274 CmdArgs
.push_back("--dependent-lib=FortranDecimal.dynamic.lib");
276 case options::OPT__SLASH_MDd
:
277 CmdArgs
.push_back("-D_MT");
278 CmdArgs
.push_back("-D_DEBUG");
279 CmdArgs
.push_back("-D_DLL");
280 CmdArgs
.push_back("--dependent-lib=msvcrtd");
282 CmdArgs
.push_back("--dependent-lib=Fortran_main.dynamic_dbg.lib");
283 CmdArgs
.push_back("--dependent-lib=FortranRuntime.dynamic_dbg.lib");
284 CmdArgs
.push_back("--dependent-lib=FortranDecimal.dynamic_dbg.lib");
289 void Flang::AddAMDGPUTargetArgs(const ArgList
&Args
,
290 ArgStringList
&CmdArgs
) const {
291 if (Arg
*A
= Args
.getLastArg(options::OPT_mcode_object_version_EQ
)) {
292 StringRef Val
= A
->getValue();
293 CmdArgs
.push_back(Args
.MakeArgString("-mcode-object-version=" + Val
));
297 void Flang::addTargetOptions(const ArgList
&Args
,
298 ArgStringList
&CmdArgs
) const {
299 const ToolChain
&TC
= getToolChain();
300 const llvm::Triple
&Triple
= TC
.getEffectiveTriple();
301 const Driver
&D
= TC
.getDriver();
303 std::string CPU
= getCPUName(D
, Args
, Triple
);
305 CmdArgs
.push_back("-target-cpu");
306 CmdArgs
.push_back(Args
.MakeArgString(CPU
));
309 // Add the target features.
310 switch (TC
.getArch()) {
313 case llvm::Triple::aarch64
:
314 getTargetFeatures(D
, Triple
, Args
, CmdArgs
, /*ForAs*/ false);
315 AddAArch64TargetArgs(Args
, CmdArgs
);
318 case llvm::Triple::r600
:
319 case llvm::Triple::amdgcn
:
320 getTargetFeatures(D
, Triple
, Args
, CmdArgs
, /*ForAs*/ false);
321 AddAMDGPUTargetArgs(Args
, CmdArgs
);
323 case llvm::Triple::riscv64
:
324 case llvm::Triple::x86_64
:
325 getTargetFeatures(D
, Triple
, Args
, CmdArgs
, /*ForAs*/ false);
329 if (Arg
*A
= Args
.getLastArg(options::OPT_fveclib
)) {
330 StringRef Name
= A
->getValue();
331 if (Name
== "SVML") {
332 if (Triple
.getArch() != llvm::Triple::x86
&&
333 Triple
.getArch() != llvm::Triple::x86_64
)
334 D
.Diag(diag::err_drv_unsupported_opt_for_target
)
335 << Name
<< Triple
.getArchName();
336 } else if (Name
== "LIBMVEC-X86") {
337 if (Triple
.getArch() != llvm::Triple::x86
&&
338 Triple
.getArch() != llvm::Triple::x86_64
)
339 D
.Diag(diag::err_drv_unsupported_opt_for_target
)
340 << Name
<< Triple
.getArchName();
341 } else if (Name
== "SLEEF" || Name
== "ArmPL") {
342 if (Triple
.getArch() != llvm::Triple::aarch64
&&
343 Triple
.getArch() != llvm::Triple::aarch64_be
)
344 D
.Diag(diag::err_drv_unsupported_opt_for_target
)
345 << Name
<< Triple
.getArchName();
348 if (Triple
.isOSDarwin()) {
349 // flang doesn't currently suport nostdlib, nodefaultlibs. Adding these
350 // here incase they are added someday
351 if (!Args
.hasArg(options::OPT_nostdlib
, options::OPT_nodefaultlibs
)) {
352 if (A
->getValue() == StringRef
{"Accelerate"}) {
353 CmdArgs
.push_back("-framework");
354 CmdArgs
.push_back("Accelerate");
355 A
->render(Args
, CmdArgs
);
359 A
->render(Args
, CmdArgs
);
363 if (Triple
.isKnownWindowsMSVCEnvironment()) {
364 processVSRuntimeLibrary(TC
, Args
, CmdArgs
);
365 addVSDefines(TC
, Args
, CmdArgs
);
368 // TODO: Add target specific flags, ABI, mtune option etc.
371 void Flang::addOffloadOptions(Compilation
&C
, const InputInfoList
&Inputs
,
372 const JobAction
&JA
, const ArgList
&Args
,
373 ArgStringList
&CmdArgs
) const {
374 bool IsOpenMPDevice
= JA
.isDeviceOffloading(Action::OFK_OpenMP
);
375 bool IsHostOffloadingAction
= JA
.isHostOffloading(Action::OFK_OpenMP
) ||
376 JA
.isHostOffloading(C
.getActiveOffloadKinds());
378 // Skips the primary input file, which is the input file that the compilation
379 // proccess will be executed upon (e.g. the host bitcode file) and
380 // adds other secondary input (e.g. device bitcode files for embedding to the
381 // -fembed-offload-object argument or the host IR file for proccessing
382 // during device compilation to the fopenmp-host-ir-file-path argument via
383 // OpenMPDeviceInput). This is condensed logic from the ConstructJob
384 // function inside of the Clang driver for pushing on further input arguments
385 // needed for offloading during various phases of compilation.
386 for (size_t i
= 1; i
< Inputs
.size(); ++i
) {
387 if (Inputs
[i
].getType() == types::TY_Nothing
) {
388 // contains nothing, so it's skippable
389 } else if (IsHostOffloadingAction
) {
391 Args
.MakeArgString("-fembed-offload-object=" +
392 getToolChain().getInputFilename(Inputs
[i
])));
393 } else if (IsOpenMPDevice
) {
394 if (Inputs
[i
].getFilename()) {
395 CmdArgs
.push_back("-fopenmp-host-ir-file-path");
396 CmdArgs
.push_back(Args
.MakeArgString(Inputs
[i
].getFilename()));
398 llvm_unreachable("missing openmp host-ir file for device offloading");
402 "unexpectedly given multiple inputs or given unknown input");
406 if (IsOpenMPDevice
) {
407 // -fopenmp-is-target-device is passed along to tell the frontend that it is
408 // generating code for a device, so that only the relevant code is emitted.
409 CmdArgs
.push_back("-fopenmp-is-target-device");
411 // When in OpenMP offloading mode, enable debugging on the device.
412 Args
.AddAllArgs(CmdArgs
, options::OPT_fopenmp_target_debug_EQ
);
413 if (Args
.hasFlag(options::OPT_fopenmp_target_debug
,
414 options::OPT_fno_openmp_target_debug
, /*Default=*/false))
415 CmdArgs
.push_back("-fopenmp-target-debug");
417 // When in OpenMP offloading mode, forward assumptions information about
418 // thread and team counts in the device.
419 if (Args
.hasFlag(options::OPT_fopenmp_assume_teams_oversubscription
,
420 options::OPT_fno_openmp_assume_teams_oversubscription
,
422 CmdArgs
.push_back("-fopenmp-assume-teams-oversubscription");
423 if (Args
.hasFlag(options::OPT_fopenmp_assume_threads_oversubscription
,
424 options::OPT_fno_openmp_assume_threads_oversubscription
,
426 CmdArgs
.push_back("-fopenmp-assume-threads-oversubscription");
427 if (Args
.hasArg(options::OPT_fopenmp_assume_no_thread_state
))
428 CmdArgs
.push_back("-fopenmp-assume-no-thread-state");
429 if (Args
.hasArg(options::OPT_fopenmp_assume_no_nested_parallelism
))
430 CmdArgs
.push_back("-fopenmp-assume-no-nested-parallelism");
434 static void addFloatingPointOptions(const Driver
&D
, const ArgList
&Args
,
435 ArgStringList
&CmdArgs
) {
436 StringRef FPContract
;
437 bool HonorINFs
= true;
438 bool HonorNaNs
= true;
439 bool ApproxFunc
= false;
440 bool SignedZeros
= true;
441 bool AssociativeMath
= false;
442 bool ReciprocalMath
= false;
444 if (const Arg
*A
= Args
.getLastArg(options::OPT_ffp_contract
)) {
445 const StringRef Val
= A
->getValue();
446 if (Val
== "fast" || Val
== "off") {
448 } else if (Val
== "on") {
449 // Warn instead of error because users might have makefiles written for
450 // gfortran (which accepts -ffp-contract=on)
451 D
.Diag(diag::warn_drv_unsupported_option_for_flang
)
452 << Val
<< A
->getOption().getName() << "off";
455 // Clang's "fast-honor-pragmas" option is not supported because it is
457 D
.Diag(diag::err_drv_unsupported_option_argument
)
458 << A
->getSpelling() << Val
;
461 for (const Arg
*A
: Args
) {
462 auto optId
= A
->getOption().getID();
464 // if this isn't an FP option, skip the claim below
468 case options::OPT_fhonor_infinities
:
471 case options::OPT_fno_honor_infinities
:
474 case options::OPT_fhonor_nans
:
477 case options::OPT_fno_honor_nans
:
480 case options::OPT_fapprox_func
:
483 case options::OPT_fno_approx_func
:
486 case options::OPT_fsigned_zeros
:
489 case options::OPT_fno_signed_zeros
:
492 case options::OPT_fassociative_math
:
493 AssociativeMath
= true;
495 case options::OPT_fno_associative_math
:
496 AssociativeMath
= false;
498 case options::OPT_freciprocal_math
:
499 ReciprocalMath
= true;
501 case options::OPT_fno_reciprocal_math
:
502 ReciprocalMath
= false;
504 case options::OPT_Ofast
:
506 case options::OPT_ffast_math
:
509 AssociativeMath
= true;
510 ReciprocalMath
= true;
515 case options::OPT_fno_fast_math
:
518 AssociativeMath
= false;
519 ReciprocalMath
= false;
522 // -fno-fast-math should undo -ffast-math so I return FPContract to the
523 // default. It is important to check it is "fast" (the default) so that
524 // --ffp-contract=off -fno-fast-math --> -ffp-contract=off
525 if (FPContract
== "fast")
530 // If we handled this option claim it
534 if (!HonorINFs
&& !HonorNaNs
&& AssociativeMath
&& ReciprocalMath
&&
535 ApproxFunc
&& !SignedZeros
&&
536 (FPContract
== "fast" || FPContract
== "")) {
537 CmdArgs
.push_back("-ffast-math");
541 if (!FPContract
.empty())
542 CmdArgs
.push_back(Args
.MakeArgString("-ffp-contract=" + FPContract
));
545 CmdArgs
.push_back("-menable-no-infs");
548 CmdArgs
.push_back("-menable-no-nans");
551 CmdArgs
.push_back("-fapprox-func");
554 CmdArgs
.push_back("-fno-signed-zeros");
556 if (AssociativeMath
&& !SignedZeros
)
557 CmdArgs
.push_back("-mreassociate");
560 CmdArgs
.push_back("-freciprocal-math");
563 static void renderRemarksOptions(const ArgList
&Args
, ArgStringList
&CmdArgs
,
564 const InputInfo
&Input
) {
565 StringRef Format
= "yaml";
566 if (const Arg
*A
= Args
.getLastArg(options::OPT_fsave_optimization_record_EQ
))
567 Format
= A
->getValue();
569 CmdArgs
.push_back("-opt-record-file");
571 const Arg
*A
= Args
.getLastArg(options::OPT_foptimization_record_file_EQ
);
573 CmdArgs
.push_back(A
->getValue());
577 if (Args
.hasArg(options::OPT_c
) || Args
.hasArg(options::OPT_S
)) {
578 if (Arg
*FinalOutput
= Args
.getLastArg(options::OPT_o
))
579 F
= FinalOutput
->getValue();
583 // Use the input filename.
584 F
= llvm::sys::path::stem(Input
.getBaseInput());
587 SmallString
<32> Extension
;
591 llvm::sys::path::replace_extension(F
, Extension
);
592 CmdArgs
.push_back(Args
.MakeArgString(F
));
596 Args
.getLastArg(options::OPT_foptimization_record_passes_EQ
)) {
597 CmdArgs
.push_back("-opt-record-passes");
598 CmdArgs
.push_back(A
->getValue());
601 if (!Format
.empty()) {
602 CmdArgs
.push_back("-opt-record-format");
603 CmdArgs
.push_back(Format
.data());
607 void Flang::ConstructJob(Compilation
&C
, const JobAction
&JA
,
608 const InputInfo
&Output
, const InputInfoList
&Inputs
,
609 const ArgList
&Args
, const char *LinkingOutput
) const {
610 const auto &TC
= getToolChain();
611 const llvm::Triple
&Triple
= TC
.getEffectiveTriple();
612 const std::string
&TripleStr
= Triple
.getTriple();
614 const Driver
&D
= TC
.getDriver();
615 ArgStringList CmdArgs
;
616 DiagnosticsEngine
&Diags
= D
.getDiags();
618 // Invoke ourselves in -fc1 mode.
619 CmdArgs
.push_back("-fc1");
621 // Add the "effective" target triple.
622 CmdArgs
.push_back("-triple");
623 CmdArgs
.push_back(Args
.MakeArgString(TripleStr
));
625 if (isa
<PreprocessJobAction
>(JA
)) {
626 CmdArgs
.push_back("-E");
627 } else if (isa
<CompileJobAction
>(JA
) || isa
<BackendJobAction
>(JA
)) {
628 if (JA
.getType() == types::TY_Nothing
) {
629 CmdArgs
.push_back("-fsyntax-only");
630 } else if (JA
.getType() == types::TY_AST
) {
631 CmdArgs
.push_back("-emit-ast");
632 } else if (JA
.getType() == types::TY_LLVM_IR
||
633 JA
.getType() == types::TY_LTO_IR
) {
634 CmdArgs
.push_back("-emit-llvm");
635 } else if (JA
.getType() == types::TY_LLVM_BC
||
636 JA
.getType() == types::TY_LTO_BC
) {
637 CmdArgs
.push_back("-emit-llvm-bc");
638 } else if (JA
.getType() == types::TY_PP_Asm
) {
639 CmdArgs
.push_back("-S");
641 assert(false && "Unexpected output type!");
643 } else if (isa
<AssembleJobAction
>(JA
)) {
644 CmdArgs
.push_back("-emit-obj");
646 assert(false && "Unexpected action class for Flang tool.");
649 const InputInfo
&Input
= Inputs
[0];
650 types::ID InputType
= Input
.getType();
652 // Add preprocessing options like -I, -D, etc. if we are using the
653 // preprocessor (i.e. skip when dealing with e.g. binary files).
654 if (types::getPreprocessedType(InputType
) != types::TY_INVALID
)
655 addPreprocessingOptions(Args
, CmdArgs
);
657 addFortranDialectOptions(Args
, CmdArgs
);
659 // Color diagnostics are parsed by the driver directly from argv and later
660 // re-parsed to construct this job; claim any possible color diagnostic here
661 // to avoid warn_drv_unused_argument.
662 Args
.getLastArg(options::OPT_fcolor_diagnostics
,
663 options::OPT_fno_color_diagnostics
);
664 if (Diags
.getDiagnosticOptions().ShowColors
)
665 CmdArgs
.push_back("-fcolor-diagnostics");
667 // LTO mode is parsed by the Clang driver library.
668 LTOKind LTOMode
= D
.getLTOMode(/* IsOffload */ false);
669 assert(LTOMode
!= LTOK_Unknown
&& "Unknown LTO mode.");
670 if (LTOMode
== LTOK_Full
)
671 CmdArgs
.push_back("-flto=full");
672 else if (LTOMode
== LTOK_Thin
) {
674 Diags
.getCustomDiagID(DiagnosticsEngine::Warning
,
675 "the option '-flto=thin' is a work in progress"));
676 CmdArgs
.push_back("-flto=thin");
679 // -fPIC and related options.
680 addPicOptions(Args
, CmdArgs
);
682 // Floating point related options
683 addFloatingPointOptions(D
, Args
, CmdArgs
);
685 // Add target args, features, etc.
686 addTargetOptions(Args
, CmdArgs
);
688 // Add Codegen options
689 addCodegenOptions(Args
, CmdArgs
);
691 // Add R Group options
692 Args
.AddAllArgs(CmdArgs
, options::OPT_R_Group
);
694 // Remarks can be enabled with any of the `-f.*optimization-record.*` flags.
695 if (willEmitRemarks(Args
))
696 renderRemarksOptions(Args
, CmdArgs
, Input
);
698 // Add other compile options
699 addOtherOptions(Args
, CmdArgs
);
701 // Offloading related options
702 addOffloadOptions(C
, Inputs
, JA
, Args
, CmdArgs
);
704 // Forward -Xflang arguments to -fc1
705 Args
.AddAllArgValues(CmdArgs
, options::OPT_Xflang
);
707 CodeGenOptions::FramePointerKind FPKeepKind
=
708 getFramePointerKind(Args
, Triple
);
710 const char *FPKeepKindStr
= nullptr;
711 switch (FPKeepKind
) {
712 case CodeGenOptions::FramePointerKind::None
:
713 FPKeepKindStr
= "-mframe-pointer=none";
715 case CodeGenOptions::FramePointerKind::NonLeaf
:
716 FPKeepKindStr
= "-mframe-pointer=non-leaf";
718 case CodeGenOptions::FramePointerKind::All
:
719 FPKeepKindStr
= "-mframe-pointer=all";
722 assert(FPKeepKindStr
&& "unknown FramePointerKind");
723 CmdArgs
.push_back(FPKeepKindStr
);
725 // Forward -mllvm options to the LLVM option parser. In practice, this means
726 // forwarding to `-fc1` as that's where the LLVM parser is run.
727 for (const Arg
*A
: Args
.filtered(options::OPT_mllvm
)) {
729 A
->render(Args
, CmdArgs
);
732 for (const Arg
*A
: Args
.filtered(options::OPT_mmlir
)) {
734 A
->render(Args
, CmdArgs
);
737 // Remove any unsupported gfortran diagnostic options
738 for (const Arg
*A
: Args
.filtered(options::OPT_flang_ignored_w_Group
)) {
740 D
.Diag(diag::warn_drv_unsupported_diag_option_for_flang
)
741 << A
->getOption().getName();
744 // Optimization level for CodeGen.
745 if (const Arg
*A
= Args
.getLastArg(options::OPT_O_Group
)) {
746 if (A
->getOption().matches(options::OPT_O4
)) {
747 CmdArgs
.push_back("-O3");
748 D
.Diag(diag::warn_O4_is_O3
);
749 } else if (A
->getOption().matches(options::OPT_Ofast
)) {
750 CmdArgs
.push_back("-O3");
752 A
->render(Args
, CmdArgs
);
756 assert((Output
.isFilename() || Output
.isNothing()) && "Invalid output.");
757 if (Output
.isFilename()) {
758 CmdArgs
.push_back("-o");
759 CmdArgs
.push_back(Output
.getFilename());
762 assert(Input
.isFilename() && "Invalid input.");
764 if (Args
.getLastArg(options::OPT_save_temps_EQ
))
765 Args
.AddLastArg(CmdArgs
, options::OPT_save_temps_EQ
);
767 addDashXForInput(Args
, Input
, CmdArgs
);
769 CmdArgs
.push_back(Input
.getFilename());
771 // TODO: Replace flang-new with flang once the new driver replaces the
773 const char *Exec
= Args
.MakeArgString(D
.GetProgramPath("flang-new", TC
));
774 C
.addCommand(std::make_unique
<Command
>(JA
, *this,
775 ResponseFileSupport::AtFileUTF8(),
776 Exec
, CmdArgs
, Inputs
, Output
));
779 Flang::Flang(const ToolChain
&TC
) : Tool("flang-new", "flang frontend", TC
) {}