1//===- CompilerInvocation.cpp ---------------------------------------------===//
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// Coding style: https://mlir.llvm.org/getting_started/DeveloperGuide/
10//
11//===----------------------------------------------------------------------===//
12
13#include "flang/Frontend/CompilerInvocation.h"
14#include "flang/Frontend/CodeGenOptions.h"
15#include "flang/Frontend/PreprocessorOptions.h"
16#include "flang/Frontend/TargetOptions.h"
17#include "flang/Semantics/semantics.h"
18#include "flang/Support/Fortran-features.h"
19#include "flang/Support/OpenMP-features.h"
20#include "flang/Support/Version.h"
21#include "flang/Tools/TargetSetup.h"
22#include "flang/Version.inc"
23#include "clang/Basic/DiagnosticDriver.h"
24#include "clang/Basic/DiagnosticOptions.h"
25#include "clang/Driver/CommonArgs.h"
26#include "clang/Driver/Driver.h"
27#include "clang/Driver/OptionUtils.h"
28#include "clang/Driver/Options.h"
29#include "llvm/ADT/StringRef.h"
30#include "llvm/ADT/StringSwitch.h"
31#include "llvm/Frontend/Debug/Options.h"
32#include "llvm/Option/Arg.h"
33#include "llvm/Option/ArgList.h"
34#include "llvm/Option/OptTable.h"
35#include "llvm/Support/CodeGen.h"
36#include "llvm/Support/FileSystem.h"
37#include "llvm/Support/Path.h"
38#include "llvm/Support/Process.h"
39#include "llvm/Support/raw_ostream.h"
40#include "llvm/TargetParser/Host.h"
41#include "llvm/TargetParser/Triple.h"
42#include <algorithm>
43#include <cstdlib>
44#include <memory>
45#include <optional>
46
47using namespace Fortran::frontend;
48
49//===----------------------------------------------------------------------===//
50// Initialization.
51//===----------------------------------------------------------------------===//
52CompilerInvocationBase::CompilerInvocationBase()
53 : diagnosticOpts(new clang::DiagnosticOptions()),
54 preprocessorOpts(new PreprocessorOptions()) {}
55
56CompilerInvocationBase::CompilerInvocationBase(const CompilerInvocationBase &x)
57 : diagnosticOpts(new clang::DiagnosticOptions(x.getDiagnosticOpts())),
58 preprocessorOpts(new PreprocessorOptions(x.getPreprocessorOpts())) {}
59
60CompilerInvocationBase::~CompilerInvocationBase() = default;
61
62//===----------------------------------------------------------------------===//
63// Deserialization (from args)
64//===----------------------------------------------------------------------===//
65static bool parseShowColorsArgs(const llvm::opt::ArgList &args,
66 bool defaultColor = true) {
67 // Color diagnostics default to auto ("on" if terminal supports) in the
68 // compiler driver `flang` but default to off in the frontend driver
69 // `flang -fc1`, needing an explicit OPT_fdiagnostics_color.
70 // Support both clang's -f[no-]color-diagnostics and gcc's
71 // -f[no-]diagnostics-colors[=never|always|auto].
72 enum {
73 Colors_On,
74 Colors_Off,
75 Colors_Auto
76 } showColors = defaultColor ? Colors_Auto : Colors_Off;
77
78 for (auto *a : args) {
79 const llvm::opt::Option &opt = a->getOption();
80 if (opt.matches(clang::driver::options::ID: OPT_fcolor_diagnostics)) {
81 showColors = Colors_On;
82 } else if (opt.matches(clang::driver::options::ID: OPT_fno_color_diagnostics)) {
83 showColors = Colors_Off;
84 } else if (opt.matches(clang::driver::options::ID: OPT_fdiagnostics_color_EQ)) {
85 llvm::StringRef value(a->getValue());
86 if (value == "always")
87 showColors = Colors_On;
88 else if (value == "never")
89 showColors = Colors_Off;
90 else if (value == "auto")
91 showColors = Colors_Auto;
92 }
93 }
94
95 return showColors == Colors_On ||
96 (showColors == Colors_Auto &&
97 llvm::sys::Process::StandardErrHasColors());
98}
99
100/// Extracts the optimisation level from \a args.
101static unsigned getOptimizationLevel(llvm::opt::ArgList &args,
102 clang::DiagnosticsEngine &diags) {
103 unsigned defaultOpt = 0;
104
105 if (llvm::opt::Arg *a =
106 args.getLastArg(clang::driver::options::OPT_O_Group)) {
107 if (a->getOption().matches(clang::driver::options::ID: OPT_O0))
108 return 0;
109
110 assert(a->getOption().matches(clang::driver::options::OPT_O));
111
112 return getLastArgIntValue(args, clang::driver::options::OPT_O, defaultOpt,
113 diags);
114 }
115
116 return defaultOpt;
117}
118
119bool Fortran::frontend::parseDiagnosticArgs(clang::DiagnosticOptions &opts,
120 llvm::opt::ArgList &args) {
121 opts.ShowColors = parseShowColorsArgs(args);
122
123 return true;
124}
125
126static bool parseDebugArgs(Fortran::frontend::CodeGenOptions &opts,
127 llvm::opt::ArgList &args,
128 clang::DiagnosticsEngine &diags) {
129 using DebugInfoKind = llvm::codegenoptions::DebugInfoKind;
130 if (llvm::opt::Arg *arg =
131 args.getLastArg(clang::driver::options::OPT_debug_info_kind_EQ)) {
132 std::optional<DebugInfoKind> val =
133 llvm::StringSwitch<std::optional<DebugInfoKind>>(arg->getValue())
134 .Case(S: "line-tables-only", Value: llvm::codegenoptions::DebugLineTablesOnly)
135 .Case(S: "line-directives-only",
136 Value: llvm::codegenoptions::DebugDirectivesOnly)
137 .Case(S: "constructor", Value: llvm::codegenoptions::DebugInfoConstructor)
138 .Case(S: "limited", Value: llvm::codegenoptions::LimitedDebugInfo)
139 .Case(S: "standalone", Value: llvm::codegenoptions::FullDebugInfo)
140 .Case(S: "unused-types", Value: llvm::codegenoptions::UnusedTypeInfo)
141 .Default(Value: std::nullopt);
142 if (!val.has_value()) {
143 diags.Report(clang::diag::err_drv_invalid_value)
144 << arg->getAsString(Args: args) << arg->getValue();
145 return false;
146 }
147 opts.setDebugInfo(val.value());
148 if (val != llvm::codegenoptions::DebugLineTablesOnly &&
149 val != llvm::codegenoptions::FullDebugInfo &&
150 val != llvm::codegenoptions::NoDebugInfo) {
151 const auto debugWarning = diags.getCustomDiagID(
152 L: clang::DiagnosticsEngine::Warning, FormatString: "Unsupported debug option: %0");
153 diags.Report(DiagID: debugWarning) << arg->getValue();
154 }
155 }
156 return true;
157}
158
159static void parseDoConcurrentMapping(Fortran::frontend::CodeGenOptions &opts,
160 llvm::opt::ArgList &args,
161 clang::DiagnosticsEngine &diags) {
162 llvm::opt::Arg *arg =
163 args.getLastArg(clang::driver::options::OPT_fdo_concurrent_to_openmp_EQ);
164 if (!arg)
165 return;
166
167 using DoConcurrentMappingKind =
168 Fortran::frontend::CodeGenOptions::DoConcurrentMappingKind;
169 std::optional<DoConcurrentMappingKind> val =
170 llvm::StringSwitch<std::optional<DoConcurrentMappingKind>>(
171 arg->getValue())
172 .Case("none", DoConcurrentMappingKind::DCMK_None)
173 .Case("host", DoConcurrentMappingKind::DCMK_Host)
174 .Case("device", DoConcurrentMappingKind::DCMK_Device)
175 .Default(std::nullopt);
176
177 if (!val.has_value()) {
178 diags.Report(clang::diag::err_drv_invalid_value)
179 << arg->getAsString(Args: args) << arg->getValue();
180 }
181
182 opts.setDoConcurrentMapping(val.value());
183}
184
185static bool parseVectorLibArg(Fortran::frontend::CodeGenOptions &opts,
186 llvm::opt::ArgList &args,
187 clang::DiagnosticsEngine &diags) {
188 llvm::opt::Arg *arg = args.getLastArg(clang::driver::options::OPT_fveclib);
189 if (!arg)
190 return true;
191
192 using VectorLibrary = llvm::driver::VectorLibrary;
193 std::optional<VectorLibrary> val =
194 llvm::StringSwitch<std::optional<VectorLibrary>>(arg->getValue())
195 .Case(S: "Accelerate", Value: VectorLibrary::Accelerate)
196 .Case(S: "libmvec", Value: VectorLibrary::LIBMVEC)
197 .Case(S: "MASSV", Value: VectorLibrary::MASSV)
198 .Case(S: "SVML", Value: VectorLibrary::SVML)
199 .Case(S: "SLEEF", Value: VectorLibrary::SLEEF)
200 .Case(S: "Darwin_libsystem_m", Value: VectorLibrary::Darwin_libsystem_m)
201 .Case(S: "ArmPL", Value: VectorLibrary::ArmPL)
202 .Case(S: "AMDLIBM", Value: VectorLibrary::AMDLIBM)
203 .Case(S: "NoLibrary", Value: VectorLibrary::NoLibrary)
204 .Default(Value: std::nullopt);
205 if (!val.has_value()) {
206 diags.Report(clang::diag::err_drv_invalid_value)
207 << arg->getAsString(Args: args) << arg->getValue();
208 return false;
209 }
210 opts.setVecLib(val.value());
211 return true;
212}
213
214// Generate an OptRemark object containing info on if the -Rgroup
215// specified is enabled or not.
216static CodeGenOptions::OptRemark
217parseOptimizationRemark(clang::DiagnosticsEngine &diags,
218 llvm::opt::ArgList &args, llvm::opt::OptSpecifier optEq,
219 llvm::StringRef remarkOptName) {
220 assert((remarkOptName == "pass" || remarkOptName == "pass-missed" ||
221 remarkOptName == "pass-analysis") &&
222 "Unsupported remark option name provided.");
223 CodeGenOptions::OptRemark result;
224
225 for (llvm::opt::Arg *a : args) {
226 if (a->getOption().matches(clang::driver::options::ID: OPT_R_Joined)) {
227 llvm::StringRef value = a->getValue();
228
229 if (value == remarkOptName) {
230 result.Kind = CodeGenOptions::RemarkKind::RK_Enabled;
231 // Enable everything
232 result.Pattern = ".*";
233 result.Regex = std::make_shared<llvm::Regex>(args&: result.Pattern);
234
235 } else if (value.split(Separator: '-') ==
236 std::make_pair(x: llvm::StringRef("no"), y&: remarkOptName)) {
237 result.Kind = CodeGenOptions::RemarkKind::RK_Disabled;
238 // Disable everything
239 result.Pattern = "";
240 result.Regex = nullptr;
241 }
242 } else if (a->getOption().matches(ID: optEq)) {
243 result.Kind = CodeGenOptions::RemarkKind::RK_WithPattern;
244 result.Pattern = a->getValue();
245 result.Regex = std::make_shared<llvm::Regex>(args&: result.Pattern);
246 std::string regexError;
247
248 if (!result.Regex->isValid(Error&: regexError)) {
249 diags.Report(clang::diag::err_drv_optimization_remark_pattern)
250 << regexError << a->getAsString(Args: args);
251 return CodeGenOptions::OptRemark();
252 }
253 }
254 }
255 return result;
256}
257
258static void parseCodeGenArgs(Fortran::frontend::CodeGenOptions &opts,
259 llvm::opt::ArgList &args,
260 clang::DiagnosticsEngine &diags) {
261 opts.OptimizationLevel = getOptimizationLevel(args, diags);
262
263 if (args.hasFlag(clang::driver::options::OPT_fdebug_pass_manager,
264 clang::driver::options::OPT_fno_debug_pass_manager, false))
265 opts.DebugPassManager = 1;
266
267 if (args.hasFlag(clang::driver::options::OPT_fstack_arrays,
268 clang::driver::options::OPT_fno_stack_arrays, false))
269 opts.StackArrays = 1;
270
271 if (args.getLastArg(clang::driver::options::OPT_floop_interchange))
272 opts.InterchangeLoops = 1;
273
274 if (args.getLastArg(clang::driver::options::OPT_vectorize_loops))
275 opts.VectorizeLoop = 1;
276
277 if (args.getLastArg(clang::driver::options::OPT_vectorize_slp))
278 opts.VectorizeSLP = 1;
279
280 if (args.hasFlag(clang::driver::options::OPT_floop_versioning,
281 clang::driver::options::OPT_fno_loop_versioning, false))
282 opts.LoopVersioning = 1;
283
284 opts.UnrollLoops = args.hasFlag(clang::driver::options::OPT_funroll_loops,
285 clang::driver::options::OPT_fno_unroll_loops,
286 (opts.OptimizationLevel > 1));
287
288 opts.AliasAnalysis = opts.OptimizationLevel > 0;
289
290 // -mframe-pointer=none/non-leaf/all option.
291 if (const llvm::opt::Arg *a =
292 args.getLastArg(clang::driver::options::OPT_mframe_pointer_EQ)) {
293 std::optional<llvm::FramePointerKind> val =
294 llvm::StringSwitch<std::optional<llvm::FramePointerKind>>(a->getValue())
295 .Case(S: "none", Value: llvm::FramePointerKind::None)
296 .Case(S: "non-leaf", Value: llvm::FramePointerKind::NonLeaf)
297 .Case(S: "all", Value: llvm::FramePointerKind::All)
298 .Default(Value: std::nullopt);
299
300 if (!val.has_value()) {
301 diags.Report(clang::diag::err_drv_invalid_value)
302 << a->getAsString(Args: args) << a->getValue();
303 } else
304 opts.setFramePointer(val.value());
305 }
306
307 for (auto *a : args.filtered(clang::driver::options::OPT_fpass_plugin_EQ))
308 opts.LLVMPassPlugins.push_back(a->getValue());
309
310 opts.Reciprocals = clang::driver::tools::parseMRecipOption(Diags&: diags, Args: args);
311
312 opts.PreferVectorWidth =
313 clang::driver::tools::parseMPreferVectorWidthOption(Diags&: diags, Args: args);
314
315 // -fembed-offload-object option
316 for (auto *a :
317 args.filtered(clang::driver::options::OPT_fembed_offload_object_EQ))
318 opts.OffloadObjects.push_back(a->getValue());
319
320 if (args.hasArg(clang::driver::options::OPT_finstrument_functions))
321 opts.InstrumentFunctions = 1;
322
323 // -flto=full/thin option.
324 if (const llvm::opt::Arg *a =
325 args.getLastArg(clang::driver::options::OPT_flto_EQ)) {
326 llvm::StringRef s = a->getValue();
327 assert((s == "full" || s == "thin") && "Unknown LTO mode.");
328 if (s == "full")
329 opts.PrepareForFullLTO = true;
330 else
331 opts.PrepareForThinLTO = true;
332 }
333
334 if (const llvm::opt::Arg *a = args.getLastArg(
335 clang::driver::options::OPT_mcode_object_version_EQ)) {
336 llvm::StringRef s = a->getValue();
337 if (s == "6")
338 opts.CodeObjectVersion = llvm::CodeObjectVersionKind::COV_6;
339 if (s == "5")
340 opts.CodeObjectVersion = llvm::CodeObjectVersionKind::COV_5;
341 if (s == "4")
342 opts.CodeObjectVersion = llvm::CodeObjectVersionKind::COV_4;
343 if (s == "none")
344 opts.CodeObjectVersion = llvm::CodeObjectVersionKind::COV_None;
345 }
346
347 // -f[no-]save-optimization-record[=<format>]
348 if (const llvm::opt::Arg *a =
349 args.getLastArg(clang::driver::options::OPT_opt_record_file))
350 opts.OptRecordFile = a->getValue();
351
352 // Optimization file format. Defaults to yaml
353 if (const llvm::opt::Arg *a =
354 args.getLastArg(clang::driver::options::OPT_opt_record_format))
355 opts.OptRecordFormat = a->getValue();
356
357 // Specifies, using a regex, which successful optimization passes(middle and
358 // backend), to include in the final optimization record file generated. If
359 // not provided -fsave-optimization-record will include all passes.
360 if (const llvm::opt::Arg *a =
361 args.getLastArg(clang::driver::options::OPT_opt_record_passes))
362 opts.OptRecordPasses = a->getValue();
363
364 // Create OptRemark that allows printing of all successful optimization
365 // passes applied.
366 opts.OptimizationRemark =
367 parseOptimizationRemark(diags, args, clang::driver::options::OPT_Rpass_EQ,
368 /*remarkOptName=*/"pass");
369
370 // Create OptRemark that allows all missed optimization passes to be printed.
371 opts.OptimizationRemarkMissed = parseOptimizationRemark(
372 diags, args, clang::driver::options::OPT_Rpass_missed_EQ,
373 /*remarkOptName=*/"pass-missed");
374
375 // Create OptRemark that allows all optimization decisions made by LLVM
376 // to be printed.
377 opts.OptimizationRemarkAnalysis = parseOptimizationRemark(
378 diags, args, clang::driver::options::OPT_Rpass_analysis_EQ,
379 /*remarkOptName=*/"pass-analysis");
380
381 if (opts.getDebugInfo() == llvm::codegenoptions::NoDebugInfo) {
382 // If the user requested a flag that requires source locations available in
383 // the backend, make sure that the backend tracks source location
384 // information.
385 bool needLocTracking = !opts.OptRecordFile.empty() ||
386 !opts.OptRecordPasses.empty() ||
387 !opts.OptRecordFormat.empty() ||
388 opts.OptimizationRemark.hasValidPattern() ||
389 opts.OptimizationRemarkMissed.hasValidPattern() ||
390 opts.OptimizationRemarkAnalysis.hasValidPattern();
391
392 if (needLocTracking)
393 opts.setDebugInfo(llvm::codegenoptions::LocTrackingOnly);
394 }
395
396 if (auto *a = args.getLastArg(clang::driver::options::OPT_save_temps_EQ))
397 opts.SaveTempsDir = a->getValue();
398
399 // -record-command-line option.
400 if (const llvm::opt::Arg *a =
401 args.getLastArg(clang::driver::options::OPT_record_command_line)) {
402 opts.RecordCommandLine = a->getValue();
403 }
404
405 // -mlink-builtin-bitcode
406 for (auto *a :
407 args.filtered(clang::driver::options::OPT_mlink_builtin_bitcode))
408 opts.BuiltinBCLibs.push_back(a->getValue());
409
410 // -mrelocation-model option.
411 if (const llvm::opt::Arg *a =
412 args.getLastArg(clang::driver::options::OPT_mrelocation_model)) {
413 llvm::StringRef modelName = a->getValue();
414 auto relocModel =
415 llvm::StringSwitch<std::optional<llvm::Reloc::Model>>(modelName)
416 .Case(S: "static", Value: llvm::Reloc::Static)
417 .Case(S: "pic", Value: llvm::Reloc::PIC_)
418 .Case(S: "dynamic-no-pic", Value: llvm::Reloc::DynamicNoPIC)
419 .Case(S: "ropi", Value: llvm::Reloc::ROPI)
420 .Case(S: "rwpi", Value: llvm::Reloc::RWPI)
421 .Case(S: "ropi-rwpi", Value: llvm::Reloc::ROPI_RWPI)
422 .Default(Value: std::nullopt);
423 if (relocModel.has_value())
424 opts.setRelocationModel(*relocModel);
425 else
426 diags.Report(clang::diag::err_drv_invalid_value)
427 << a->getAsString(args) << modelName;
428 }
429
430 // -pic-level and -pic-is-pie option.
431 if (int picLevel = getLastArgIntValue(
432 args, clang::driver::options::OPT_pic_level, 0, diags)) {
433 if (picLevel > 2)
434 diags.Report(clang::diag::err_drv_invalid_value)
435 << args.getLastArg(clang::driver::options::OPT_pic_level)
436 ->getAsString(args)
437 << picLevel;
438
439 opts.PICLevel = picLevel;
440 if (args.hasArg(clang::driver::options::OPT_pic_is_pie))
441 opts.IsPIE = 1;
442 }
443
444 // -mcmodel option.
445 if (const llvm::opt::Arg *a =
446 args.getLastArg(clang::driver::options::OPT_mcmodel_EQ)) {
447 llvm::StringRef modelName = a->getValue();
448 std::optional<llvm::CodeModel::Model> codeModel = getCodeModel(modelName);
449
450 if (codeModel.has_value())
451 opts.CodeModel = modelName;
452 else
453 diags.Report(clang::diag::err_drv_invalid_value)
454 << a->getAsString(args) << modelName;
455 }
456
457 if (const llvm::opt::Arg *arg = args.getLastArg(
458 clang::driver::options::OPT_mlarge_data_threshold_EQ)) {
459 uint64_t LDT;
460 if (llvm::StringRef(arg->getValue()).getAsInteger(/*Radix=*/10, Result&: LDT)) {
461 diags.Report(clang::diag::err_drv_invalid_value)
462 << arg->getSpelling() << arg->getValue();
463 }
464 opts.LargeDataThreshold = LDT;
465 }
466
467 // This option is compatible with -f[no-]underscoring in gfortran.
468 if (args.hasFlag(clang::driver::options::OPT_fno_underscoring,
469 clang::driver::options::OPT_funderscoring, false)) {
470 opts.Underscoring = 0;
471 }
472
473 parseDoConcurrentMapping(opts, args, diags);
474}
475
476/// Parses all target input arguments and populates the target
477/// options accordingly.
478///
479/// \param [in] opts The target options instance to update
480/// \param [in] args The list of input arguments (from the compiler invocation)
481static void parseTargetArgs(TargetOptions &opts, llvm::opt::ArgList &args) {
482 if (const llvm::opt::Arg *a =
483 args.getLastArg(clang::driver::options::OPT_triple))
484 opts.triple = a->getValue();
485
486 if (const llvm::opt::Arg *a =
487 args.getLastArg(clang::driver::options::OPT_target_cpu))
488 opts.cpu = a->getValue();
489
490 if (const llvm::opt::Arg *a =
491 args.getLastArg(clang::driver::options::OPT_tune_cpu))
492 opts.cpuToTuneFor = a->getValue();
493
494 for (const llvm::opt::Arg *currentArg :
495 args.filtered(clang::driver::options::OPT_target_feature))
496 opts.featuresAsWritten.emplace_back(currentArg->getValue());
497
498 if (args.hasArg(clang::driver::options::OPT_fdisable_real_10))
499 opts.disabledRealKinds.push_back(10);
500
501 if (args.hasArg(clang::driver::options::OPT_fdisable_real_3))
502 opts.disabledRealKinds.push_back(3);
503
504 if (args.hasArg(clang::driver::options::OPT_fdisable_integer_2))
505 opts.disabledIntegerKinds.push_back(2);
506
507 if (args.hasArg(clang::driver::options::OPT_fdisable_integer_16))
508 opts.disabledIntegerKinds.push_back(16);
509
510 if (const llvm::opt::Arg *a =
511 args.getLastArg(clang::driver::options::OPT_mabi_EQ)) {
512 opts.abi = a->getValue();
513 llvm::StringRef V = a->getValue();
514 if (V == "vec-extabi") {
515 opts.EnableAIXExtendedAltivecABI = true;
516 } else if (V == "vec-default") {
517 opts.EnableAIXExtendedAltivecABI = false;
518 }
519 }
520
521 opts.asmVerbose =
522 args.hasFlag(clang::driver::options::OPT_fverbose_asm,
523 clang::driver::options::OPT_fno_verbose_asm, false);
524}
525// Tweak the frontend configuration based on the frontend action
526static void setUpFrontendBasedOnAction(FrontendOptions &opts) {
527 if (opts.programAction == DebugDumpParsingLog)
528 opts.instrumentedParse = true;
529
530 if (opts.programAction == DebugDumpProvenance ||
531 opts.programAction == Fortran::frontend::GetDefinition)
532 opts.needProvenanceRangeToCharBlockMappings = true;
533}
534
535/// Parse the argument specified for the -fconvert=<value> option
536static std::optional<const char *> parseConvertArg(const char *s) {
537 return llvm::StringSwitch<std::optional<const char *>>(s)
538 .Case(S: "unknown", Value: "UNKNOWN")
539 .Case(S: "native", Value: "NATIVE")
540 .Case(S: "little-endian", Value: "LITTLE_ENDIAN")
541 .Case(S: "big-endian", Value: "BIG_ENDIAN")
542 .Case(S: "swap", Value: "SWAP")
543 .Default(Value: std::nullopt);
544}
545
546static bool parseFrontendArgs(FrontendOptions &opts, llvm::opt::ArgList &args,
547 clang::DiagnosticsEngine &diags) {
548 unsigned numErrorsBefore = diags.getNumErrors();
549
550 // By default the frontend driver creates a ParseSyntaxOnly action.
551 opts.programAction = ParseSyntaxOnly;
552
553 // Treat multiple action options as an invocation error. Note that `clang
554 // -cc1` does accept multiple action options, but will only consider the
555 // rightmost one.
556 if (args.hasMultipleArgs(clang::driver::options::OPT_Action_Group)) {
557 const unsigned diagID = diags.getCustomDiagID(
558 L: clang::DiagnosticsEngine::Error, FormatString: "Only one action option is allowed");
559 diags.Report(DiagID: diagID);
560 return false;
561 }
562
563 // Identify the action (i.e. opts.ProgramAction)
564 if (const llvm::opt::Arg *a =
565 args.getLastArg(clang::driver::options::OPT_Action_Group)) {
566 switch (a->getOption().getID()) {
567 default: {
568 llvm_unreachable("Invalid option in group!");
569 }
570 case clang::driver::options::OPT_test_io:
571 opts.programAction = InputOutputTest;
572 break;
573 case clang::driver::options::OPT_E:
574 opts.programAction = PrintPreprocessedInput;
575 break;
576 case clang::driver::options::OPT_fsyntax_only:
577 opts.programAction = ParseSyntaxOnly;
578 break;
579 case clang::driver::options::OPT_emit_fir:
580 opts.programAction = EmitFIR;
581 break;
582 case clang::driver::options::OPT_emit_hlfir:
583 opts.programAction = EmitHLFIR;
584 break;
585 case clang::driver::options::OPT_emit_llvm:
586 opts.programAction = EmitLLVM;
587 break;
588 case clang::driver::options::OPT_emit_llvm_bc:
589 opts.programAction = EmitLLVMBitcode;
590 break;
591 case clang::driver::options::OPT_emit_obj:
592 opts.programAction = EmitObj;
593 break;
594 case clang::driver::options::OPT_S:
595 opts.programAction = EmitAssembly;
596 break;
597 case clang::driver::options::OPT_fdebug_unparse:
598 opts.programAction = DebugUnparse;
599 break;
600 case clang::driver::options::OPT_fdebug_unparse_no_sema:
601 opts.programAction = DebugUnparseNoSema;
602 break;
603 case clang::driver::options::OPT_fdebug_unparse_with_symbols:
604 opts.programAction = DebugUnparseWithSymbols;
605 break;
606 case clang::driver::options::OPT_fdebug_unparse_with_modules:
607 opts.programAction = DebugUnparseWithModules;
608 break;
609 case clang::driver::options::OPT_fdebug_dump_symbols:
610 opts.programAction = DebugDumpSymbols;
611 break;
612 case clang::driver::options::OPT_fdebug_dump_parse_tree:
613 opts.programAction = DebugDumpParseTree;
614 break;
615 case clang::driver::options::OPT_fdebug_dump_pft:
616 opts.programAction = DebugDumpPFT;
617 break;
618 case clang::driver::options::OPT_fdebug_dump_all:
619 opts.programAction = DebugDumpAll;
620 break;
621 case clang::driver::options::OPT_fdebug_dump_parse_tree_no_sema:
622 opts.programAction = DebugDumpParseTreeNoSema;
623 break;
624 case clang::driver::options::OPT_fdebug_dump_provenance:
625 opts.programAction = DebugDumpProvenance;
626 break;
627 case clang::driver::options::OPT_fdebug_dump_parsing_log:
628 opts.programAction = DebugDumpParsingLog;
629 break;
630 case clang::driver::options::OPT_fdebug_measure_parse_tree:
631 opts.programAction = DebugMeasureParseTree;
632 break;
633 case clang::driver::options::OPT_fdebug_pre_fir_tree:
634 opts.programAction = DebugPreFIRTree;
635 break;
636 case clang::driver::options::OPT_fget_symbols_sources:
637 opts.programAction = GetSymbolsSources;
638 break;
639 case clang::driver::options::OPT_fget_definition:
640 opts.programAction = GetDefinition;
641 break;
642 case clang::driver::options::OPT_init_only:
643 opts.programAction = InitOnly;
644 break;
645
646 // TODO:
647 // case clang::driver::options::OPT_emit_llvm:
648 // case clang::driver::options::OPT_emit_llvm_only:
649 // case clang::driver::options::OPT_emit_codegen_only:
650 // case clang::driver::options::OPT_emit_module:
651 // (...)
652 }
653
654 // Parse the values provided with `-fget-definition` (there should be 3
655 // integers)
656 if (llvm::opt::OptSpecifier(a->getOption().getID()) ==
657 clang::driver::options::OPT_fget_definition) {
658 unsigned optVals[3] = {0, 0, 0};
659
660 for (unsigned i = 0; i < 3; i++) {
661 llvm::StringRef val = a->getValue(N: i);
662
663 if (val.getAsInteger(Radix: 10, Result&: optVals[i])) {
664 // A non-integer was encountered - that's an error.
665 diags.Report(clang::diag::err_drv_invalid_value)
666 << a->getOption().getName() << val;
667 break;
668 }
669 }
670 opts.getDefVals.line = optVals[0];
671 opts.getDefVals.startColumn = optVals[1];
672 opts.getDefVals.endColumn = optVals[2];
673 }
674 }
675
676 // Parsing -load <dsopath> option and storing shared object path
677 if (llvm::opt::Arg *a = args.getLastArg(clang::driver::options::OPT_load)) {
678 opts.plugins.push_back(a->getValue());
679 }
680
681 // Parsing -plugin <name> option and storing plugin name and setting action
682 if (const llvm::opt::Arg *a =
683 args.getLastArg(clang::driver::options::OPT_plugin)) {
684 opts.programAction = PluginAction;
685 opts.actionName = a->getValue();
686 }
687
688 opts.outputFile = args.getLastArgValue(clang::driver::options::OPT_o);
689 opts.showHelp = args.hasArg(clang::driver::options::OPT_help);
690 opts.showVersion = args.hasArg(clang::driver::options::OPT_version);
691 opts.printSupportedCPUs =
692 args.hasArg(clang::driver::options::OPT_print_supported_cpus);
693
694 // Get the input kind (from the value passed via `-x`)
695 InputKind dashX(Language::Unknown);
696 if (const llvm::opt::Arg *a =
697 args.getLastArg(clang::driver::options::OPT_x)) {
698 llvm::StringRef xValue = a->getValue();
699 // Principal languages.
700 dashX = llvm::StringSwitch<InputKind>(xValue)
701 // Flang does not differentiate between pre-processed and not
702 // pre-processed inputs.
703 .Case("f95", Language::Fortran)
704 .Case("f95-cpp-input", Language::Fortran)
705 // CUDA Fortran
706 .Case("cuda", Language::Fortran)
707 .Default(Language::Unknown);
708
709 // Flang's intermediate representations.
710 if (dashX.isUnknown())
711 dashX = llvm::StringSwitch<InputKind>(xValue)
712 .Case("ir", Language::LLVM_IR)
713 .Case("fir", Language::MLIR)
714 .Case("mlir", Language::MLIR)
715 .Default(Language::Unknown);
716
717 if (dashX.isUnknown())
718 diags.Report(clang::diag::err_drv_invalid_value)
719 << a->getAsString(args) << a->getValue();
720 }
721
722 // Collect the input files and save them in our instance of FrontendOptions.
723 std::vector<std::string> inputs =
724 args.getAllArgValues(clang::driver::options::OPT_INPUT);
725 opts.inputs.clear();
726 if (inputs.empty())
727 // '-' is the default input if none is given.
728 inputs.push_back(x: "-");
729 for (unsigned i = 0, e = inputs.size(); i != e; ++i) {
730 InputKind ik = dashX;
731 if (ik.isUnknown()) {
732 ik = FrontendOptions::getInputKindForExtension(
733 llvm::StringRef(inputs[i]).rsplit('.').second);
734 if (ik.isUnknown())
735 ik = Language::Unknown;
736 if (i == 0)
737 dashX = ik;
738 }
739
740 opts.inputs.emplace_back(std::move(inputs[i]), ik);
741 }
742
743 // Set fortranForm based on options -ffree-form and -ffixed-form.
744 if (const auto *arg =
745 args.getLastArg(clang::driver::options::OPT_ffixed_form,
746 clang::driver::options::OPT_ffree_form)) {
747 opts.fortranForm =
748 arg->getOption().matches(clang::driver::options::OPT_ffixed_form)
749 ? FortranForm::FixedForm
750 : FortranForm::FreeForm;
751 }
752
753 // Set fixedFormColumns based on -ffixed-line-length=<value>
754 if (const auto *arg =
755 args.getLastArg(clang::driver::options::OPT_ffixed_line_length_EQ)) {
756 llvm::StringRef argValue = llvm::StringRef(arg->getValue());
757 std::int64_t columns = -1;
758 if (argValue == "none") {
759 columns = 0;
760 } else if (argValue.getAsInteger(/*Radix=*/10, Result&: columns)) {
761 columns = -1;
762 }
763 if (columns < 0) {
764 diags.Report(clang::diag::err_drv_negative_columns)
765 << arg->getOption().getName() << arg->getValue();
766 } else if (columns == 0) {
767 opts.fixedFormColumns = 1000000;
768 } else if (columns < 7) {
769 diags.Report(clang::diag::err_drv_small_columns)
770 << arg->getOption().getName() << arg->getValue() << "7";
771 } else {
772 opts.fixedFormColumns = columns;
773 }
774 }
775
776 // Set conversion based on -fconvert=<value>
777 if (const auto *arg =
778 args.getLastArg(clang::driver::options::OPT_fconvert_EQ)) {
779 const char *argValue = arg->getValue();
780 if (auto convert = parseConvertArg(argValue))
781 opts.envDefaults.push_back({"FORT_CONVERT", *convert});
782 else
783 diags.Report(clang::diag::err_drv_invalid_value)
784 << arg->getAsString(args) << argValue;
785 }
786
787 // -f{no-}implicit-none
788 opts.features.Enable(
789 Fortran::common::LanguageFeature::ImplicitNoneTypeAlways,
790 args.hasFlag(clang::driver::options::OPT_fimplicit_none,
791 clang::driver::options::OPT_fno_implicit_none, false));
792
793 // -f{no-}implicit-none-ext
794 opts.features.Enable(
795 Fortran::common::LanguageFeature::ImplicitNoneExternal,
796 args.hasFlag(clang::driver::options::OPT_fimplicit_none_ext,
797 clang::driver::options::OPT_fno_implicit_none_ext, false));
798
799 // -f{no-}backslash
800 opts.features.Enable(Fortran::common::LanguageFeature::BackslashEscapes,
801 args.hasFlag(clang::driver::options::OPT_fbackslash,
802 clang::driver::options::OPT_fno_backslash,
803 false));
804
805 // -f{no-}logical-abbreviations
806 opts.features.Enable(
807 Fortran::common::LanguageFeature::LogicalAbbreviations,
808 args.hasFlag(clang::driver::options::OPT_flogical_abbreviations,
809 clang::driver::options::OPT_fno_logical_abbreviations,
810 false));
811
812 // -f{no-}unsigned
813 opts.features.Enable(Fortran::common::LanguageFeature::Unsigned,
814 args.hasFlag(clang::driver::options::OPT_funsigned,
815 clang::driver::options::OPT_fno_unsigned,
816 false));
817
818 // -f{no-}xor-operator
819 opts.features.Enable(
820 Fortran::common::LanguageFeature::XOROperator,
821 args.hasFlag(clang::driver::options::OPT_fxor_operator,
822 clang::driver::options::OPT_fno_xor_operator, false));
823
824 // -fno-automatic
825 if (args.hasArg(clang::driver::options::OPT_fno_automatic)) {
826 opts.features.Enable(Fortran::common::LanguageFeature::DefaultSave);
827 }
828
829 // -f{no}-save-main-program
830 opts.features.Enable(
831 Fortran::common::LanguageFeature::SaveMainProgram,
832 args.hasFlag(clang::driver::options::OPT_fsave_main_program,
833 clang::driver::options::OPT_fno_save_main_program, false));
834
835 if (args.hasArg(
836 clang::driver::options::OPT_falternative_parameter_statement)) {
837 opts.features.Enable(Fortran::common::LanguageFeature::OldStyleParameter);
838 }
839 if (const llvm::opt::Arg *arg =
840 args.getLastArg(clang::driver::options::OPT_finput_charset_EQ)) {
841 llvm::StringRef argValue = arg->getValue();
842 if (argValue == "utf-8") {
843 opts.encoding = Fortran::parser::Encoding::UTF_8;
844 } else if (argValue == "latin-1") {
845 opts.encoding = Fortran::parser::Encoding::LATIN_1;
846 } else {
847 diags.Report(clang::diag::err_drv_invalid_value)
848 << arg->getAsString(args) << argValue;
849 }
850 }
851
852 setUpFrontendBasedOnAction(opts);
853 opts.dashX = dashX;
854
855 return diags.getNumErrors() == numErrorsBefore;
856}
857
858// Generate the path to look for intrinsic modules
859static std::string getIntrinsicDir(const char *argv) {
860 // TODO: Find a system independent API
861 llvm::SmallString<128> driverPath;
862 driverPath.assign(RHS: llvm::sys::fs::getMainExecutable(argv0: argv, MainExecAddr: nullptr));
863 llvm::sys::path::remove_filename(path&: driverPath);
864 driverPath.append(RHS: "/../include/flang/");
865 return std::string(driverPath);
866}
867
868// Generate the path to look for OpenMP headers
869static std::string getOpenMPHeadersDir(const char *argv) {
870 llvm::SmallString<128> includePath;
871 includePath.assign(RHS: llvm::sys::fs::getMainExecutable(argv0: argv, MainExecAddr: nullptr));
872 llvm::sys::path::remove_filename(path&: includePath);
873 includePath.append(RHS: "/../include/flang/OpenMP/");
874 return std::string(includePath);
875}
876
877/// Parses all preprocessor input arguments and populates the preprocessor
878/// options accordingly.
879///
880/// \param [in] opts The preprocessor options instance
881/// \param [out] args The list of input arguments
882static void parsePreprocessorArgs(Fortran::frontend::PreprocessorOptions &opts,
883 llvm::opt::ArgList &args) {
884 // Add macros from the command line.
885 for (const auto *currentArg : args.filtered(clang::driver::options::OPT_D,
886 clang::driver::options::OPT_U)) {
887 if (currentArg->getOption().matches(clang::driver::options::OPT_D)) {
888 opts.addMacroDef(currentArg->getValue());
889 } else {
890 opts.addMacroUndef(currentArg->getValue());
891 }
892 }
893
894 // Add the ordered list of -I's.
895 for (const auto *currentArg : args.filtered(clang::driver::options::OPT_I))
896 opts.searchDirectoriesFromDashI.emplace_back(currentArg->getValue());
897
898 // Prepend the ordered list of -intrinsic-modules-path
899 // to the default location to search.
900 for (const auto *currentArg :
901 args.filtered(clang::driver::options::OPT_fintrinsic_modules_path))
902 opts.searchDirectoriesFromIntrModPath.emplace_back(currentArg->getValue());
903
904 // -cpp/-nocpp
905 if (const auto *currentArg = args.getLastArg(
906 clang::driver::options::OPT_cpp, clang::driver::options::OPT_nocpp))
907 opts.macrosFlag =
908 (currentArg->getOption().matches(clang::driver::options::OPT_cpp))
909 ? PPMacrosFlag::Include
910 : PPMacrosFlag::Exclude;
911 // Enable -cpp based on -x unless explicitly disabled with -nocpp
912 if (opts.macrosFlag != PPMacrosFlag::Exclude)
913 if (const auto *dashX = args.getLastArg(clang::driver::options::OPT_x))
914 opts.macrosFlag = llvm::StringSwitch<PPMacrosFlag>(dashX->getValue())
915 .Case("f95-cpp-input", PPMacrosFlag::Include)
916 .Default(opts.macrosFlag);
917
918 opts.noReformat = args.hasArg(clang::driver::options::OPT_fno_reformat);
919 opts.preprocessIncludeLines =
920 args.hasArg(clang::driver::options::OPT_fpreprocess_include_lines);
921 opts.noLineDirectives = args.hasArg(clang::driver::options::OPT_P);
922 opts.showMacros = args.hasArg(clang::driver::options::OPT_dM);
923}
924
925/// Parses all semantic related arguments and populates the variables
926/// options accordingly. Returns false if new errors are generated.
927static bool parseSemaArgs(CompilerInvocation &res, llvm::opt::ArgList &args,
928 clang::DiagnosticsEngine &diags) {
929 unsigned numErrorsBefore = diags.getNumErrors();
930
931 // -J/module-dir option
932 std::vector<std::string> moduleDirList =
933 args.getAllArgValues(clang::driver::options::OPT_module_dir);
934 // User can only specify one -J/-module-dir directory, but may repeat
935 // -J/-module-dir as long as the directory is the same each time.
936 // https://gcc.gnu.org/onlinedocs/gfortran/Directory-Options.html
937 std::sort(first: moduleDirList.begin(), last: moduleDirList.end());
938 moduleDirList.erase(first: std::unique(first: moduleDirList.begin(), last: moduleDirList.end()),
939 last: moduleDirList.end());
940 if (moduleDirList.size() > 1) {
941 const unsigned diagID =
942 diags.getCustomDiagID(L: clang::DiagnosticsEngine::Error,
943 FormatString: "Only one '-module-dir/-J' directory allowed. "
944 "'-module-dir/-J' may be given multiple times "
945 "but the directory must be the same each time.");
946 diags.Report(DiagID: diagID);
947 }
948 if (moduleDirList.size() == 1)
949 res.setModuleDir(moduleDirList[0]);
950
951 // -fdebug-module-writer option
952 if (args.hasArg(clang::driver::options::OPT_fdebug_module_writer)) {
953 res.setDebugModuleDir(true);
954 }
955
956 // -fhermetic-module-files option
957 if (args.hasArg(clang::driver::options::OPT_fhermetic_module_files)) {
958 res.setHermeticModuleFileOutput(true);
959 }
960
961 // -module-suffix
962 if (const auto *moduleSuffix =
963 args.getLastArg(clang::driver::options::OPT_module_suffix)) {
964 res.setModuleFileSuffix(moduleSuffix->getValue());
965 }
966
967 // -f{no-}analyzed-objects-for-unparse
968 res.setUseAnalyzedObjectsForUnparse(args.hasFlag(
969 clang::driver::options::OPT_fanalyzed_objects_for_unparse,
970 clang::driver::options::OPT_fno_analyzed_objects_for_unparse, true));
971
972 return diags.getNumErrors() == numErrorsBefore;
973}
974
975/// Parses all diagnostics related arguments and populates the variables
976/// options accordingly. Returns false if new errors are generated.
977/// FC1 driver entry point for parsing diagnostic arguments.
978static bool parseDiagArgs(CompilerInvocation &res, llvm::opt::ArgList &args,
979 clang::DiagnosticsEngine &diags) {
980 unsigned numErrorsBefore = diags.getNumErrors();
981
982 auto &features{res.getFrontendOpts().features};
983 // The order of these flags (-pedantic -W<feature> -w) is important and is
984 // chosen to match clang's behavior.
985
986 // -pedantic
987 if (args.hasArg(clang::driver::options::OPT_pedantic)) {
988 features.WarnOnAllNonstandard();
989 features.WarnOnAllUsage();
990 res.setEnableConformanceChecks();
991 res.setEnableUsageChecks();
992 }
993
994 // -Werror option
995 // TODO: Currently throws a Diagnostic for anything other than -W<error>,
996 // this has to change when other -W<opt>'s are supported.
997 if (args.hasArg(clang::driver::options::OPT_W_Joined)) {
998 const auto &wArgs =
999 args.getAllArgValues(clang::driver::options::OPT_W_Joined);
1000 for (const auto &wArg : wArgs) {
1001 if (wArg == "error") {
1002 res.setWarnAsErr(true);
1003 // -W(no-)<feature>
1004 } else if (!features.ApplyCliOption(wArg)) {
1005 const unsigned diagID = diags.getCustomDiagID(
1006 clang::DiagnosticsEngine::Error, "Unknown diagnostic option: -W%0");
1007 diags.Report(diagID) << wArg;
1008 }
1009 }
1010 }
1011
1012 // -w
1013 if (args.hasArg(clang::driver::options::OPT_w)) {
1014 features.DisableAllWarnings();
1015 res.setDisableWarnings();
1016 }
1017
1018 // Default to off for `flang -fc1`.
1019 bool showColors{parseShowColorsArgs(args, defaultColor: false)};
1020 diags.getDiagnosticOptions().ShowColors = showColors;
1021 res.getDiagnosticOpts().ShowColors = showColors;
1022 res.getFrontendOpts().showColors = showColors;
1023 return diags.getNumErrors() == numErrorsBefore;
1024}
1025
1026/// Parses all Dialect related arguments and populates the variables
1027/// options accordingly. Returns false if new errors are generated.
1028static bool parseDialectArgs(CompilerInvocation &res, llvm::opt::ArgList &args,
1029 clang::DiagnosticsEngine &diags) {
1030 unsigned numErrorsBefore = diags.getNumErrors();
1031
1032 // -fd-lines-as-code
1033 if (args.hasArg(clang::driver::options::OPT_fd_lines_as_code)) {
1034 if (res.getFrontendOpts().fortranForm == FortranForm::FreeForm) {
1035 const unsigned fdLinesAsWarning = diags.getCustomDiagID(
1036 L: clang::DiagnosticsEngine::Warning,
1037 FormatString: "‘-fd-lines-as-code’ has no effect in free form.");
1038 diags.Report(DiagID: fdLinesAsWarning);
1039 } else {
1040 res.getFrontendOpts().features.Enable(
1041 Fortran::common::LanguageFeature::OldDebugLines, true);
1042 }
1043 }
1044
1045 // -fd-lines-as-comments
1046 if (args.hasArg(clang::driver::options::OPT_fd_lines_as_comments)) {
1047 if (res.getFrontendOpts().fortranForm == FortranForm::FreeForm) {
1048 const unsigned fdLinesAsWarning = diags.getCustomDiagID(
1049 L: clang::DiagnosticsEngine::Warning,
1050 FormatString: "‘-fd-lines-as-comments’ has no effect in free form.");
1051 diags.Report(DiagID: fdLinesAsWarning);
1052 } else {
1053 res.getFrontendOpts().features.Enable(
1054 Fortran::common::LanguageFeature::OldDebugLines, false);
1055 }
1056 }
1057
1058 // -fdefault* family
1059 if (args.hasArg(clang::driver::options::OPT_fdefault_real_8)) {
1060 res.getDefaultKinds().set_defaultRealKind(8);
1061 res.getDefaultKinds().set_doublePrecisionKind(16);
1062 }
1063 if (args.hasArg(clang::driver::options::OPT_fdefault_integer_8)) {
1064 res.getDefaultKinds().set_defaultIntegerKind(8);
1065 res.getDefaultKinds().set_subscriptIntegerKind(8);
1066 res.getDefaultKinds().set_sizeIntegerKind(8);
1067 res.getDefaultKinds().set_defaultLogicalKind(8);
1068 }
1069 if (args.hasArg(clang::driver::options::OPT_fdefault_double_8)) {
1070 if (!args.hasArg(clang::driver::options::OPT_fdefault_real_8)) {
1071 // -fdefault-double-8 has to be used with -fdefault-real-8
1072 // to be compatible with gfortran
1073 const unsigned diagID = diags.getCustomDiagID(
1074 L: clang::DiagnosticsEngine::Error,
1075 FormatString: "Use of `-fdefault-double-8` requires `-fdefault-real-8`");
1076 diags.Report(DiagID: diagID);
1077 }
1078 // https://gcc.gnu.org/onlinedocs/gfortran/Fortran-Dialect-Options.html
1079 res.getDefaultKinds().set_doublePrecisionKind(8);
1080 }
1081 if (args.hasArg(clang::driver::options::OPT_flarge_sizes))
1082 res.getDefaultKinds().set_sizeIntegerKind(8);
1083
1084 // -x cuda
1085 auto language = args.getLastArgValue(clang::driver::options::OPT_x);
1086 if (language == "cuda") {
1087 res.getFrontendOpts().features.Enable(
1088 Fortran::common::LanguageFeature::CUDA);
1089 }
1090
1091 // -fopenacc
1092 if (args.hasArg(clang::driver::options::OPT_fopenacc)) {
1093 res.getFrontendOpts().features.Enable(
1094 Fortran::common::LanguageFeature::OpenACC);
1095 }
1096
1097 // -std=f2018
1098 // TODO: Set proper options when more fortran standards
1099 // are supported.
1100 if (args.hasArg(clang::driver::options::OPT_std_EQ)) {
1101 auto standard = args.getLastArgValue(clang::driver::options::OPT_std_EQ);
1102 // We only allow f2018 as the given standard
1103 if (standard == "f2018") {
1104 res.setEnableConformanceChecks();
1105 res.getFrontendOpts().features.WarnOnAllNonstandard();
1106 } else {
1107 const unsigned diagID =
1108 diags.getCustomDiagID(L: clang::DiagnosticsEngine::Error,
1109 FormatString: "Only -std=f2018 is allowed currently.");
1110 diags.Report(DiagID: diagID);
1111 }
1112 }
1113 return diags.getNumErrors() == numErrorsBefore;
1114}
1115
1116/// Parses all OpenMP related arguments if the -fopenmp option is present,
1117/// populating the \c res object accordingly. Returns false if new errors are
1118/// generated.
1119static bool parseOpenMPArgs(CompilerInvocation &res, llvm::opt::ArgList &args,
1120 clang::DiagnosticsEngine &diags) {
1121 llvm::opt::Arg *arg = args.getLastArg(clang::driver::options::OPT_fopenmp,
1122 clang::driver::options::OPT_fno_openmp);
1123 if (!arg || arg->getOption().matches(clang::driver::options::OPT_fno_openmp))
1124 return true;
1125
1126 unsigned numErrorsBefore = diags.getNumErrors();
1127 llvm::Triple t(res.getTargetOpts().triple);
1128
1129 // By default OpenMP is set to 3.1 version
1130 res.getLangOpts().OpenMPVersion = 31;
1131 res.getFrontendOpts().features.Enable(
1132 Fortran::common::LanguageFeature::OpenMP);
1133 if (int Version = getLastArgIntValue(
1134 args, clang::driver::options::OPT_fopenmp_version_EQ,
1135 res.getLangOpts().OpenMPVersion, diags)) {
1136 res.getLangOpts().OpenMPVersion = Version;
1137 }
1138 if (args.hasArg(clang::driver::options::OPT_fopenmp_force_usm)) {
1139 res.getLangOpts().OpenMPForceUSM = 1;
1140 }
1141 if (args.hasArg(clang::driver::options::OPT_fopenmp_is_target_device)) {
1142 res.getLangOpts().OpenMPIsTargetDevice = 1;
1143
1144 // Get OpenMP host file path if any and report if a non existent file is
1145 // found
1146 if (auto *arg = args.getLastArg(
1147 clang::driver::options::OPT_fopenmp_host_ir_file_path)) {
1148 res.getLangOpts().OMPHostIRFile = arg->getValue();
1149 if (!llvm::sys::fs::exists(res.getLangOpts().OMPHostIRFile))
1150 diags.Report(clang::diag::err_drv_omp_host_ir_file_not_found)
1151 << res.getLangOpts().OMPHostIRFile;
1152 }
1153
1154 if (args.hasFlag(
1155 clang::driver::options::OPT_fopenmp_assume_teams_oversubscription,
1156 clang::driver::options::
1157 OPT_fno_openmp_assume_teams_oversubscription,
1158 /*Default=*/false))
1159 res.getLangOpts().OpenMPTeamSubscription = true;
1160
1161 if (args.hasArg(clang::driver::options::OPT_fopenmp_assume_no_thread_state))
1162 res.getLangOpts().OpenMPNoThreadState = 1;
1163
1164 if (args.hasArg(
1165 clang::driver::options::OPT_fopenmp_assume_no_nested_parallelism))
1166 res.getLangOpts().OpenMPNoNestedParallelism = 1;
1167
1168 if (args.hasFlag(
1169 clang::driver::options::OPT_fopenmp_assume_threads_oversubscription,
1170 clang::driver::options::
1171 OPT_fno_openmp_assume_threads_oversubscription,
1172 /*Default=*/false))
1173 res.getLangOpts().OpenMPThreadSubscription = true;
1174
1175 if ((args.hasArg(clang::driver::options::OPT_fopenmp_target_debug) ||
1176 args.hasArg(clang::driver::options::OPT_fopenmp_target_debug_EQ))) {
1177 res.getLangOpts().OpenMPTargetDebug = getLastArgIntValue(
1178 args, clang::driver::options::OPT_fopenmp_target_debug_EQ,
1179 res.getLangOpts().OpenMPTargetDebug, diags);
1180
1181 if (!res.getLangOpts().OpenMPTargetDebug &&
1182 args.hasArg(clang::driver::options::OPT_fopenmp_target_debug))
1183 res.getLangOpts().OpenMPTargetDebug = 1;
1184 }
1185 if (args.hasArg(clang::driver::options::OPT_no_offloadlib))
1186 res.getLangOpts().NoGPULib = 1;
1187 }
1188 if (llvm::Triple(res.getTargetOpts().triple).isGPU()) {
1189 if (!res.getLangOpts().OpenMPIsTargetDevice) {
1190 const unsigned diagID = diags.getCustomDiagID(
1191 L: clang::DiagnosticsEngine::Error,
1192 FormatString: "OpenMP GPU is only prepared to deal with device code.");
1193 diags.Report(DiagID: diagID);
1194 }
1195 res.getLangOpts().OpenMPIsGPU = 1;
1196 } else {
1197 res.getLangOpts().OpenMPIsGPU = 0;
1198 }
1199
1200 // Get the OpenMP target triples if any.
1201 if (auto *arg =
1202 args.getLastArg(clang::driver::options::OPT_fopenmp_targets_EQ)) {
1203 enum ArchPtrSize { Arch16Bit, Arch32Bit, Arch64Bit };
1204 auto getArchPtrSize = [](const llvm::Triple &triple) {
1205 if (triple.isArch16Bit())
1206 return Arch16Bit;
1207 if (triple.isArch32Bit())
1208 return Arch32Bit;
1209 assert(triple.isArch64Bit() && "Expected 64-bit architecture");
1210 return Arch64Bit;
1211 };
1212
1213 for (unsigned i = 0; i < arg->getNumValues(); ++i) {
1214 llvm::Triple tt(arg->getValue(i));
1215
1216 if (tt.getArch() == llvm::Triple::UnknownArch ||
1217 !(tt.getArch() == llvm::Triple::aarch64 || tt.isPPC() ||
1218 tt.getArch() == llvm::Triple::systemz ||
1219 tt.getArch() == llvm::Triple::x86 ||
1220 tt.getArch() == llvm::Triple::x86_64 || tt.isGPU()))
1221 diags.Report(clang::diag::err_drv_invalid_omp_target)
1222 << arg->getValue(i);
1223 else if (getArchPtrSize(t) != getArchPtrSize(tt))
1224 diags.Report(clang::diag::err_drv_incompatible_omp_arch)
1225 << arg->getValue(i) << t.str();
1226 else
1227 res.getLangOpts().OMPTargetTriples.push_back(tt);
1228 }
1229 }
1230 return diags.getNumErrors() == numErrorsBefore;
1231}
1232
1233/// Parses signed integer overflow options and populates the
1234/// CompilerInvocation accordingly.
1235/// Returns false if new errors are generated.
1236///
1237/// \param [out] invoc Stores the processed arguments
1238/// \param [in] args The compiler invocation arguments to parse
1239/// \param [out] diags DiagnosticsEngine to report erros with
1240static bool parseIntegerOverflowArgs(CompilerInvocation &invoc,
1241 llvm::opt::ArgList &args,
1242 clang::DiagnosticsEngine &diags) {
1243 Fortran::common::LangOptions &opts = invoc.getLangOpts();
1244
1245 if (args.getLastArg(clang::driver::options::OPT_fwrapv))
1246 opts.setSignedOverflowBehavior(Fortran::common::LangOptions::SOB_Defined);
1247
1248 return true;
1249}
1250
1251/// Parses all floating point related arguments and populates the
1252/// CompilerInvocation accordingly.
1253/// Returns false if new errors are generated.
1254///
1255/// \param [out] invoc Stores the processed arguments
1256/// \param [in] args The compiler invocation arguments to parse
1257/// \param [out] diags DiagnosticsEngine to report erros with
1258static bool parseFloatingPointArgs(CompilerInvocation &invoc,
1259 llvm::opt::ArgList &args,
1260 clang::DiagnosticsEngine &diags) {
1261 Fortran::common::LangOptions &opts = invoc.getLangOpts();
1262
1263 if (const llvm::opt::Arg *a =
1264 args.getLastArg(clang::driver::options::OPT_ffp_contract)) {
1265 const llvm::StringRef val = a->getValue();
1266 enum Fortran::common::LangOptions::FPModeKind fpContractMode;
1267
1268 if (val == "off")
1269 fpContractMode = Fortran::common::LangOptions::FPM_Off;
1270 else if (val == "fast")
1271 fpContractMode = Fortran::common::LangOptions::FPM_Fast;
1272 else {
1273 diags.Report(clang::diag::err_drv_unsupported_option_argument)
1274 << a->getSpelling() << val;
1275 return false;
1276 }
1277
1278 opts.setFPContractMode(fpContractMode);
1279 }
1280
1281 if (args.getLastArg(clang::driver::options::OPT_menable_no_infs)) {
1282 opts.NoHonorInfs = true;
1283 }
1284
1285 if (args.getLastArg(clang::driver::options::OPT_menable_no_nans)) {
1286 opts.NoHonorNaNs = true;
1287 }
1288
1289 if (args.getLastArg(clang::driver::options::OPT_fapprox_func)) {
1290 opts.ApproxFunc = true;
1291 }
1292
1293 if (args.getLastArg(clang::driver::options::OPT_fno_signed_zeros)) {
1294 opts.NoSignedZeros = true;
1295 }
1296
1297 if (args.getLastArg(clang::driver::options::OPT_mreassociate)) {
1298 opts.AssociativeMath = true;
1299 }
1300
1301 if (args.getLastArg(clang::driver::options::OPT_freciprocal_math)) {
1302 opts.ReciprocalMath = true;
1303 }
1304
1305 if (args.getLastArg(clang::driver::options::OPT_ffast_math)) {
1306 opts.NoHonorInfs = true;
1307 opts.NoHonorNaNs = true;
1308 opts.AssociativeMath = true;
1309 opts.ReciprocalMath = true;
1310 opts.ApproxFunc = true;
1311 opts.NoSignedZeros = true;
1312 opts.setFPContractMode(Fortran::common::LangOptions::FPM_Fast);
1313 }
1314
1315 return true;
1316}
1317
1318/// Parses vscale range options and populates the CompilerInvocation
1319/// accordingly.
1320/// Returns false if new errors are generated.
1321///
1322/// \param [out] invoc Stores the processed arguments
1323/// \param [in] args The compiler invocation arguments to parse
1324/// \param [out] diags DiagnosticsEngine to report erros with
1325static bool parseVScaleArgs(CompilerInvocation &invoc, llvm::opt::ArgList &args,
1326 clang::DiagnosticsEngine &diags) {
1327 const auto *vscaleMin =
1328 args.getLastArg(clang::driver::options::OPT_mvscale_min_EQ);
1329 const auto *vscaleMax =
1330 args.getLastArg(clang::driver::options::OPT_mvscale_max_EQ);
1331
1332 if (!vscaleMin && !vscaleMax)
1333 return true;
1334
1335 llvm::Triple triple = llvm::Triple(invoc.getTargetOpts().triple);
1336 if (!triple.isAArch64() && !triple.isRISCV()) {
1337 const unsigned diagID =
1338 diags.getCustomDiagID(L: clang::DiagnosticsEngine::Error,
1339 FormatString: "`-mvscale-max` and `-mvscale-min` are not "
1340 "supported for this architecture: %0");
1341 diags.Report(DiagID: diagID) << triple.getArchName();
1342 return false;
1343 }
1344
1345 Fortran::common::LangOptions &opts = invoc.getLangOpts();
1346 if (vscaleMin) {
1347 llvm::StringRef argValue = llvm::StringRef(vscaleMin->getValue());
1348 unsigned vscaleMinVal;
1349 if (argValue.getAsInteger(/*Radix=*/10, Result&: vscaleMinVal)) {
1350 diags.Report(clang::diag::err_drv_unsupported_option_argument)
1351 << vscaleMax->getSpelling() << argValue;
1352 return false;
1353 }
1354 opts.VScaleMin = vscaleMinVal;
1355 }
1356
1357 if (vscaleMax) {
1358 llvm::StringRef argValue = llvm::StringRef(vscaleMax->getValue());
1359 unsigned vscaleMaxVal;
1360 if (argValue.getAsInteger(/*Radix=w*/ Radix: 10, Result&: vscaleMaxVal)) {
1361 diags.Report(clang::diag::err_drv_unsupported_option_argument)
1362 << vscaleMax->getSpelling() << argValue;
1363 return false;
1364 }
1365 opts.VScaleMax = vscaleMaxVal;
1366 }
1367 return true;
1368}
1369
1370static bool parseLinkerOptionsArgs(CompilerInvocation &invoc,
1371 llvm::opt::ArgList &args,
1372 clang::DiagnosticsEngine &diags) {
1373 llvm::Triple triple = llvm::Triple(invoc.getTargetOpts().triple);
1374
1375 // TODO: support --dependent-lib on other platforms when MLIR supports
1376 // !llvm.dependent.lib
1377 if (args.hasArg(clang::driver::options::OPT_dependent_lib) &&
1378 !triple.isOSWindows()) {
1379 const unsigned diagID =
1380 diags.getCustomDiagID(L: clang::DiagnosticsEngine::Error,
1381 FormatString: "--dependent-lib is only supported on Windows");
1382 diags.Report(DiagID: diagID);
1383 return false;
1384 }
1385
1386 invoc.getCodeGenOpts().DependentLibs =
1387 args.getAllArgValues(clang::driver::options::OPT_dependent_lib);
1388 return true;
1389}
1390
1391static bool parseLangOptionsArgs(CompilerInvocation &invoc,
1392 llvm::opt::ArgList &args,
1393 clang::DiagnosticsEngine &diags) {
1394 bool success = true;
1395
1396 success &= parseIntegerOverflowArgs(invoc, args, diags);
1397 success &= parseFloatingPointArgs(invoc, args, diags);
1398 success &= parseVScaleArgs(invoc, args, diags);
1399
1400 return success;
1401}
1402
1403bool CompilerInvocation::createFromArgs(
1404 CompilerInvocation &invoc, llvm::ArrayRef<const char *> commandLineArgs,
1405 clang::DiagnosticsEngine &diags, const char *argv0) {
1406
1407 bool success = true;
1408
1409 // Set the default triple for this CompilerInvocation. This might be
1410 // overridden by users with `-triple` (see the call to `ParseTargetArgs`
1411 // below).
1412 // NOTE: Like in Clang, it would be nice to use option marshalling
1413 // for this so that the entire logic for setting-up the triple is in one
1414 // place.
1415 invoc.getTargetOpts().triple =
1416 llvm::Triple::normalize(llvm::sys::getDefaultTargetTriple());
1417
1418 // Parse the arguments
1419 const llvm::opt::OptTable &opts = clang::driver::getDriverOptTable();
1420 llvm::opt::Visibility visibilityMask(clang::driver::options::FC1Option);
1421 unsigned missingArgIndex, missingArgCount;
1422 llvm::opt::InputArgList args = opts.ParseArgs(
1423 commandLineArgs, missingArgIndex, missingArgCount, visibilityMask);
1424
1425 // Check for missing argument error.
1426 if (missingArgCount) {
1427 diags.Report(clang::diag::err_drv_missing_argument)
1428 << args.getArgString(missingArgIndex) << missingArgCount;
1429 success = false;
1430 }
1431
1432 // Issue errors on unknown arguments
1433 for (const auto *a : args.filtered(clang::driver::options::OPT_UNKNOWN)) {
1434 auto argString = a->getAsString(args);
1435 std::string nearest;
1436 if (opts.findNearest(argString, nearest, visibilityMask) > 1)
1437 diags.Report(clang::diag::err_drv_unknown_argument) << argString;
1438 else
1439 diags.Report(clang::diag::err_drv_unknown_argument_with_suggestion)
1440 << argString << nearest;
1441 success = false;
1442 }
1443
1444 // -flang-experimental-hlfir
1445 if (args.hasArg(clang::driver::options::OPT_flang_experimental_hlfir) ||
1446 args.hasArg(clang::driver::options::OPT_emit_hlfir)) {
1447 invoc.loweringOpts.setLowerToHighLevelFIR(true);
1448 }
1449
1450 // -flang-deprecated-no-hlfir
1451 if (args.hasArg(clang::driver::options::OPT_flang_deprecated_no_hlfir) &&
1452 !args.hasArg(clang::driver::options::OPT_emit_hlfir)) {
1453 if (args.hasArg(clang::driver::options::OPT_flang_experimental_hlfir)) {
1454 const unsigned diagID = diags.getCustomDiagID(
1455 clang::DiagnosticsEngine::Error,
1456 "Options '-flang-experimental-hlfir' and "
1457 "'-flang-deprecated-no-hlfir' cannot be both specified");
1458 diags.Report(diagID);
1459 }
1460 invoc.loweringOpts.setLowerToHighLevelFIR(false);
1461 }
1462
1463 // -fno-ppc-native-vector-element-order
1464 if (args.hasArg(clang::driver::options::OPT_fno_ppc_native_vec_elem_order)) {
1465 invoc.loweringOpts.setNoPPCNativeVecElemOrder(true);
1466 }
1467
1468 // -f[no-]init-global-zero
1469 if (args.hasFlag(clang::driver::options::OPT_finit_global_zero,
1470 clang::driver::options::OPT_fno_init_global_zero,
1471 /*default=*/true))
1472 invoc.loweringOpts.setInitGlobalZero(true);
1473 else
1474 invoc.loweringOpts.setInitGlobalZero(false);
1475
1476 // Preserve all the remark options requested, i.e. -Rpass, -Rpass-missed or
1477 // -Rpass-analysis. This will be used later when processing and outputting the
1478 // remarks generated by LLVM in ExecuteCompilerInvocation.cpp.
1479 for (auto *a : args.filtered(clang::driver::options::OPT_R_Group)) {
1480 if (a->getOption().matches(clang::driver::options::OPT_R_value_Group))
1481 // This is -Rfoo=, where foo is the name of the diagnostic
1482 // group. Add only the remark option name to the diagnostics. e.g. for
1483 // -Rpass= we will add the string "pass".
1484 invoc.getDiagnosticOpts().Remarks.push_back(
1485 std::string(a->getOption().getName().drop_front(1).rtrim("=-")));
1486 else
1487 // If no regex was provided, add the provided value, e.g. for -Rpass add
1488 // the string "pass".
1489 invoc.getDiagnosticOpts().Remarks.push_back(a->getValue());
1490 }
1491
1492 // -frealloc-lhs is the default.
1493 if (!args.hasFlag(clang::driver::options::OPT_frealloc_lhs,
1494 clang::driver::options::OPT_fno_realloc_lhs, true))
1495 invoc.loweringOpts.setReallocateLHS(false);
1496
1497 invoc.loweringOpts.setRepackArrays(
1498 args.hasFlag(clang::driver::options::OPT_frepack_arrays,
1499 clang::driver::options::OPT_fno_repack_arrays,
1500 /*default=*/false));
1501 invoc.loweringOpts.setStackRepackArrays(
1502 args.hasFlag(clang::driver::options::OPT_fstack_repack_arrays,
1503 clang::driver::options::OPT_fno_stack_repack_arrays,
1504 /*default=*/false));
1505 if (auto *arg = args.getLastArg(
1506 clang::driver::options::OPT_frepack_arrays_contiguity_EQ))
1507 invoc.loweringOpts.setRepackArraysWhole(arg->getValue() ==
1508 llvm::StringRef{"whole"});
1509
1510 success &= parseFrontendArgs(invoc.getFrontendOpts(), args, diags);
1511 parseTargetArgs(invoc.getTargetOpts(), args);
1512 parsePreprocessorArgs(invoc.getPreprocessorOpts(), args);
1513 parseCodeGenArgs(invoc.getCodeGenOpts(), args, diags);
1514 success &= parseDebugArgs(invoc.getCodeGenOpts(), args, diags);
1515 success &= parseVectorLibArg(invoc.getCodeGenOpts(), args, diags);
1516 success &= parseSemaArgs(invoc, args, diags);
1517 success &= parseDialectArgs(invoc, args, diags);
1518 success &= parseOpenMPArgs(invoc, args, diags);
1519 success &= parseDiagArgs(invoc, args, diags);
1520
1521 // Collect LLVM (-mllvm) and MLIR (-mmlir) options.
1522 // NOTE: Try to avoid adding any options directly to `llvmArgs` or
1523 // `mlirArgs`. Instead, you can use
1524 // * `-mllvm <your-llvm-option>`, or
1525 // * `-mmlir <your-mlir-option>`.
1526 invoc.frontendOpts.llvmArgs =
1527 args.getAllArgValues(clang::driver::options::OPT_mllvm);
1528 invoc.frontendOpts.mlirArgs =
1529 args.getAllArgValues(clang::driver::options::OPT_mmlir);
1530
1531 success &= parseLangOptionsArgs(invoc, args, diags);
1532
1533 success &= parseLinkerOptionsArgs(invoc, args, diags);
1534
1535 // Set the string to be used as the return value of the COMPILER_OPTIONS
1536 // intrinsic of iso_fortran_env. This is either passed in from the parent
1537 // compiler driver invocation with an environment variable, or failing that
1538 // set to the command line arguments of the frontend driver invocation.
1539 invoc.allCompilerInvocOpts = std::string();
1540 llvm::raw_string_ostream os(invoc.allCompilerInvocOpts);
1541 char *compilerOptsEnv = std::getenv("FLANG_COMPILER_OPTIONS_STRING");
1542 if (compilerOptsEnv != nullptr) {
1543 os << compilerOptsEnv;
1544 } else {
1545 os << argv0 << ' ';
1546 for (auto it = commandLineArgs.begin(), e = commandLineArgs.end(); it != e;
1547 ++it) {
1548 os << ' ' << *it;
1549 }
1550 }
1551
1552 // Process the timing-related options.
1553 if (args.hasArg(clang::driver::options::OPT_ftime_report))
1554 invoc.enableTimers = true;
1555
1556 invoc.setArgv0(argv0);
1557
1558 return success;
1559}
1560
1561void CompilerInvocation::collectMacroDefinitions() {
1562 auto &ppOpts = this->getPreprocessorOpts();
1563
1564 for (unsigned i = 0, n = ppOpts.macros.size(); i != n; ++i) {
1565 llvm::StringRef macro = ppOpts.macros[i].first;
1566 bool isUndef = ppOpts.macros[i].second;
1567
1568 std::pair<llvm::StringRef, llvm::StringRef> macroPair = macro.split('=');
1569 llvm::StringRef macroName = macroPair.first;
1570 llvm::StringRef macroBody = macroPair.second;
1571
1572 // For an #undef'd macro, we only care about the name.
1573 if (isUndef) {
1574 parserOpts.predefinitions.emplace_back(macroName.str(),
1575 std::optional<std::string>{});
1576 continue;
1577 }
1578
1579 // For a #define'd macro, figure out the actual definition.
1580 if (macroName.size() == macro.size())
1581 macroBody = "1";
1582 else {
1583 // Note: GCC drops anything following an end-of-line character.
1584 llvm::StringRef::size_type end = macroBody.find_first_of("\n\r");
1585 macroBody = macroBody.substr(0, end);
1586 }
1587 parserOpts.predefinitions.emplace_back(
1588 macroName, std::optional<std::string>(macroBody.str()));
1589 }
1590}
1591
1592void CompilerInvocation::setDefaultFortranOpts() {
1593 auto &fortranOptions = getFortranOpts();
1594
1595 std::vector<std::string> searchDirectories{"."s};
1596 fortranOptions.searchDirectories = searchDirectories;
1597
1598 // Add the location of omp_lib.h to the search directories. Currently this is
1599 // identical to the modules' directory.
1600 fortranOptions.searchDirectories.emplace_back(
1601 getOpenMPHeadersDir(getArgv0()));
1602
1603 fortranOptions.isFixedForm = false;
1604}
1605
1606// TODO: When expanding this method, consider creating a dedicated API for
1607// this. Also at some point we will need to differentiate between different
1608// targets and add dedicated predefines for each.
1609void CompilerInvocation::setDefaultPredefinitions() {
1610 auto &fortranOptions = getFortranOpts();
1611 const auto &frontendOptions = getFrontendOpts();
1612 // Populate the macro list with version numbers and other predefinitions.
1613 fortranOptions.predefinitions.emplace_back("__flang__", "1");
1614 fortranOptions.predefinitions.emplace_back("__flang_major__",
1615 FLANG_VERSION_MAJOR_STRING);
1616 fortranOptions.predefinitions.emplace_back("__flang_minor__",
1617 FLANG_VERSION_MINOR_STRING);
1618 fortranOptions.predefinitions.emplace_back("__flang_patchlevel__",
1619 FLANG_VERSION_PATCHLEVEL_STRING);
1620
1621 // Add predefinitions based on extensions enabled
1622 if (frontendOptions.features.IsEnabled(
1623 Fortran::common::LanguageFeature::OpenACC)) {
1624 fortranOptions.predefinitions.emplace_back("_OPENACC", "202211");
1625 }
1626 if (frontendOptions.features.IsEnabled(
1627 Fortran::common::LanguageFeature::OpenMP)) {
1628 Fortran::common::setOpenMPMacro(getLangOpts().OpenMPVersion,
1629 fortranOptions.predefinitions);
1630 }
1631
1632 llvm::Triple targetTriple{llvm::Triple(this->targetOpts.triple)};
1633 if (targetTriple.isOSLinux()) {
1634 fortranOptions.predefinitions.emplace_back("__linux__", "1");
1635 } else if (targetTriple.isOSAIX()) {
1636 fortranOptions.predefinitions.emplace_back("_AIX", "1");
1637 }
1638
1639 switch (targetTriple.getArch()) {
1640 default:
1641 break;
1642 case llvm::Triple::ArchType::x86_64:
1643 fortranOptions.predefinitions.emplace_back("__x86_64__", "1");
1644 fortranOptions.predefinitions.emplace_back("__x86_64", "1");
1645 break;
1646 case llvm::Triple::ArchType::ppc:
1647 case llvm::Triple::ArchType::ppc64:
1648 case llvm::Triple::ArchType::ppcle:
1649 case llvm::Triple::ArchType::ppc64le:
1650 // '__powerpc__' is a generic macro for any PowerPC.
1651 fortranOptions.predefinitions.emplace_back("__powerpc__", "1");
1652 if (targetTriple.isOSAIX() && targetTriple.isArch64Bit()) {
1653 fortranOptions.predefinitions.emplace_back("__64BIT__", "1");
1654 }
1655 break;
1656 case llvm::Triple::ArchType::aarch64:
1657 fortranOptions.predefinitions.emplace_back("__aarch64__", "1");
1658 fortranOptions.predefinitions.emplace_back("__aarch64", "1");
1659 break;
1660 }
1661}
1662
1663void CompilerInvocation::setFortranOpts() {
1664 auto &fortranOptions = getFortranOpts();
1665 const auto &frontendOptions = getFrontendOpts();
1666 const auto &preprocessorOptions = getPreprocessorOpts();
1667 auto &moduleDirJ = getModuleDir();
1668
1669 if (frontendOptions.fortranForm != FortranForm::Unknown) {
1670 fortranOptions.isFixedForm =
1671 frontendOptions.fortranForm == FortranForm::FixedForm;
1672 }
1673 fortranOptions.fixedFormColumns = frontendOptions.fixedFormColumns;
1674
1675 // -E
1676 fortranOptions.prescanAndReformat =
1677 frontendOptions.programAction == PrintPreprocessedInput;
1678
1679 fortranOptions.features = frontendOptions.features;
1680 fortranOptions.encoding = frontendOptions.encoding;
1681
1682 // Adding search directories specified by -I
1683 fortranOptions.searchDirectories.insert(
1684 fortranOptions.searchDirectories.end(),
1685 preprocessorOptions.searchDirectoriesFromDashI.begin(),
1686 preprocessorOptions.searchDirectoriesFromDashI.end());
1687
1688 // Add the ordered list of -intrinsic-modules-path
1689 fortranOptions.searchDirectories.insert(
1690 fortranOptions.searchDirectories.end(),
1691 preprocessorOptions.searchDirectoriesFromIntrModPath.begin(),
1692 preprocessorOptions.searchDirectoriesFromIntrModPath.end());
1693
1694 // Add the default intrinsic module directory
1695 fortranOptions.intrinsicModuleDirectories.emplace_back(
1696 getIntrinsicDir(getArgv0()));
1697
1698 // Add the directory supplied through -J/-module-dir to the list of search
1699 // directories
1700 if (moduleDirJ != ".")
1701 fortranOptions.searchDirectories.emplace_back(moduleDirJ);
1702
1703 if (frontendOptions.instrumentedParse)
1704 fortranOptions.instrumentedParse = true;
1705
1706 if (frontendOptions.showColors)
1707 fortranOptions.showColors = true;
1708
1709 if (frontendOptions.needProvenanceRangeToCharBlockMappings)
1710 fortranOptions.needProvenanceRangeToCharBlockMappings = true;
1711
1712 fortranOptions.features = frontendOptions.features;
1713}
1714
1715std::unique_ptr<Fortran::semantics::SemanticsContext>
1716CompilerInvocation::getSemanticsCtx(
1717 Fortran::parser::AllCookedSources &allCookedSources,
1718 const llvm::TargetMachine &targetMachine) {
1719 auto &fortranOptions = getFortranOpts();
1720
1721 auto semanticsContext = std::make_unique<semantics::SemanticsContext>(
1722 getDefaultKinds(), fortranOptions.features, getLangOpts(),
1723 allCookedSources);
1724
1725 semanticsContext->set_moduleDirectory(getModuleDir())
1726 .set_searchDirectories(fortranOptions.searchDirectories)
1727 .set_intrinsicModuleDirectories(fortranOptions.intrinsicModuleDirectories)
1728 .set_warningsAreErrors(getWarnAsErr())
1729 .set_moduleFileSuffix(getModuleFileSuffix())
1730 .set_underscoring(getCodeGenOpts().Underscoring);
1731
1732 std::string compilerVersion = Fortran::common::getFlangFullVersion();
1733 Fortran::tools::setUpTargetCharacteristics(
1734 semanticsContext->targetCharacteristics(), targetMachine, getTargetOpts(),
1735 compilerVersion, allCompilerInvocOpts);
1736 return semanticsContext;
1737}
1738
1739/// Set \p loweringOptions controlling lowering behavior based
1740/// on the \p optimizationLevel.
1741void CompilerInvocation::setLoweringOptions() {
1742 const CodeGenOptions &codegenOpts = getCodeGenOpts();
1743
1744 // Lower TRANSPOSE as a runtime call under -O0.
1745 loweringOpts.setOptimizeTranspose(codegenOpts.OptimizationLevel > 0);
1746 loweringOpts.setUnderscoring(codegenOpts.Underscoring);
1747
1748 const Fortran::common::LangOptions &langOptions = getLangOpts();
1749 loweringOpts.setIntegerWrapAround(langOptions.getSignedOverflowBehavior() ==
1750 Fortran::common::LangOptions::SOB_Defined);
1751 Fortran::common::MathOptionsBase &mathOpts = loweringOpts.getMathOptions();
1752 // TODO: when LangOptions are finalized, we can represent
1753 // the math related options using Fortran::commmon::MathOptionsBase,
1754 // so that we can just copy it into LoweringOptions.
1755 mathOpts
1756 .setFPContractEnabled(langOptions.getFPContractMode() ==
1757 Fortran::common::LangOptions::FPM_Fast)
1758 .setNoHonorInfs(langOptions.NoHonorInfs)
1759 .setNoHonorNaNs(langOptions.NoHonorNaNs)
1760 .setApproxFunc(langOptions.ApproxFunc)
1761 .setNoSignedZeros(langOptions.NoSignedZeros)
1762 .setAssociativeMath(langOptions.AssociativeMath)
1763 .setReciprocalMath(langOptions.ReciprocalMath);
1764}
1765

Provided by KDAB

Privacy Policy
Update your C++ knowledge – Modern C++11/14/17 Training
Find out more

source code of flang/lib/Frontend/CompilerInvocation.cpp