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

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