/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/lib/Driver/ToolChains/Flang.cpp
Line | Count | Source (jump to first uncovered line) |
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 | | |
10 | | #include "Flang.h" |
11 | | #include "CommonArgs.h" |
12 | | |
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" |
17 | | |
18 | | #include <cassert> |
19 | | |
20 | | using namespace clang::driver; |
21 | | using namespace clang::driver::tools; |
22 | | using namespace clang; |
23 | | using namespace llvm::opt; |
24 | | |
25 | | /// Add -x lang to \p CmdArgs for \p Input. |
26 | | static void addDashXForInput(const ArgList &Args, const InputInfo &Input, |
27 | 15 | ArgStringList &CmdArgs) { |
28 | 15 | CmdArgs.push_back("-x"); |
29 | | // Map the driver type to the frontend type. |
30 | 15 | CmdArgs.push_back(types::getTypeName(Input.getType())); |
31 | 15 | } |
32 | | |
33 | | void Flang::addFortranDialectOptions(const ArgList &Args, |
34 | 15 | ArgStringList &CmdArgs) const { |
35 | 15 | Args.AddAllArgs(CmdArgs, {options::OPT_ffixed_form, |
36 | 15 | options::OPT_ffree_form, |
37 | 15 | options::OPT_ffixed_line_length_EQ, |
38 | 15 | options::OPT_fopenmp, |
39 | 15 | options::OPT_fopenmp_version_EQ, |
40 | 15 | options::OPT_fopenacc, |
41 | 15 | options::OPT_finput_charset_EQ, |
42 | 15 | options::OPT_fimplicit_none, |
43 | 15 | options::OPT_fno_implicit_none, |
44 | 15 | options::OPT_fbackslash, |
45 | 15 | options::OPT_fno_backslash, |
46 | 15 | options::OPT_flogical_abbreviations, |
47 | 15 | options::OPT_fno_logical_abbreviations, |
48 | 15 | options::OPT_fxor_operator, |
49 | 15 | options::OPT_fno_xor_operator, |
50 | 15 | options::OPT_falternative_parameter_statement, |
51 | 15 | options::OPT_fdefault_real_8, |
52 | 15 | options::OPT_fdefault_integer_8, |
53 | 15 | options::OPT_fdefault_double_8, |
54 | 15 | options::OPT_flarge_sizes, |
55 | 15 | options::OPT_fno_automatic}); |
56 | 15 | } |
57 | | |
58 | | void Flang::addPreprocessingOptions(const ArgList &Args, |
59 | 15 | ArgStringList &CmdArgs) const { |
60 | 15 | Args.AddAllArgs(CmdArgs, |
61 | 15 | {options::OPT_P, options::OPT_D, options::OPT_U, |
62 | 15 | options::OPT_I, options::OPT_cpp, options::OPT_nocpp}); |
63 | 15 | } |
64 | | |
65 | | /// @C shouldLoopVersion |
66 | | /// |
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: |
73 | | /// -floop-versioning |
74 | | /// -Ofast |
75 | | /// -O4 |
76 | | /// -O3 |
77 | | /// For all other cases, loop versioning is is disabled. |
78 | | /// |
79 | | /// The gfortran compiler automatically enables the option for -O3 or -Ofast. |
80 | | /// |
81 | | /// @return true if loop-versioning should be enabled, otherwise false. |
82 | 15 | static bool shouldLoopVersion(const ArgList &Args) { |
83 | 15 | const Arg *LoopVersioningArg = Args.getLastArg( |
84 | 15 | options::OPT_Ofast, options::OPT_O, options::OPT_O4, |
85 | 15 | options::OPT_floop_versioning, options::OPT_fno_loop_versioning); |
86 | 15 | if (!LoopVersioningArg) |
87 | 15 | return false; |
88 | | |
89 | 0 | if (LoopVersioningArg->getOption().matches(options::OPT_fno_loop_versioning)) |
90 | 0 | return false; |
91 | | |
92 | 0 | if (LoopVersioningArg->getOption().matches(options::OPT_floop_versioning)) |
93 | 0 | return true; |
94 | | |
95 | 0 | if (LoopVersioningArg->getOption().matches(options::OPT_Ofast) || |
96 | 0 | LoopVersioningArg->getOption().matches(options::OPT_O4)) |
97 | 0 | return true; |
98 | | |
99 | 0 | if (LoopVersioningArg->getOption().matches(options::OPT_O)) { |
100 | 0 | StringRef S(LoopVersioningArg->getValue()); |
101 | 0 | unsigned OptLevel = 0; |
102 | | // Note -Os or Oz woould "fail" here, so return false. Which is the |
103 | | // desiered behavior. |
104 | 0 | if (S.getAsInteger(10, OptLevel)) |
105 | 0 | return false; |
106 | | |
107 | 0 | return OptLevel > 2; |
108 | 0 | } |
109 | | |
110 | 0 | llvm_unreachable("We should not end up here"); |
111 | 0 | return false; |
112 | 0 | } |
113 | | |
114 | 15 | void Flang::addOtherOptions(const ArgList &Args, ArgStringList &CmdArgs) const { |
115 | 15 | Args.AddAllArgs(CmdArgs, |
116 | 15 | {options::OPT_module_dir, options::OPT_fdebug_module_writer, |
117 | 15 | options::OPT_fintrinsic_modules_path, options::OPT_pedantic, |
118 | 15 | options::OPT_std_EQ, options::OPT_W_Joined, |
119 | 15 | options::OPT_fconvert_EQ, options::OPT_fpass_plugin_EQ, |
120 | 15 | options::OPT_funderscoring, options::OPT_fno_underscoring}); |
121 | | |
122 | 15 | llvm::codegenoptions::DebugInfoKind DebugInfoKind; |
123 | 15 | if (Args.hasArg(options::OPT_gN_Group)) { |
124 | 0 | Arg *gNArg = Args.getLastArg(options::OPT_gN_Group); |
125 | 0 | DebugInfoKind = debugLevelToInfoKind(*gNArg); |
126 | 15 | } else if (Args.hasArg(options::OPT_g_Flag)) { |
127 | 0 | DebugInfoKind = llvm::codegenoptions::DebugLineTablesOnly; |
128 | 15 | } else { |
129 | 15 | DebugInfoKind = llvm::codegenoptions::NoDebugInfo; |
130 | 15 | } |
131 | 15 | addDebugInfoKind(CmdArgs, DebugInfoKind); |
132 | 15 | } |
133 | | |
134 | | void Flang::addCodegenOptions(const ArgList &Args, |
135 | 15 | ArgStringList &CmdArgs) const { |
136 | 15 | Arg *stackArrays = |
137 | 15 | Args.getLastArg(options::OPT_Ofast, options::OPT_fstack_arrays, |
138 | 15 | options::OPT_fno_stack_arrays); |
139 | 15 | if (stackArrays && |
140 | 15 | !stackArrays->getOption().matches(options::OPT_fno_stack_arrays)0 ) |
141 | 0 | CmdArgs.push_back("-fstack-arrays"); |
142 | | |
143 | 15 | if (shouldLoopVersion(Args)) |
144 | 0 | CmdArgs.push_back("-fversion-loops-for-stride"); |
145 | | |
146 | 15 | Args.AddAllArgs(CmdArgs, {options::OPT_flang_experimental_hlfir, |
147 | 15 | options::OPT_flang_experimental_polymorphism, |
148 | 15 | options::OPT_fno_ppc_native_vec_elem_order, |
149 | 15 | options::OPT_fppc_native_vec_elem_order}); |
150 | 15 | } |
151 | | |
152 | 15 | void Flang::addPicOptions(const ArgList &Args, ArgStringList &CmdArgs) const { |
153 | | // ParsePICArgs parses -fPIC/-fPIE and their variants and returns a tuple of |
154 | | // (RelocationModel, PICLevel, IsPIE). |
155 | 15 | llvm::Reloc::Model RelocationModel; |
156 | 15 | unsigned PICLevel; |
157 | 15 | bool IsPIE; |
158 | 15 | std::tie(RelocationModel, PICLevel, IsPIE) = |
159 | 15 | ParsePICArgs(getToolChain(), Args); |
160 | | |
161 | 15 | if (auto *RMName = RelocationModelName(RelocationModel)) { |
162 | 15 | CmdArgs.push_back("-mrelocation-model"); |
163 | 15 | CmdArgs.push_back(RMName); |
164 | 15 | } |
165 | 15 | if (PICLevel > 0) { |
166 | 15 | CmdArgs.push_back("-pic-level"); |
167 | 15 | CmdArgs.push_back(PICLevel == 1 ? "1"0 : "2"); |
168 | 15 | if (IsPIE) |
169 | 0 | CmdArgs.push_back("-pic-is-pie"); |
170 | 15 | } |
171 | 15 | } |
172 | | |
173 | | void Flang::addTargetOptions(const ArgList &Args, |
174 | 15 | ArgStringList &CmdArgs) const { |
175 | 15 | const ToolChain &TC = getToolChain(); |
176 | 15 | const llvm::Triple &Triple = TC.getEffectiveTriple(); |
177 | 15 | const Driver &D = TC.getDriver(); |
178 | | |
179 | 15 | std::string CPU = getCPUName(D, Args, Triple); |
180 | 15 | if (!CPU.empty()) { |
181 | 15 | CmdArgs.push_back("-target-cpu"); |
182 | 15 | CmdArgs.push_back(Args.MakeArgString(CPU)); |
183 | 15 | } |
184 | | |
185 | | // Add the target features. |
186 | 15 | switch (TC.getArch()) { |
187 | 0 | default: |
188 | 0 | break; |
189 | 0 | case llvm::Triple::r600: |
190 | 0 | case llvm::Triple::amdgcn: |
191 | 0 | case llvm::Triple::aarch64: |
192 | 0 | case llvm::Triple::riscv64: |
193 | 15 | case llvm::Triple::x86_64: |
194 | 15 | getTargetFeatures(D, Triple, Args, CmdArgs, /*ForAs*/ false); |
195 | 15 | break; |
196 | 15 | } |
197 | | |
198 | | // TODO: Add target specific flags, ABI, mtune option etc. |
199 | 15 | } |
200 | | |
201 | | void Flang::addOffloadOptions(Compilation &C, const InputInfoList &Inputs, |
202 | | const JobAction &JA, const ArgList &Args, |
203 | 15 | ArgStringList &CmdArgs) const { |
204 | 15 | bool IsOpenMPDevice = JA.isDeviceOffloading(Action::OFK_OpenMP); |
205 | 15 | bool IsHostOffloadingAction = JA.isHostOffloading(Action::OFK_OpenMP) || |
206 | 15 | JA.isHostOffloading(C.getActiveOffloadKinds()); |
207 | | |
208 | | // Skips the primary input file, which is the input file that the compilation |
209 | | // proccess will be executed upon (e.g. the host bitcode file) and |
210 | | // adds other secondary input (e.g. device bitcode files for embedding to the |
211 | | // -fembed-offload-object argument or the host IR file for proccessing |
212 | | // during device compilation to the fopenmp-host-ir-file-path argument via |
213 | | // OpenMPDeviceInput). This is condensed logic from the ConstructJob |
214 | | // function inside of the Clang driver for pushing on further input arguments |
215 | | // needed for offloading during various phases of compilation. |
216 | 15 | for (size_t i = 1; i < Inputs.size(); ++i0 ) { |
217 | 0 | if (Inputs[i].getType() == types::TY_Nothing) { |
218 | | // contains nothing, so it's skippable |
219 | 0 | } else if (IsHostOffloadingAction) { |
220 | 0 | CmdArgs.push_back( |
221 | 0 | Args.MakeArgString("-fembed-offload-object=" + |
222 | 0 | getToolChain().getInputFilename(Inputs[i]))); |
223 | 0 | } else if (IsOpenMPDevice) { |
224 | 0 | if (Inputs[i].getFilename()) { |
225 | 0 | CmdArgs.push_back("-fopenmp-host-ir-file-path"); |
226 | 0 | CmdArgs.push_back(Args.MakeArgString(Inputs[i].getFilename())); |
227 | 0 | } else { |
228 | 0 | llvm_unreachable("missing openmp host-ir file for device offloading"); |
229 | 0 | } |
230 | 0 | } else { |
231 | 0 | llvm_unreachable( |
232 | 0 | "unexpectedly given multiple inputs or given unknown input"); |
233 | 0 | } |
234 | 0 | } |
235 | | |
236 | 15 | if (IsOpenMPDevice) { |
237 | | // -fopenmp-is-target-device is passed along to tell the frontend that it is |
238 | | // generating code for a device, so that only the relevant code is emitted. |
239 | 0 | CmdArgs.push_back("-fopenmp-is-target-device"); |
240 | | |
241 | | // When in OpenMP offloading mode, enable debugging on the device. |
242 | 0 | Args.AddAllArgs(CmdArgs, options::OPT_fopenmp_target_debug_EQ); |
243 | 0 | if (Args.hasFlag(options::OPT_fopenmp_target_debug, |
244 | 0 | options::OPT_fno_openmp_target_debug, /*Default=*/false)) |
245 | 0 | CmdArgs.push_back("-fopenmp-target-debug"); |
246 | | |
247 | | // When in OpenMP offloading mode, forward assumptions information about |
248 | | // thread and team counts in the device. |
249 | 0 | if (Args.hasFlag(options::OPT_fopenmp_assume_teams_oversubscription, |
250 | 0 | options::OPT_fno_openmp_assume_teams_oversubscription, |
251 | 0 | /*Default=*/false)) |
252 | 0 | CmdArgs.push_back("-fopenmp-assume-teams-oversubscription"); |
253 | 0 | if (Args.hasFlag(options::OPT_fopenmp_assume_threads_oversubscription, |
254 | 0 | options::OPT_fno_openmp_assume_threads_oversubscription, |
255 | 0 | /*Default=*/false)) |
256 | 0 | CmdArgs.push_back("-fopenmp-assume-threads-oversubscription"); |
257 | 0 | if (Args.hasArg(options::OPT_fopenmp_assume_no_thread_state)) |
258 | 0 | CmdArgs.push_back("-fopenmp-assume-no-thread-state"); |
259 | 0 | if (Args.hasArg(options::OPT_fopenmp_assume_no_nested_parallelism)) |
260 | 0 | CmdArgs.push_back("-fopenmp-assume-no-nested-parallelism"); |
261 | 0 | } |
262 | 15 | } |
263 | | |
264 | | static void addFloatingPointOptions(const Driver &D, const ArgList &Args, |
265 | 15 | ArgStringList &CmdArgs) { |
266 | 15 | StringRef FPContract; |
267 | 15 | bool HonorINFs = true; |
268 | 15 | bool HonorNaNs = true; |
269 | 15 | bool ApproxFunc = false; |
270 | 15 | bool SignedZeros = true; |
271 | 15 | bool AssociativeMath = false; |
272 | 15 | bool ReciprocalMath = false; |
273 | | |
274 | 15 | if (const Arg *A = Args.getLastArg(options::OPT_ffp_contract)) { |
275 | 0 | const StringRef Val = A->getValue(); |
276 | 0 | if (Val == "fast" || Val == "off") { |
277 | 0 | FPContract = Val; |
278 | 0 | } else if (Val == "on") { |
279 | | // Warn instead of error because users might have makefiles written for |
280 | | // gfortran (which accepts -ffp-contract=on) |
281 | 0 | D.Diag(diag::warn_drv_unsupported_option_for_flang) |
282 | 0 | << Val << A->getOption().getName() << "off"; |
283 | 0 | FPContract = "off"; |
284 | 0 | } else |
285 | | // Clang's "fast-honor-pragmas" option is not supported because it is |
286 | | // non-standard |
287 | 0 | D.Diag(diag::err_drv_unsupported_option_argument) |
288 | 0 | << A->getSpelling() << Val; |
289 | 0 | } |
290 | | |
291 | 112 | for (const Arg *A : Args) { |
292 | 112 | auto optId = A->getOption().getID(); |
293 | 112 | switch (optId) { |
294 | | // if this isn't an FP option, skip the claim below |
295 | 112 | default: |
296 | 112 | continue; |
297 | | |
298 | 112 | case options::OPT_fhonor_infinities: |
299 | 0 | HonorINFs = true; |
300 | 0 | break; |
301 | 0 | case options::OPT_fno_honor_infinities: |
302 | 0 | HonorINFs = false; |
303 | 0 | break; |
304 | 0 | case options::OPT_fhonor_nans: |
305 | 0 | HonorNaNs = true; |
306 | 0 | break; |
307 | 0 | case options::OPT_fno_honor_nans: |
308 | 0 | HonorNaNs = false; |
309 | 0 | break; |
310 | 0 | case options::OPT_fapprox_func: |
311 | 0 | ApproxFunc = true; |
312 | 0 | break; |
313 | 0 | case options::OPT_fno_approx_func: |
314 | 0 | ApproxFunc = false; |
315 | 0 | break; |
316 | 0 | case options::OPT_fsigned_zeros: |
317 | 0 | SignedZeros = true; |
318 | 0 | break; |
319 | 0 | case options::OPT_fno_signed_zeros: |
320 | 0 | SignedZeros = false; |
321 | 0 | break; |
322 | 0 | case options::OPT_fassociative_math: |
323 | 0 | AssociativeMath = true; |
324 | 0 | break; |
325 | 0 | case options::OPT_fno_associative_math: |
326 | 0 | AssociativeMath = false; |
327 | 0 | break; |
328 | 0 | case options::OPT_freciprocal_math: |
329 | 0 | ReciprocalMath = true; |
330 | 0 | break; |
331 | 0 | case options::OPT_fno_reciprocal_math: |
332 | 0 | ReciprocalMath = false; |
333 | 0 | break; |
334 | 0 | case options::OPT_Ofast: |
335 | 0 | [[fallthrough]]; |
336 | 0 | case options::OPT_ffast_math: |
337 | 0 | HonorINFs = false; |
338 | 0 | HonorNaNs = false; |
339 | 0 | AssociativeMath = true; |
340 | 0 | ReciprocalMath = true; |
341 | 0 | ApproxFunc = true; |
342 | 0 | SignedZeros = false; |
343 | 0 | FPContract = "fast"; |
344 | 0 | break; |
345 | 0 | case options::OPT_fno_fast_math: |
346 | 0 | HonorINFs = true; |
347 | 0 | HonorNaNs = true; |
348 | 0 | AssociativeMath = false; |
349 | 0 | ReciprocalMath = false; |
350 | 0 | ApproxFunc = false; |
351 | 0 | SignedZeros = true; |
352 | | // -fno-fast-math should undo -ffast-math so I return FPContract to the |
353 | | // default. It is important to check it is "fast" (the default) so that |
354 | | // --ffp-contract=off -fno-fast-math --> -ffp-contract=off |
355 | 0 | if (FPContract == "fast") |
356 | 0 | FPContract = ""; |
357 | 0 | break; |
358 | 112 | } |
359 | | |
360 | | // If we handled this option claim it |
361 | 0 | A->claim(); |
362 | 0 | } |
363 | | |
364 | 15 | if (!HonorINFs && !HonorNaNs0 && AssociativeMath0 && ReciprocalMath0 && |
365 | 15 | ApproxFunc0 && !SignedZeros0 && |
366 | 15 | (0 FPContract == "fast"0 || FPContract == ""0 )) { |
367 | 0 | CmdArgs.push_back("-ffast-math"); |
368 | 0 | return; |
369 | 0 | } |
370 | | |
371 | 15 | if (!FPContract.empty()) |
372 | 0 | CmdArgs.push_back(Args.MakeArgString("-ffp-contract=" + FPContract)); |
373 | | |
374 | 15 | if (!HonorINFs) |
375 | 0 | CmdArgs.push_back("-menable-no-infs"); |
376 | | |
377 | 15 | if (!HonorNaNs) |
378 | 0 | CmdArgs.push_back("-menable-no-nans"); |
379 | | |
380 | 15 | if (ApproxFunc) |
381 | 0 | CmdArgs.push_back("-fapprox-func"); |
382 | | |
383 | 15 | if (!SignedZeros) |
384 | 0 | CmdArgs.push_back("-fno-signed-zeros"); |
385 | | |
386 | 15 | if (AssociativeMath && !SignedZeros0 ) |
387 | 0 | CmdArgs.push_back("-mreassociate"); |
388 | | |
389 | 15 | if (ReciprocalMath) |
390 | 0 | CmdArgs.push_back("-freciprocal-math"); |
391 | 15 | } |
392 | | |
393 | | static void renderRemarksOptions(const ArgList &Args, ArgStringList &CmdArgs, |
394 | 0 | const InputInfo &Input) { |
395 | 0 | StringRef Format = "yaml"; |
396 | 0 | if (const Arg *A = Args.getLastArg(options::OPT_fsave_optimization_record_EQ)) |
397 | 0 | Format = A->getValue(); |
398 | |
|
399 | 0 | CmdArgs.push_back("-opt-record-file"); |
400 | |
|
401 | 0 | const Arg *A = Args.getLastArg(options::OPT_foptimization_record_file_EQ); |
402 | 0 | if (A) { |
403 | 0 | CmdArgs.push_back(A->getValue()); |
404 | 0 | } else { |
405 | 0 | SmallString<128> F; |
406 | |
|
407 | 0 | if (Args.hasArg(options::OPT_c) || Args.hasArg(options::OPT_S)) { |
408 | 0 | if (Arg *FinalOutput = Args.getLastArg(options::OPT_o)) |
409 | 0 | F = FinalOutput->getValue(); |
410 | 0 | } |
411 | |
|
412 | 0 | if (F.empty()) { |
413 | | // Use the input filename. |
414 | 0 | F = llvm::sys::path::stem(Input.getBaseInput()); |
415 | 0 | } |
416 | |
|
417 | 0 | SmallString<32> Extension; |
418 | 0 | Extension += "opt."; |
419 | 0 | Extension += Format; |
420 | |
|
421 | 0 | llvm::sys::path::replace_extension(F, Extension); |
422 | 0 | CmdArgs.push_back(Args.MakeArgString(F)); |
423 | 0 | } |
424 | |
|
425 | 0 | if (const Arg *A = |
426 | 0 | Args.getLastArg(options::OPT_foptimization_record_passes_EQ)) { |
427 | 0 | CmdArgs.push_back("-opt-record-passes"); |
428 | 0 | CmdArgs.push_back(A->getValue()); |
429 | 0 | } |
430 | |
|
431 | 0 | if (!Format.empty()) { |
432 | 0 | CmdArgs.push_back("-opt-record-format"); |
433 | 0 | CmdArgs.push_back(Format.data()); |
434 | 0 | } |
435 | 0 | } |
436 | | |
437 | | void Flang::ConstructJob(Compilation &C, const JobAction &JA, |
438 | | const InputInfo &Output, const InputInfoList &Inputs, |
439 | 15 | const ArgList &Args, const char *LinkingOutput) const { |
440 | 15 | const auto &TC = getToolChain(); |
441 | 15 | const llvm::Triple &Triple = TC.getEffectiveTriple(); |
442 | 15 | const std::string &TripleStr = Triple.getTriple(); |
443 | | |
444 | 15 | const Driver &D = TC.getDriver(); |
445 | 15 | ArgStringList CmdArgs; |
446 | 15 | DiagnosticsEngine &Diags = D.getDiags(); |
447 | | |
448 | | // Invoke ourselves in -fc1 mode. |
449 | 15 | CmdArgs.push_back("-fc1"); |
450 | | |
451 | | // Add the "effective" target triple. |
452 | 15 | CmdArgs.push_back("-triple"); |
453 | 15 | CmdArgs.push_back(Args.MakeArgString(TripleStr)); |
454 | | |
455 | 15 | if (isa<PreprocessJobAction>(JA)) { |
456 | 2 | CmdArgs.push_back("-E"); |
457 | 13 | } else if (isa<CompileJobAction>(JA) || isa<BackendJobAction>(JA)8 ) { |
458 | 11 | if (JA.getType() == types::TY_Nothing) { |
459 | 5 | CmdArgs.push_back("-fsyntax-only"); |
460 | 6 | } else if (JA.getType() == types::TY_AST) { |
461 | 0 | CmdArgs.push_back("-emit-ast"); |
462 | 6 | } else if (JA.getType() == types::TY_LLVM_IR || |
463 | 6 | JA.getType() == types::TY_LTO_IR4 ) { |
464 | 2 | CmdArgs.push_back("-emit-llvm"); |
465 | 4 | } else if (JA.getType() == types::TY_LLVM_BC || |
466 | 4 | JA.getType() == types::TY_LTO_BC2 ) { |
467 | 2 | CmdArgs.push_back("-emit-llvm-bc"); |
468 | 2 | } else if (JA.getType() == types::TY_PP_Asm) { |
469 | 2 | CmdArgs.push_back("-S"); |
470 | 2 | } else { |
471 | 0 | assert(false && "Unexpected output type!"); |
472 | 0 | } |
473 | 11 | } else if (2 isa<AssembleJobAction>(JA)2 ) { |
474 | 2 | CmdArgs.push_back("-emit-obj"); |
475 | 2 | } else { |
476 | 0 | assert(false && "Unexpected action class for Flang tool."); |
477 | 0 | } |
478 | | |
479 | 15 | const InputInfo &Input = Inputs[0]; |
480 | 15 | types::ID InputType = Input.getType(); |
481 | | |
482 | | // Add preprocessing options like -I, -D, etc. if we are using the |
483 | | // preprocessor (i.e. skip when dealing with e.g. binary files). |
484 | 15 | if (types::getPreprocessedType(InputType) != types::TY_INVALID) |
485 | 15 | addPreprocessingOptions(Args, CmdArgs); |
486 | | |
487 | 15 | addFortranDialectOptions(Args, CmdArgs); |
488 | | |
489 | | // Color diagnostics are parsed by the driver directly from argv and later |
490 | | // re-parsed to construct this job; claim any possible color diagnostic here |
491 | | // to avoid warn_drv_unused_argument. |
492 | 15 | Args.getLastArg(options::OPT_fcolor_diagnostics, |
493 | 15 | options::OPT_fno_color_diagnostics); |
494 | 15 | if (Diags.getDiagnosticOptions().ShowColors) |
495 | 0 | CmdArgs.push_back("-fcolor-diagnostics"); |
496 | | |
497 | | // LTO mode is parsed by the Clang driver library. |
498 | 15 | LTOKind LTOMode = D.getLTOMode(/* IsOffload */ false); |
499 | 15 | assert(LTOMode != LTOK_Unknown && "Unknown LTO mode."); |
500 | 15 | if (LTOMode == LTOK_Full) |
501 | 0 | CmdArgs.push_back("-flto=full"); |
502 | 15 | else if (LTOMode == LTOK_Thin) { |
503 | 0 | Diags.Report( |
504 | 0 | Diags.getCustomDiagID(DiagnosticsEngine::Warning, |
505 | 0 | "the option '-flto=thin' is a work in progress")); |
506 | 0 | CmdArgs.push_back("-flto=thin"); |
507 | 0 | } |
508 | | |
509 | | // -fPIC and related options. |
510 | 15 | addPicOptions(Args, CmdArgs); |
511 | | |
512 | | // Floating point related options |
513 | 15 | addFloatingPointOptions(D, Args, CmdArgs); |
514 | | |
515 | | // Add target args, features, etc. |
516 | 15 | addTargetOptions(Args, CmdArgs); |
517 | | |
518 | | // Add Codegen options |
519 | 15 | addCodegenOptions(Args, CmdArgs); |
520 | | |
521 | | // Add R Group options |
522 | 15 | Args.AddAllArgs(CmdArgs, options::OPT_R_Group); |
523 | | |
524 | | // Remarks can be enabled with any of the `-f.*optimization-record.*` flags. |
525 | 15 | if (willEmitRemarks(Args)) |
526 | 0 | renderRemarksOptions(Args, CmdArgs, Input); |
527 | | |
528 | | // Add other compile options |
529 | 15 | addOtherOptions(Args, CmdArgs); |
530 | | |
531 | | // Offloading related options |
532 | 15 | addOffloadOptions(C, Inputs, JA, Args, CmdArgs); |
533 | | |
534 | | // Forward -Xflang arguments to -fc1 |
535 | 15 | Args.AddAllArgValues(CmdArgs, options::OPT_Xflang); |
536 | | |
537 | | // Forward -mllvm options to the LLVM option parser. In practice, this means |
538 | | // forwarding to `-fc1` as that's where the LLVM parser is run. |
539 | 15 | for (const Arg *A : Args.filtered(options::OPT_mllvm)) { |
540 | 0 | A->claim(); |
541 | 0 | A->render(Args, CmdArgs); |
542 | 0 | } |
543 | | |
544 | 15 | for (const Arg *A : Args.filtered(options::OPT_mmlir)) { |
545 | 0 | A->claim(); |
546 | 0 | A->render(Args, CmdArgs); |
547 | 0 | } |
548 | | |
549 | | // Remove any unsupported gfortran diagnostic options |
550 | 15 | for (const Arg *A : Args.filtered(options::OPT_flang_ignored_w_Group)) { |
551 | 0 | A->claim(); |
552 | 0 | D.Diag(diag::warn_drv_unsupported_diag_option_for_flang) |
553 | 0 | << A->getOption().getName(); |
554 | 0 | } |
555 | | |
556 | | // Optimization level for CodeGen. |
557 | 15 | if (const Arg *A = Args.getLastArg(options::OPT_O_Group)) { |
558 | 0 | if (A->getOption().matches(options::OPT_O4)) { |
559 | 0 | CmdArgs.push_back("-O3"); |
560 | 0 | D.Diag(diag::warn_O4_is_O3); |
561 | 0 | } else if (A->getOption().matches(options::OPT_Ofast)) { |
562 | 0 | CmdArgs.push_back("-O3"); |
563 | 0 | } else { |
564 | 0 | A->render(Args, CmdArgs); |
565 | 0 | } |
566 | 0 | } |
567 | | |
568 | 15 | if (Output.isFilename()) { |
569 | 10 | CmdArgs.push_back("-o"); |
570 | 10 | CmdArgs.push_back(Output.getFilename()); |
571 | 10 | } else { |
572 | 5 | assert(Output.isNothing() && "Invalid output."); |
573 | 5 | } |
574 | | |
575 | 15 | assert(Input.isFilename() && "Invalid input."); |
576 | | |
577 | 15 | if (Args.getLastArg(options::OPT_save_temps_EQ)) |
578 | 0 | Args.AddLastArg(CmdArgs, options::OPT_save_temps_EQ); |
579 | | |
580 | 15 | addDashXForInput(Args, Input, CmdArgs); |
581 | | |
582 | 15 | CmdArgs.push_back(Input.getFilename()); |
583 | | |
584 | | // TODO: Replace flang-new with flang once the new driver replaces the |
585 | | // throwaway driver |
586 | 15 | const char *Exec = Args.MakeArgString(D.GetProgramPath("flang-new", TC)); |
587 | 15 | C.addCommand(std::make_unique<Command>(JA, *this, |
588 | 15 | ResponseFileSupport::AtFileUTF8(), |
589 | 15 | Exec, CmdArgs, Inputs, Output)); |
590 | 15 | } |
591 | | |
592 | 14 | Flang::Flang(const ToolChain &TC) : Tool("flang-new", "flang frontend", TC) {} |
593 | | |
594 | 14 | Flang::~Flang() {} |