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