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

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