1 //===-- tools/f18/f18.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 // Temporary Fortran front end driver main program for development scaffolding.
10 
11 #include "flang/Common/Fortran-features.h"
12 #include "flang/Common/default-kinds.h"
13 #include "flang/Evaluate/expression.h"
14 #include "flang/Lower/PFTBuilder.h"
15 #include "flang/Parser/characters.h"
16 #include "flang/Parser/dump-parse-tree.h"
17 #include "flang/Parser/message.h"
18 #include "flang/Parser/parse-tree-visitor.h"
19 #include "flang/Parser/parse-tree.h"
20 #include "flang/Parser/parsing.h"
21 #include "flang/Parser/provenance.h"
22 #include "flang/Parser/unparse.h"
23 #include "flang/Semantics/expression.h"
24 #include "flang/Semantics/runtime-type-info.h"
25 #include "flang/Semantics/semantics.h"
26 #include "flang/Semantics/unparse-with-symbols.h"
27 #include "flang/Version.inc"
28 #include "llvm/Support/Errno.h"
29 #include "llvm/Support/FileSystem.h"
30 #include "llvm/Support/Program.h"
31 #include "llvm/Support/Signals.h"
32 #include "llvm/Support/raw_ostream.h"
33 #include <cstdio>
34 #include <cstring>
35 #include <fstream>
36 #include <list>
37 #include <memory>
38 #include <optional>
39 #include <stdlib.h>
40 #include <string>
41 #include <vector>
42 
argList(int argc,char * const argv[])43 static std::list<std::string> argList(int argc, char *const argv[]) {
44   std::list<std::string> result;
45   for (int j = 0; j < argc; ++j) {
46     result.emplace_back(argv[j]);
47   }
48   return result;
49 }
50 
51 struct MeasurementVisitor {
PreMeasurementVisitor52   template <typename A> bool Pre(const A &) { return true; }
PostMeasurementVisitor53   template <typename A> void Post(const A &) {
54     ++objects;
55     bytes += sizeof(A);
56   }
57   size_t objects{0}, bytes{0};
58 };
59 
MeasureParseTree(const Fortran::parser::Program & program)60 void MeasureParseTree(const Fortran::parser::Program &program) {
61   MeasurementVisitor visitor;
62   Fortran::parser::Walk(program, visitor);
63   llvm::outs() << "Parse tree comprises " << visitor.objects
64                << " objects and occupies " << visitor.bytes
65                << " total bytes.\n";
66 }
67 
68 std::vector<std::string> filesToDelete;
69 
CleanUpAtExit()70 void CleanUpAtExit() {
71   for (const auto &path : filesToDelete) {
72     if (!path.empty()) {
73       llvm::sys::fs::remove(path);
74     }
75   }
76 }
77 
78 struct GetDefinitionArgs {
79   int line, startColumn, endColumn;
80 };
81 
82 struct DriverOptions {
DriverOptionsDriverOptions83   DriverOptions() {}
84   bool verbose{false}; // -v
85   bool compileOnly{false}; // -c
86   std::string outputPath; // -o path
87   std::vector<std::string> searchDirectories{"."s}; // -I dir
88   std::string moduleDirectory{"."s}; // -module dir
89   std::string moduleFileSuffix{".mod"}; // -moduleSuffix suff
90   bool forcedForm{false}; // -Mfixed or -Mfree appeared
91   bool warnOnNonstandardUsage{false}; // -Mstandard
92   bool warningsAreErrors{false}; // -Werror
93   bool byteswapio{false}; // -byteswapio
94   Fortran::parser::Encoding encoding{Fortran::parser::Encoding::UTF_8};
95   bool parseOnly{false};
96   bool dumpProvenance{false};
97   bool dumpCookedChars{false};
98   bool dumpUnparse{false};
99   bool dumpUnparseWithSymbols{false};
100   bool dumpParseTree{false};
101   bool dumpPreFirTree{false};
102   bool dumpSymbols{false};
103   bool debugNoSemantics{false};
104   bool debugModuleWriter{false};
105   bool measureTree{false};
106   bool unparseTypedExprsToF18_FC{false};
107   std::vector<std::string> F18_FCArgs;
108   const char *prefix{nullptr};
109   bool getDefinition{false};
110   GetDefinitionArgs getDefinitionArgs{0, 0, 0};
111   bool getSymbolsSources{false};
112 };
113 
Exec(std::vector<llvm::StringRef> & argv,bool verbose=false)114 void Exec(std::vector<llvm::StringRef> &argv, bool verbose = false) {
115   if (verbose) {
116     for (size_t j{0}; j < argv.size(); ++j) {
117       llvm::errs() << (j > 0 ? " " : "") << argv[j];
118     }
119     llvm::errs() << '\n';
120   }
121   std::string ErrMsg;
122   llvm::ErrorOr<std::string> Program = llvm::sys::findProgramByName(argv[0]);
123   if (!Program)
124     ErrMsg = Program.getError().message();
125   if (!Program ||
126       llvm::sys::ExecuteAndWait(
127           Program.get(), argv, llvm::None, {}, 0, 0, &ErrMsg)) {
128     llvm::errs() << "execvp(" << argv[0] << ") failed: " << ErrMsg << '\n';
129     exit(EXIT_FAILURE);
130   }
131 }
132 
RunOtherCompiler(DriverOptions & driver,char * source,char * relo)133 void RunOtherCompiler(DriverOptions &driver, char *source, char *relo) {
134   std::vector<llvm::StringRef> argv;
135   for (size_t j{0}; j < driver.F18_FCArgs.size(); ++j) {
136     argv.push_back(driver.F18_FCArgs[j]);
137   }
138   char dashC[3] = "-c", dashO[3] = "-o";
139   argv.push_back(dashC);
140   argv.push_back(dashO);
141   argv.push_back(relo);
142   argv.push_back(source);
143   Exec(argv, driver.verbose);
144 }
145 
RelocatableName(const DriverOptions & driver,std::string path)146 std::string RelocatableName(const DriverOptions &driver, std::string path) {
147   if (driver.compileOnly && !driver.outputPath.empty()) {
148     return driver.outputPath;
149   }
150   std::string base{path};
151   auto slash{base.rfind("/")};
152   if (slash != std::string::npos) {
153     base = base.substr(slash + 1);
154   }
155   std::string relo{base};
156   auto dot{base.rfind(".")};
157   if (dot != std::string::npos) {
158     relo = base.substr(0, dot);
159   }
160   relo += ".o";
161   return relo;
162 }
163 
164 int exitStatus{EXIT_SUCCESS};
165 
166 static Fortran::parser::AnalyzedObjectsAsFortran asFortran{
__anon1116175c0102() 167     [](llvm::raw_ostream &o, const Fortran::evaluate::GenericExprWrapper &x) {
168       if (x.v) {
169         x.v->AsFortran(o);
170       } else {
171         o << "(bad expression)";
172       }
173     },
174     [](llvm::raw_ostream &o,
__anon1116175c0202() 175         const Fortran::evaluate::GenericAssignmentWrapper &x) {
176       if (x.v) {
177         x.v->AsFortran(o);
178       } else {
179         o << "(bad assignment)";
180       }
181     },
__anon1116175c0302() 182     [](llvm::raw_ostream &o, const Fortran::evaluate::ProcedureRef &x) {
183       x.AsFortran(o << "CALL ");
184     },
185 };
186 
CompileFortran(std::string path,Fortran::parser::Options options,DriverOptions & driver,const Fortran::common::IntrinsicTypeDefaultKinds & defaultKinds)187 std::string CompileFortran(std::string path, Fortran::parser::Options options,
188     DriverOptions &driver,
189     const Fortran::common::IntrinsicTypeDefaultKinds &defaultKinds) {
190   Fortran::parser::AllSources allSources;
191   Fortran::parser::AllCookedSources allCookedSources{allSources};
192   allSources.set_encoding(driver.encoding);
193   Fortran::semantics::SemanticsContext semanticsContext{
194       defaultKinds, options.features, allCookedSources};
195   semanticsContext.set_moduleDirectory(driver.moduleDirectory)
196       .set_moduleFileSuffix(driver.moduleFileSuffix)
197       .set_searchDirectories(driver.searchDirectories)
198       .set_warnOnNonstandardUsage(driver.warnOnNonstandardUsage)
199       .set_warningsAreErrors(driver.warningsAreErrors);
200   if (!driver.forcedForm) {
201     auto dot{path.rfind(".")};
202     if (dot != std::string::npos) {
203       std::string suffix{path.substr(dot + 1)};
204       options.isFixedForm = suffix == "f" || suffix == "F" || suffix == "ff";
205     }
206   }
207   options.searchDirectories = driver.searchDirectories;
208   Fortran::parser::Parsing parsing{allCookedSources};
209   parsing.Prescan(path, options);
210   if (!parsing.messages().empty() &&
211       (driver.warningsAreErrors || parsing.messages().AnyFatalError())) {
212     llvm::errs() << driver.prefix << "Could not scan " << path << '\n';
213     parsing.messages().Emit(llvm::errs(), allCookedSources);
214     exitStatus = EXIT_FAILURE;
215     return {};
216   }
217   if (driver.dumpProvenance) {
218     parsing.DumpProvenance(llvm::outs());
219     return {};
220   }
221   if (driver.dumpCookedChars) {
222     parsing.messages().Emit(llvm::errs(), allCookedSources);
223     parsing.DumpCookedChars(llvm::outs());
224     return {};
225   }
226   parsing.Parse(llvm::outs());
227   if (options.instrumentedParse) {
228     parsing.DumpParsingLog(llvm::outs());
229     return {};
230   }
231   parsing.ClearLog();
232   parsing.messages().Emit(llvm::errs(), allCookedSources);
233   if (!parsing.consumedWholeFile()) {
234     parsing.EmitMessage(llvm::errs(), parsing.finalRestingPlace(),
235         "Parser FAIL (final position)");
236     exitStatus = EXIT_FAILURE;
237     return {};
238   }
239   if ((!parsing.messages().empty() &&
240           (driver.warningsAreErrors || parsing.messages().AnyFatalError())) ||
241       !parsing.parseTree()) {
242     llvm::errs() << driver.prefix << "Could not parse " << path << '\n';
243     exitStatus = EXIT_FAILURE;
244     return {};
245   }
246   auto &parseTree{*parsing.parseTree()};
247   if (driver.measureTree) {
248     MeasureParseTree(parseTree);
249   }
250   if (!driver.debugNoSemantics || driver.dumpSymbols ||
251       driver.dumpUnparseWithSymbols || driver.getDefinition ||
252       driver.getSymbolsSources) {
253     Fortran::semantics::Semantics semantics{semanticsContext, parseTree,
254         parsing.cooked().AsCharBlock(), driver.debugModuleWriter};
255     semantics.Perform();
256     semantics.EmitMessages(llvm::errs());
257     if (semantics.AnyFatalError()) {
258       if (driver.dumpSymbols) {
259         semantics.DumpSymbols(llvm::outs());
260       }
261       llvm::errs() << driver.prefix << "Semantic errors in " << path << '\n';
262       exitStatus = EXIT_FAILURE;
263       if (driver.dumpParseTree) {
264         Fortran::parser::DumpTree(llvm::outs(), parseTree, &asFortran);
265       }
266       return {};
267     }
268     auto tables{
269         Fortran::semantics::BuildRuntimeDerivedTypeTables(semanticsContext)};
270     if (!tables.schemata) {
271       llvm::errs() << driver.prefix
272                    << "could not find module file for __fortran_type_info\n";
273     }
274     if (driver.dumpSymbols) {
275       semantics.DumpSymbols(llvm::outs());
276     }
277     if (driver.dumpUnparseWithSymbols) {
278       Fortran::semantics::UnparseWithSymbols(
279           llvm::outs(), parseTree, driver.encoding);
280       return {};
281     }
282     if (driver.getSymbolsSources) {
283       semantics.DumpSymbolsSources(llvm::outs());
284       return {};
285     }
286     if (driver.getDefinition) {
287       if (auto cb{allCookedSources.GetCharBlockFromLineAndColumns(
288               driver.getDefinitionArgs.line,
289               driver.getDefinitionArgs.startColumn,
290               driver.getDefinitionArgs.endColumn)}) {
291         llvm::errs() << "String range: >" << cb->ToString() << "<\n";
292         if (auto symbol{semanticsContext.FindScope(*cb).FindSymbol(*cb)}) {
293           llvm::errs() << "Found symbol name: " << symbol->name().ToString()
294                        << "\n";
295           if (auto sourceInfo{
296                   allCookedSources.GetSourcePositionRange(symbol->name())}) {
297             llvm::outs() << symbol->name().ToString() << ": "
298                          << sourceInfo->first.file.path() << ", "
299                          << sourceInfo->first.line << ", "
300                          << sourceInfo->first.column << "-"
301                          << sourceInfo->second.column << "\n";
302             exitStatus = EXIT_SUCCESS;
303             return {};
304           }
305         }
306       }
307       llvm::errs() << "Symbol not found.\n";
308       exitStatus = EXIT_FAILURE;
309       return {};
310     }
311   }
312   if (driver.dumpParseTree) {
313     Fortran::parser::DumpTree(llvm::outs(), parseTree, &asFortran);
314   }
315   if (driver.dumpUnparse) {
316     Unparse(llvm::outs(), parseTree, driver.encoding, true /*capitalize*/,
317         options.features.IsEnabled(
318             Fortran::common::LanguageFeature::BackslashEscapes),
319         nullptr /* action before each statement */, &asFortran);
320     return {};
321   }
322   if (driver.dumpPreFirTree) {
323     if (auto ast{Fortran::lower::createPFT(parseTree, semanticsContext)}) {
324       Fortran::lower::dumpPFT(llvm::outs(), *ast);
325     } else {
326       llvm::errs() << "Pre FIR Tree is NULL.\n";
327       exitStatus = EXIT_FAILURE;
328     }
329   }
330   if (driver.parseOnly) {
331     return {};
332   }
333 
334   std::string relo{RelocatableName(driver, path)};
335 
336   llvm::SmallString<32> tmpSourcePath;
337   {
338     int fd;
339     std::error_code EC =
340         llvm::sys::fs::createUniqueFile("f18-%%%%.f90", fd, tmpSourcePath);
341     if (EC) {
342       llvm::errs() << EC.message() << "\n";
343       std::exit(EXIT_FAILURE);
344     }
345     llvm::raw_fd_ostream tmpSource(fd, /*shouldClose*/ true);
346     Unparse(tmpSource, parseTree, driver.encoding, true /*capitalize*/,
347         options.features.IsEnabled(
348             Fortran::common::LanguageFeature::BackslashEscapes),
349         nullptr /* action before each statement */,
350         driver.unparseTypedExprsToF18_FC ? &asFortran : nullptr);
351   }
352 
353   RunOtherCompiler(driver, tmpSourcePath.data(), relo.data());
354   filesToDelete.emplace_back(tmpSourcePath);
355   if (!driver.compileOnly && driver.outputPath.empty()) {
356     filesToDelete.push_back(relo);
357   }
358   return relo;
359 }
360 
CompileOtherLanguage(std::string path,DriverOptions & driver)361 std::string CompileOtherLanguage(std::string path, DriverOptions &driver) {
362   std::string relo{RelocatableName(driver, path)};
363   RunOtherCompiler(driver, path.data(), relo.data());
364   if (!driver.compileOnly && driver.outputPath.empty()) {
365     filesToDelete.push_back(relo);
366   }
367   return relo;
368 }
369 
Link(std::vector<std::string> & liblist,std::vector<std::string> & objects,DriverOptions & driver)370 void Link(std::vector<std::string> &liblist, std::vector<std::string> &objects,
371     DriverOptions &driver) {
372   std::vector<llvm::StringRef> argv;
373   for (size_t j{0}; j < driver.F18_FCArgs.size(); ++j) {
374     argv.push_back(driver.F18_FCArgs[j].data());
375   }
376   for (auto &obj : objects) {
377     argv.push_back(obj.data());
378   }
379   if (!driver.outputPath.empty()) {
380     char dashO[3] = "-o";
381     argv.push_back(dashO);
382     argv.push_back(driver.outputPath.data());
383   }
384   for (auto &lib : liblist) {
385     argv.push_back(lib.data());
386   }
387   Exec(argv, driver.verbose);
388 }
389 
printVersion()390 int printVersion() {
391   llvm::errs() << "\nf18 compiler (under development), version "
392                << FLANG_VERSION_STRING << "\n";
393   return exitStatus;
394 }
395 
main(int argc,char * const argv[])396 int main(int argc, char *const argv[]) {
397 
398   atexit(CleanUpAtExit);
399 
400   DriverOptions driver;
401   const char *F18_FC{getenv("F18_FC")};
402   driver.F18_FCArgs.push_back(F18_FC ? F18_FC : "gfortran");
403   bool isPGF90{driver.F18_FCArgs.back().rfind("pgf90") != std::string::npos};
404 
405   std::list<std::string> args{argList(argc, argv)};
406   std::vector<std::string> objlist, liblist;
407   std::string prefix{args.front()};
408   args.pop_front();
409   prefix += ": ";
410   driver.prefix = prefix.data();
411 
412   Fortran::parser::Options options;
413   options.predefinitions.emplace_back("__F18", "1");
414   options.predefinitions.emplace_back("__F18_MAJOR__", "1");
415   options.predefinitions.emplace_back("__F18_MINOR__", "1");
416   options.predefinitions.emplace_back("__F18_PATCHLEVEL__", "1");
417   options.predefinitions.emplace_back("__flang__", FLANG_VERSION_STRING);
418   options.predefinitions.emplace_back(
419       "__flang_major__", FLANG_VERSION_MAJOR_STRING);
420   options.predefinitions.emplace_back(
421       "__flang_minor__", FLANG_VERSION_MINOR_STRING);
422   options.predefinitions.emplace_back(
423       "__flang_patchlevel__", FLANG_VERSION_PATCHLEVEL_STRING);
424 #if __x86_64__
425   options.predefinitions.emplace_back("__x86_64__", "1");
426 #endif
427 
428   Fortran::common::IntrinsicTypeDefaultKinds defaultKinds;
429 
430   std::vector<std::string> fortranSources, otherSources;
431   bool anyFiles{false};
432 
433   while (!args.empty()) {
434     std::string arg{std::move(args.front())};
435     auto dot{arg.rfind(".")};
436     std::string suffix{arg.substr(dot + 1)};
437     std::string prefix{arg.substr(0, 2)};
438     args.pop_front();
439     if (arg.empty()) {
440     } else if (arg.at(0) != '-') {
441       anyFiles = true;
442       if (dot == std::string::npos) {
443         driver.F18_FCArgs.push_back(arg);
444       } else {
445         if (suffix == "f" || suffix == "F" || suffix == "ff" ||
446             suffix == "f90" || suffix == "F90" || suffix == "ff90" ||
447             suffix == "f95" || suffix == "F95" || suffix == "ff95" ||
448             suffix == "cuf" || suffix == "CUF" || suffix == "f18" ||
449             suffix == "F18" || suffix == "ff18") {
450           fortranSources.push_back(arg);
451         } else if (suffix == "o" || suffix == "so") {
452           objlist.push_back(arg);
453         } else if (suffix == "a") {
454           liblist.push_back(arg);
455         } else {
456           otherSources.push_back(arg);
457         }
458       }
459     } else if (prefix == "-l" || suffix == "a") {
460       liblist.push_back(arg);
461     } else if (arg == "-") {
462       fortranSources.push_back("-");
463     } else if (arg == "--") {
464       while (!args.empty()) {
465         fortranSources.emplace_back(std::move(args.front()));
466         args.pop_front();
467       }
468       break;
469     } else if (arg == "-Mfixed" || arg == "-ffixed-form") {
470       driver.forcedForm = true;
471       options.isFixedForm = true;
472     } else if (arg == "-Mfree" || arg == "-ffree-form") {
473       driver.forcedForm = true;
474       options.isFixedForm = false;
475     } else if (arg == "-Mextend" || arg == "-ffixed-line-length-132") {
476       options.fixedFormColumns = 132;
477     } else if (arg == "-Munlimited" || arg == "-ffree-line-length-none" ||
478         arg == "-ffree-line-length-0" || arg == "-ffixed-line-length-none" ||
479         arg == "-ffixed-line-length-0") {
480       // For reparsing f18's -E output of fixed-form cooked character stream
481       options.fixedFormColumns = 1000000;
482     } else if (arg == "-Mbackslash") {
483       options.features.Enable(
484           Fortran::common::LanguageFeature::BackslashEscapes, false);
485     } else if (arg == "-Mnobackslash") {
486       options.features.Enable(
487           Fortran::common::LanguageFeature::BackslashEscapes, true);
488     } else if (arg == "-Mstandard" || arg == "-std=f95" ||
489         arg == "-std=f2003" || arg == "-std=f2008" || arg == "-std=legacy") {
490       driver.warnOnNonstandardUsage = true;
491     } else if (arg == "-fopenacc") {
492       options.features.Enable(Fortran::common::LanguageFeature::OpenACC);
493       options.predefinitions.emplace_back("_OPENACC", "202011");
494     } else if (arg == "-fopenmp") {
495       options.features.Enable(Fortran::common::LanguageFeature::OpenMP);
496       options.predefinitions.emplace_back("_OPENMP", "201511");
497     } else if (arg == "-Werror") {
498       driver.warningsAreErrors = true;
499     } else if (arg == "-ed") {
500       options.features.Enable(Fortran::common::LanguageFeature::OldDebugLines);
501     } else if (arg == "-E") {
502       driver.dumpCookedChars = true;
503     } else if (arg == "-fbackslash" || arg == "-fno-backslash") {
504       options.features.Enable(
505           Fortran::common::LanguageFeature::BackslashEscapes,
506           arg == "-fbackslash");
507     } else if (arg == "-fxor-operator" || arg == "-fno-xor-operator") {
508       options.features.Enable(Fortran::common::LanguageFeature::XOROperator,
509           arg == "-fxor-operator");
510     } else if (arg == "-flogical-abbreviations" ||
511         arg == "-fno-logical-abbreviations") {
512       options.features.Enable(
513           Fortran::parser::LanguageFeature::LogicalAbbreviations,
514           arg == "-flogical-abbreviations");
515     } else if (arg == "-fimplicit-none-type-always") {
516       options.features.Enable(
517           Fortran::common::LanguageFeature::ImplicitNoneTypeAlways);
518     } else if (arg == "-fimplicit-none-type-never") {
519       options.features.Enable(
520           Fortran::common::LanguageFeature::ImplicitNoneTypeNever);
521     } else if (arg == "-fdebug-dump-provenance") {
522       driver.dumpProvenance = true;
523       options.needProvenanceRangeToCharBlockMappings = true;
524     } else if (arg == "-fdebug-dump-parse-tree") {
525       driver.dumpParseTree = true;
526     } else if (arg == "-fdebug-pre-fir-tree") {
527       driver.dumpPreFirTree = true;
528     } else if (arg == "-fdebug-dump-symbols") {
529       driver.dumpSymbols = true;
530     } else if (arg == "-fdebug-module-writer") {
531       driver.debugModuleWriter = true;
532     } else if (arg == "-fdebug-measure-parse-tree") {
533       driver.measureTree = true;
534     } else if (arg == "-fdebug-instrumented-parse") {
535       options.instrumentedParse = true;
536     } else if (arg == "-fdebug-no-semantics") {
537       driver.debugNoSemantics = true;
538     } else if (arg == "-funparse") {
539       driver.dumpUnparse = true;
540     } else if (arg == "-funparse-with-symbols") {
541       driver.dumpUnparseWithSymbols = true;
542     } else if (arg == "-funparse-typed-exprs-to-f18-fc") {
543       driver.unparseTypedExprsToF18_FC = true;
544     } else if (arg == "-fparse-only") {
545       driver.parseOnly = true;
546     } else if (arg == "-c") {
547       driver.compileOnly = true;
548     } else if (arg == "-o") {
549       driver.outputPath = args.front();
550       args.pop_front();
551     } else if (arg.substr(0, 2) == "-D") {
552       auto eq{arg.find('=')};
553       if (eq == std::string::npos) {
554         options.predefinitions.emplace_back(arg.substr(2), "1");
555       } else {
556         options.predefinitions.emplace_back(
557             arg.substr(2, eq - 2), arg.substr(eq + 1));
558       }
559     } else if (arg.substr(0, 2) == "-U") {
560       options.predefinitions.emplace_back(
561           arg.substr(2), std::optional<std::string>{});
562     } else if (arg == "-fdefault-double-8") {
563       defaultKinds.set_defaultRealKind(4);
564     } else if (arg == "-r8" || arg == "-fdefault-real-8") {
565       defaultKinds.set_defaultRealKind(8);
566     } else if (arg == "-i8" || arg == "-fdefault-integer-8") {
567       defaultKinds.set_defaultIntegerKind(8);
568       defaultKinds.set_subscriptIntegerKind(8);
569       defaultKinds.set_sizeIntegerKind(8);
570       if (isPGF90) {
571         driver.F18_FCArgs.push_back("-i8");
572       } else {
573         driver.F18_FCArgs.push_back("-fdefault-integer-8");
574       }
575     } else if (arg == "-flarge-sizes") {
576       defaultKinds.set_sizeIntegerKind(8);
577     } else if (arg == "-fno-large-sizes") {
578       defaultKinds.set_sizeIntegerKind(4);
579     } else if (arg == "-module") {
580       driver.moduleDirectory = args.front();
581       args.pop_front();
582     } else if (arg == "-module-suffix") {
583       driver.moduleFileSuffix = args.front();
584       args.pop_front();
585     } else if (arg == "-intrinsic-module-directory") {
586       driver.searchDirectories.push_back(args.front());
587       args.pop_front();
588     } else if (arg == "-futf-8") {
589       driver.encoding = Fortran::parser::Encoding::UTF_8;
590     } else if (arg == "-flatin") {
591       driver.encoding = Fortran::parser::Encoding::LATIN_1;
592     } else if (arg == "-fget-definition") {
593       // Receives 3 arguments: line, startColumn, endColumn.
594       options.needProvenanceRangeToCharBlockMappings = true;
595       driver.getDefinition = true;
596       char *endptr;
597       int arguments[3];
598       for (int i = 0; i < 3; i++) {
599         if (args.empty()) {
600           llvm::errs() << "Must provide 3 arguments for -fget-definitions.\n";
601           return EXIT_FAILURE;
602         }
603         arguments[i] = std::strtol(args.front().c_str(), &endptr, 10);
604         if (*endptr != '\0') {
605           llvm::errs() << "Invalid argument to -fget-definitions: "
606                        << args.front() << '\n';
607           return EXIT_FAILURE;
608         }
609         args.pop_front();
610       }
611       driver.getDefinitionArgs = {arguments[0], arguments[1], arguments[2]};
612     } else if (arg == "-fget-symbols-sources") {
613       driver.getSymbolsSources = true;
614     } else if (arg == "-byteswapio") {
615       driver.byteswapio = true; // TODO: Pass to lowering, generate call
616     } else if (arg == "-h" || arg == "-help" || arg == "--help" ||
617         arg == "-?") {
618       llvm::errs()
619           << "f18: LLVM Fortran compiler\n"
620           << "\n"
621           << "Usage: f18 [options] <input files>\n"
622           << "\n"
623           << "Defaults:\n"
624           << "  When invoked with input files, and no options to tell\n"
625           << "  it otherwise, f18 will unparse its input and pass that on to "
626              "an\n"
627           << "  external compiler to continue the compilation.\n"
628           << "  The external compiler is specified by the F18_FC environment\n"
629           << "  variable. The default is 'gfortran'.\n"
630           << "  If invoked with no input files, f18 reads source code from\n"
631           << "  stdin and runs with -fdebug-measure-parse-tree -funparse.\n"
632           << "\n"
633           << "f18 options:\n"
634           << "  -Mfixed | -Mfree | -ffixed-form | -ffree-form   force the "
635              "source form\n"
636           << "  -Mextend | -ffixed-line-length-132   132-column fixed form\n"
637           << "  -f[no-]backslash     enable[disable] \\escapes in literals\n"
638           << "  -M[no]backslash      disable[enable] \\escapes in literals\n"
639           << "  -Mstandard           enable conformance warnings\n"
640           << "  -std=<standard>      enable conformance warnings\n"
641           << "  -r8 | -fdefault-real-8 | -i8 | -fdefault-integer-8 | "
642              "-fdefault-double-8   change default kinds of intrinsic types\n"
643           << "  -Werror              treat warnings as errors\n"
644           << "  -ed                  enable fixed form D lines\n"
645           << "  -E                   prescan & preprocess only\n"
646           << "  -module dir          module output directory (default .)\n"
647           << "  -flatin              interpret source as Latin-1 (ISO 8859-1) "
648              "rather than UTF-8\n"
649           << "  -fparse-only         parse only, no output except messages\n"
650           << "  -funparse            parse & reformat only, no code "
651              "generation\n"
652           << "  -funparse-with-symbols  parse, resolve symbols, and unparse\n"
653           << "  -fdebug-measure-parse-tree\n"
654           << "  -fdebug-dump-provenance\n"
655           << "  -fdebug-dump-parse-tree\n"
656           << "  -fdebug-dump-symbols\n"
657           << "  -fdebug-instrumented-parse\n"
658           << "  -fdebug-no-semantics  disable semantic checks\n"
659           << "  -fget-definition\n"
660           << "  -fget-symbols-sources\n"
661           << "  -v -c -o -I -D -U    have their usual meanings\n"
662           << "  -help                print this again\n"
663           << "Unrecognised options are passed through to the external "
664              "compiler\n"
665           << "set by F18_FC (see defaults).\n";
666       return exitStatus;
667     } else if (arg == "-V" || arg == "--version") {
668       return printVersion();
669     } else if (arg == "-fdebug-stack-trace") {
670       llvm::sys::PrintStackTraceOnErrorSignal(llvm::StringRef{}, true);
671     } else {
672       driver.F18_FCArgs.push_back(arg);
673       if (arg == "-v") {
674         if (args.size() > 1) {
675           driver.verbose = true;
676         } else {
677           return printVersion();
678         }
679       } else if (arg == "-I") {
680         driver.F18_FCArgs.push_back(args.front());
681         driver.searchDirectories.push_back(args.front());
682         args.pop_front();
683       } else if (arg.substr(0, 2) == "-I") {
684         driver.searchDirectories.push_back(arg.substr(2));
685       }
686     }
687   }
688 
689   if (driver.warnOnNonstandardUsage) {
690     options.features.WarnOnAllNonstandard();
691   }
692   if (isPGF90) {
693     if (!options.features.IsEnabled(
694             Fortran::common::LanguageFeature::BackslashEscapes)) {
695       driver.F18_FCArgs.push_back(
696           "-Mbackslash"); // yes, this *disables* them in pgf90
697     }
698     if (options.features.IsEnabled(Fortran::common::LanguageFeature::OpenMP)) {
699       driver.F18_FCArgs.push_back("-mp");
700     }
701 
702     Fortran::parser::useHexadecimalEscapeSequences = false;
703   } else {
704     if (options.features.IsEnabled(
705             Fortran::common::LanguageFeature::BackslashEscapes)) {
706       driver.F18_FCArgs.push_back("-fbackslash");
707     }
708     if (options.features.IsEnabled(Fortran::common::LanguageFeature::OpenMP)) {
709       driver.F18_FCArgs.push_back("-fopenmp");
710     }
711 
712     Fortran::parser::useHexadecimalEscapeSequences = true;
713   }
714 
715   if (!anyFiles) {
716     driver.measureTree = true;
717     driver.dumpUnparse = true;
718     llvm::outs() << "Enter Fortran source\n"
719                  << "Use EOF character (^D) to end file\n";
720     CompileFortran("-", options, driver, defaultKinds);
721     return exitStatus;
722   }
723   for (const auto &path : fortranSources) {
724     std::string relo{CompileFortran(path, options, driver, defaultKinds)};
725     if (!driver.compileOnly && !relo.empty()) {
726       objlist.push_back(relo);
727     }
728   }
729   for (const auto &path : otherSources) {
730     std::string relo{CompileOtherLanguage(path, driver)};
731     if (!driver.compileOnly && !relo.empty()) {
732       objlist.push_back(relo);
733     }
734   }
735   if (!driver.compileOnly && !objlist.empty()) {
736     Link(liblist, objlist, driver);
737   }
738   return exitStatus;
739 }
740