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