| //===-- tools/f18/f18.cpp -------------------------------------------------===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| |
| // Temporary Fortran front end driver main program for development scaffolding. |
| |
| #include "flang/Common/Fortran-features.h" |
| #include "flang/Common/default-kinds.h" |
| #include "flang/Evaluate/expression.h" |
| #include "flang/Lower/PFTBuilder.h" |
| #include "flang/Parser/characters.h" |
| #include "flang/Parser/dump-parse-tree.h" |
| #include "flang/Parser/message.h" |
| #include "flang/Parser/parse-tree-visitor.h" |
| #include "flang/Parser/parse-tree.h" |
| #include "flang/Parser/parsing.h" |
| #include "flang/Parser/provenance.h" |
| #include "flang/Parser/unparse.h" |
| #include "flang/Semantics/expression.h" |
| #include "flang/Semantics/runtime-type-info.h" |
| #include "flang/Semantics/semantics.h" |
| #include "flang/Semantics/unparse-with-symbols.h" |
| #include "flang/Version.inc" |
| #include "llvm/Support/Errno.h" |
| #include "llvm/Support/FileSystem.h" |
| #include "llvm/Support/Program.h" |
| #include "llvm/Support/Signals.h" |
| #include "llvm/Support/raw_ostream.h" |
| #include <cstdio> |
| #include <cstring> |
| #include <fstream> |
| #include <list> |
| #include <memory> |
| #include <optional> |
| #include <stdlib.h> |
| #include <string> |
| #include <vector> |
| |
| static std::list<std::string> argList(int argc, char *const argv[]) { |
| std::list<std::string> result; |
| for (int j = 0; j < argc; ++j) { |
| result.emplace_back(argv[j]); |
| } |
| return result; |
| } |
| |
| struct MeasurementVisitor { |
| template <typename A> bool Pre(const A &) { return true; } |
| template <typename A> void Post(const A &) { |
| ++objects; |
| bytes += sizeof(A); |
| } |
| size_t objects{0}, bytes{0}; |
| }; |
| |
| void MeasureParseTree(const Fortran::parser::Program &program) { |
| MeasurementVisitor visitor; |
| Fortran::parser::Walk(program, visitor); |
| llvm::outs() << "Parse tree comprises " << visitor.objects |
| << " objects and occupies " << visitor.bytes |
| << " total bytes.\n"; |
| } |
| |
| std::vector<std::string> filesToDelete; |
| |
| void CleanUpAtExit() { |
| for (const auto &path : filesToDelete) { |
| if (!path.empty()) { |
| llvm::sys::fs::remove(path); |
| } |
| } |
| } |
| |
| struct GetDefinitionArgs { |
| int line, startColumn, endColumn; |
| }; |
| |
| struct DriverOptions { |
| DriverOptions() {} |
| bool verbose{false}; // -v |
| bool compileOnly{false}; // -c |
| std::string outputPath; // -o path |
| std::vector<std::string> searchDirectories; // -I dir |
| std::string moduleDirectory{"."s}; // -module dir |
| std::string moduleFileSuffix{".mod"}; // -moduleSuffix suff |
| bool forcedForm{false}; // -Mfixed or -Mfree appeared |
| bool warnOnNonstandardUsage{false}; // -Mstandard |
| bool warningsAreErrors{false}; // -Werror |
| bool byteswapio{false}; // -byteswapio |
| Fortran::parser::Encoding encoding{Fortran::parser::Encoding::UTF_8}; |
| bool syntaxOnly{false}; |
| bool dumpProvenance{false}; |
| bool dumpCookedChars{false}; |
| bool dumpUnparse{false}; |
| bool dumpUnparseWithSymbols{false}; |
| bool dumpParseTree{false}; |
| bool dumpPreFirTree{false}; |
| bool dumpSymbols{false}; |
| bool debugNoSemantics{false}; |
| bool debugModuleWriter{false}; |
| bool defaultReal8{false}; |
| bool measureTree{false}; |
| bool unparseTypedExprsToF18_FC{false}; |
| std::vector<std::string> F18_FCArgs; |
| const char *prefix{nullptr}; |
| bool getDefinition{false}; |
| GetDefinitionArgs getDefinitionArgs{0, 0, 0}; |
| bool getSymbolsSources{false}; |
| std::optional<bool> forcePreprocessing; // -cpp & -nocpp |
| }; |
| |
| void Exec(std::vector<llvm::StringRef> &argv, bool verbose = false) { |
| if (verbose) { |
| for (size_t j{0}; j < argv.size(); ++j) { |
| llvm::errs() << (j > 0 ? " " : "") << argv[j]; |
| } |
| llvm::errs() << '\n'; |
| } |
| std::string ErrMsg; |
| llvm::ErrorOr<std::string> Program = llvm::sys::findProgramByName(argv[0]); |
| if (!Program) |
| ErrMsg = Program.getError().message(); |
| if (!Program || |
| llvm::sys::ExecuteAndWait( |
| Program.get(), argv, llvm::None, {}, 0, 0, &ErrMsg)) { |
| llvm::errs() << "execvp(" << argv[0] << ") failed: " << ErrMsg << '\n'; |
| exit(EXIT_FAILURE); |
| } |
| } |
| |
| void RunOtherCompiler(DriverOptions &driver, char *source, char *relo) { |
| std::vector<llvm::StringRef> argv; |
| for (size_t j{0}; j < driver.F18_FCArgs.size(); ++j) { |
| argv.push_back(driver.F18_FCArgs[j]); |
| } |
| char dashC[3] = "-c", dashO[3] = "-o"; |
| argv.push_back(dashC); |
| argv.push_back(dashO); |
| argv.push_back(relo); |
| argv.push_back(source); |
| Exec(argv, driver.verbose); |
| } |
| |
| std::string RelocatableName(const DriverOptions &driver, std::string path) { |
| if (driver.compileOnly && !driver.outputPath.empty()) { |
| return driver.outputPath; |
| } |
| std::string base{path}; |
| auto slash{base.rfind("/")}; |
| if (slash != std::string::npos) { |
| base = base.substr(slash + 1); |
| } |
| std::string relo{base}; |
| auto dot{base.rfind(".")}; |
| if (dot != std::string::npos) { |
| relo = base.substr(0, dot); |
| } |
| relo += ".o"; |
| return relo; |
| } |
| |
| int exitStatus{EXIT_SUCCESS}; |
| |
| static Fortran::parser::AnalyzedObjectsAsFortran asFortran{ |
| [](llvm::raw_ostream &o, const Fortran::evaluate::GenericExprWrapper &x) { |
| if (x.v) { |
| x.v->AsFortran(o); |
| } else { |
| o << "(bad expression)"; |
| } |
| }, |
| [](llvm::raw_ostream &o, |
| const Fortran::evaluate::GenericAssignmentWrapper &x) { |
| if (x.v) { |
| x.v->AsFortran(o); |
| } else { |
| o << "(bad assignment)"; |
| } |
| }, |
| [](llvm::raw_ostream &o, const Fortran::evaluate::ProcedureRef &x) { |
| x.AsFortran(o << "CALL "); |
| }, |
| }; |
| |
| std::string CompileFortran(std::string path, Fortran::parser::Options options, |
| DriverOptions &driver, |
| const Fortran::common::IntrinsicTypeDefaultKinds &defaultKinds) { |
| Fortran::parser::AllSources allSources; |
| Fortran::parser::AllCookedSources allCookedSources{allSources}; |
| allSources.set_encoding(driver.encoding); |
| Fortran::semantics::SemanticsContext semanticsContext{ |
| defaultKinds, options.features, allCookedSources}; |
| semanticsContext.set_moduleDirectory(driver.moduleDirectory) |
| .set_moduleFileSuffix(driver.moduleFileSuffix) |
| .set_searchDirectories(driver.searchDirectories) |
| .set_warnOnNonstandardUsage(driver.warnOnNonstandardUsage) |
| .set_warningsAreErrors(driver.warningsAreErrors); |
| if (!driver.forcedForm) { |
| auto dot{path.rfind(".")}; |
| if (dot != std::string::npos) { |
| std::string suffix{path.substr(dot + 1)}; |
| options.isFixedForm = suffix == "f" || suffix == "F" || suffix == "ff"; |
| } |
| } |
| options.searchDirectories = driver.searchDirectories; |
| Fortran::parser::Parsing parsing{allCookedSources}; |
| parsing.Prescan(path, options); |
| if (!parsing.messages().empty() && |
| (driver.warningsAreErrors || parsing.messages().AnyFatalError())) { |
| llvm::errs() << driver.prefix << "Could not scan " << path << '\n'; |
| parsing.messages().Emit(llvm::errs(), allCookedSources); |
| exitStatus = EXIT_FAILURE; |
| return {}; |
| } |
| if (driver.dumpProvenance) { |
| parsing.DumpProvenance(llvm::outs()); |
| return {}; |
| } |
| if (driver.dumpCookedChars) { |
| parsing.messages().Emit(llvm::errs(), allCookedSources); |
| parsing.DumpCookedChars(llvm::outs()); |
| return {}; |
| } |
| parsing.Parse(llvm::outs()); |
| if (options.instrumentedParse) { |
| parsing.DumpParsingLog(llvm::outs()); |
| return {}; |
| } |
| parsing.ClearLog(); |
| parsing.messages().Emit(llvm::errs(), allCookedSources); |
| if (!parsing.consumedWholeFile()) { |
| parsing.EmitMessage(llvm::errs(), parsing.finalRestingPlace(), |
| "Parser FAIL (final position)"); |
| exitStatus = EXIT_FAILURE; |
| return {}; |
| } |
| if ((!parsing.messages().empty() && |
| (driver.warningsAreErrors || parsing.messages().AnyFatalError())) || |
| !parsing.parseTree()) { |
| llvm::errs() << driver.prefix << "Could not parse " << path << '\n'; |
| exitStatus = EXIT_FAILURE; |
| return {}; |
| } |
| auto &parseTree{*parsing.parseTree()}; |
| if (driver.measureTree) { |
| MeasureParseTree(parseTree); |
| } |
| if (!driver.debugNoSemantics || driver.dumpSymbols || |
| driver.dumpUnparseWithSymbols || driver.getDefinition || |
| driver.getSymbolsSources) { |
| Fortran::semantics::Semantics semantics{semanticsContext, parseTree, |
| parsing.cooked().AsCharBlock(), driver.debugModuleWriter}; |
| semantics.Perform(); |
| semantics.EmitMessages(llvm::errs()); |
| if (semantics.AnyFatalError()) { |
| if (driver.dumpSymbols) { |
| semantics.DumpSymbols(llvm::outs()); |
| } |
| llvm::errs() << driver.prefix << "Semantic errors in " << path << '\n'; |
| exitStatus = EXIT_FAILURE; |
| if (driver.dumpParseTree) { |
| Fortran::parser::DumpTree(llvm::outs(), parseTree, &asFortran); |
| } |
| return {}; |
| } |
| auto tables{ |
| Fortran::semantics::BuildRuntimeDerivedTypeTables(semanticsContext)}; |
| if (!tables.schemata) { |
| llvm::errs() << driver.prefix |
| << "could not find module file for __fortran_type_info\n"; |
| } |
| if (driver.dumpSymbols) { |
| semantics.DumpSymbols(llvm::outs()); |
| } |
| if (driver.dumpUnparseWithSymbols) { |
| Fortran::semantics::UnparseWithSymbols( |
| llvm::outs(), parseTree, driver.encoding); |
| return {}; |
| } |
| if (driver.getSymbolsSources) { |
| semantics.DumpSymbolsSources(llvm::outs()); |
| return {}; |
| } |
| if (driver.getDefinition) { |
| if (auto cb{allCookedSources.GetCharBlockFromLineAndColumns( |
| driver.getDefinitionArgs.line, |
| driver.getDefinitionArgs.startColumn, |
| driver.getDefinitionArgs.endColumn)}) { |
| llvm::errs() << "String range: >" << cb->ToString() << "<\n"; |
| if (auto symbol{semanticsContext.FindScope(*cb).FindSymbol(*cb)}) { |
| llvm::errs() << "Found symbol name: " << symbol->name().ToString() |
| << "\n"; |
| if (auto sourceInfo{ |
| allCookedSources.GetSourcePositionRange(symbol->name())}) { |
| llvm::outs() << symbol->name().ToString() << ": " |
| << sourceInfo->first.file.path() << ", " |
| << sourceInfo->first.line << ", " |
| << sourceInfo->first.column << "-" |
| << sourceInfo->second.column << "\n"; |
| exitStatus = EXIT_SUCCESS; |
| return {}; |
| } |
| } |
| } |
| llvm::errs() << "Symbol not found.\n"; |
| exitStatus = EXIT_FAILURE; |
| return {}; |
| } |
| } |
| if (driver.dumpParseTree) { |
| Fortran::parser::DumpTree(llvm::outs(), parseTree, &asFortran); |
| } |
| if (driver.dumpUnparse) { |
| Unparse(llvm::outs(), parseTree, driver.encoding, true /*capitalize*/, |
| options.features.IsEnabled( |
| Fortran::common::LanguageFeature::BackslashEscapes), |
| nullptr /* action before each statement */, &asFortran); |
| return {}; |
| } |
| if (driver.dumpPreFirTree) { |
| if (auto ast{Fortran::lower::createPFT(parseTree, semanticsContext)}) { |
| Fortran::lower::dumpPFT(llvm::outs(), *ast); |
| } else { |
| llvm::errs() << "Pre FIR Tree is NULL.\n"; |
| exitStatus = EXIT_FAILURE; |
| } |
| } |
| if (driver.syntaxOnly) { |
| return {}; |
| } |
| |
| std::string relo{RelocatableName(driver, path)}; |
| |
| llvm::SmallString<32> tmpSourcePath; |
| { |
| int fd; |
| std::error_code EC = |
| llvm::sys::fs::createUniqueFile("f18-%%%%.f90", fd, tmpSourcePath); |
| if (EC) { |
| llvm::errs() << EC.message() << "\n"; |
| std::exit(EXIT_FAILURE); |
| } |
| llvm::raw_fd_ostream tmpSource(fd, /*shouldClose*/ true); |
| Unparse(tmpSource, parseTree, driver.encoding, true /*capitalize*/, |
| options.features.IsEnabled( |
| Fortran::common::LanguageFeature::BackslashEscapes), |
| nullptr /* action before each statement */, |
| driver.unparseTypedExprsToF18_FC ? &asFortran : nullptr); |
| } |
| |
| RunOtherCompiler(driver, tmpSourcePath.data(), relo.data()); |
| filesToDelete.emplace_back(tmpSourcePath); |
| if (!driver.compileOnly && driver.outputPath.empty()) { |
| filesToDelete.push_back(relo); |
| } |
| return relo; |
| } |
| |
| std::string CompileOtherLanguage(std::string path, DriverOptions &driver) { |
| std::string relo{RelocatableName(driver, path)}; |
| RunOtherCompiler(driver, path.data(), relo.data()); |
| if (!driver.compileOnly && driver.outputPath.empty()) { |
| filesToDelete.push_back(relo); |
| } |
| return relo; |
| } |
| |
| void Link(std::vector<std::string> &liblist, std::vector<std::string> &objects, |
| DriverOptions &driver) { |
| std::vector<llvm::StringRef> argv; |
| for (size_t j{0}; j < driver.F18_FCArgs.size(); ++j) { |
| argv.push_back(driver.F18_FCArgs[j].data()); |
| } |
| for (auto &obj : objects) { |
| argv.push_back(obj.data()); |
| } |
| if (!driver.outputPath.empty()) { |
| char dashO[3] = "-o"; |
| argv.push_back(dashO); |
| argv.push_back(driver.outputPath.data()); |
| } |
| for (auto &lib : liblist) { |
| argv.push_back(lib.data()); |
| } |
| Exec(argv, driver.verbose); |
| } |
| |
| int printVersion() { |
| llvm::errs() << "\nf18 compiler (under development), version " |
| << FLANG_VERSION_STRING << "\n"; |
| return exitStatus; |
| } |
| |
| int main(int argc, char *const argv[]) { |
| |
| atexit(CleanUpAtExit); |
| |
| DriverOptions driver; |
| const char *F18_FC{getenv("F18_FC")}; |
| driver.F18_FCArgs.push_back(F18_FC ? F18_FC : "gfortran"); |
| bool isPGF90{driver.F18_FCArgs.back().rfind("pgf90") != std::string::npos}; |
| |
| std::list<std::string> args{argList(argc, argv)}; |
| std::vector<std::string> objlist, liblist; |
| std::string prefix{args.front()}; |
| args.pop_front(); |
| prefix += ": "; |
| driver.prefix = prefix.data(); |
| |
| Fortran::parser::Options options; |
| std::vector<Fortran::parser::Options::Predefinition> predefinitions; |
| predefinitions.emplace_back("__F18", "1"); |
| predefinitions.emplace_back("__F18_MAJOR__", "1"); |
| predefinitions.emplace_back("__F18_MINOR__", "1"); |
| predefinitions.emplace_back("__F18_PATCHLEVEL__", "1"); |
| predefinitions.emplace_back("__flang__", FLANG_VERSION_STRING); |
| predefinitions.emplace_back("__flang_major__", FLANG_VERSION_MAJOR_STRING); |
| predefinitions.emplace_back("__flang_minor__", FLANG_VERSION_MINOR_STRING); |
| predefinitions.emplace_back( |
| "__flang_patchlevel__", FLANG_VERSION_PATCHLEVEL_STRING); |
| #if __x86_64__ |
| predefinitions.emplace_back("__x86_64__", "1"); |
| #endif |
| |
| Fortran::common::IntrinsicTypeDefaultKinds defaultKinds; |
| |
| std::vector<std::string> fortranSources, otherSources; |
| bool anyFiles{false}; |
| |
| while (!args.empty()) { |
| std::string arg{std::move(args.front())}; |
| auto dot{arg.rfind(".")}; |
| std::string suffix{arg.substr(dot + 1)}; |
| std::string prefix{arg.substr(0, 2)}; |
| args.pop_front(); |
| if (arg.empty()) { |
| } else if (arg.at(0) != '-') { |
| anyFiles = true; |
| if (dot == std::string::npos) { |
| driver.F18_FCArgs.push_back(arg); |
| } else { |
| if (suffix == "f" || suffix == "F" || suffix == "ff" || |
| suffix == "f90" || suffix == "F90" || suffix == "ff90" || |
| suffix == "f95" || suffix == "F95" || suffix == "ff95" || |
| suffix == "cuf" || suffix == "CUF" || suffix == "f18" || |
| suffix == "F18" || suffix == "ff18") { |
| fortranSources.push_back(arg); |
| } else if (suffix == "o" || suffix == "so") { |
| objlist.push_back(arg); |
| } else if (suffix == "a") { |
| liblist.push_back(arg); |
| } else { |
| otherSources.push_back(arg); |
| } |
| } |
| } else if (prefix == "-l" || suffix == "a") { |
| liblist.push_back(arg); |
| } else if (arg == "-") { |
| fortranSources.push_back("-"); |
| } else if (arg == "--") { |
| while (!args.empty()) { |
| fortranSources.emplace_back(std::move(args.front())); |
| args.pop_front(); |
| } |
| break; |
| } else if (arg == "-Mfixed" || arg == "-ffixed-form") { |
| driver.forcedForm = true; |
| options.isFixedForm = true; |
| } else if (arg == "-Mfree" || arg == "-ffree-form") { |
| driver.forcedForm = true; |
| options.isFixedForm = false; |
| } else if (arg == "-Mextend" || arg == "-ffixed-line-length-132") { |
| options.fixedFormColumns = 132; |
| } else if (arg == "-Munlimited" || arg == "-ffree-line-length-none" || |
| arg == "-ffree-line-length-0" || arg == "-ffixed-line-length-none" || |
| arg == "-ffixed-line-length-0") { |
| // For reparsing f18's -E output of fixed-form cooked character stream |
| options.fixedFormColumns = 1000000; |
| } else if (arg == "-Mbackslash") { |
| options.features.Enable( |
| Fortran::common::LanguageFeature::BackslashEscapes, false); |
| } else if (arg == "-Mnobackslash") { |
| options.features.Enable( |
| Fortran::common::LanguageFeature::BackslashEscapes, true); |
| } else if (arg == "-Mstandard" || arg == "-std=f95" || |
| arg == "-std=f2003" || arg == "-std=f2008" || arg == "-std=legacy") { |
| driver.warnOnNonstandardUsage = true; |
| } else if (arg == "-fopenacc") { |
| options.features.Enable(Fortran::common::LanguageFeature::OpenACC); |
| predefinitions.emplace_back("_OPENACC", "202011"); |
| } else if (arg == "-fopenmp") { |
| options.features.Enable(Fortran::common::LanguageFeature::OpenMP); |
| predefinitions.emplace_back("_OPENMP", "201511"); |
| } else if (arg == "-Werror") { |
| driver.warningsAreErrors = true; |
| } else if (arg == "-ed") { |
| options.features.Enable(Fortran::common::LanguageFeature::OldDebugLines); |
| } else if (arg == "-E") { |
| driver.dumpCookedChars = true; |
| } else if (arg == "-fbackslash" || arg == "-fno-backslash") { |
| options.features.Enable( |
| Fortran::common::LanguageFeature::BackslashEscapes, |
| arg == "-fbackslash"); |
| } else if (arg == "-fxor-operator" || arg == "-fno-xor-operator") { |
| options.features.Enable(Fortran::common::LanguageFeature::XOROperator, |
| arg == "-fxor-operator"); |
| } else if (arg == "-flogical-abbreviations" || |
| arg == "-fno-logical-abbreviations") { |
| options.features.Enable( |
| Fortran::parser::LanguageFeature::LogicalAbbreviations, |
| arg == "-flogical-abbreviations"); |
| } else if (arg == "-fimplicit-none-type-always") { |
| options.features.Enable( |
| Fortran::common::LanguageFeature::ImplicitNoneTypeAlways); |
| } else if (arg == "-fimplicit-none-type-never") { |
| options.features.Enable( |
| Fortran::common::LanguageFeature::ImplicitNoneTypeNever); |
| } else if (arg == "-falternative-parameter-statement") { |
| options.features.Enable( |
| Fortran::common::LanguageFeature::OldStyleParameter, true); |
| } else if (arg == "-fdebug-dump-provenance") { |
| driver.dumpProvenance = true; |
| options.needProvenanceRangeToCharBlockMappings = true; |
| } else if (arg == "-fdebug-dump-parse-tree") { |
| driver.dumpParseTree = true; |
| driver.syntaxOnly = true; |
| } else if (arg == "-fdebug-pre-fir-tree") { |
| driver.dumpPreFirTree = true; |
| } else if (arg == "-fdebug-dump-symbols") { |
| driver.dumpSymbols = true; |
| driver.syntaxOnly = true; |
| } else if (arg == "-fdebug-module-writer") { |
| driver.debugModuleWriter = true; |
| } else if (arg == "-fdebug-measure-parse-tree") { |
| driver.measureTree = true; |
| } else if (arg == "-fdebug-instrumented-parse" || |
| arg == "-fdebug-dump-parsing-log") { |
| options.instrumentedParse = true; |
| } else if (arg == "-fdebug-no-semantics") { |
| driver.debugNoSemantics = true; |
| } else if (arg == "-funparse" || arg == "-fdebug-unparse") { |
| driver.dumpUnparse = true; |
| } else if (arg == "-funparse-with-symbols" || |
| arg == "-fdebug-unparse-with-symbols") { |
| driver.dumpUnparseWithSymbols = true; |
| } else if (arg == "-funparse-typed-exprs-to-f18-fc") { |
| driver.unparseTypedExprsToF18_FC = true; |
| } else if (arg == "-fparse-only" || arg == "-fsyntax-only") { |
| driver.syntaxOnly = true; |
| } else if (arg == "-c") { |
| driver.compileOnly = true; |
| } else if (arg == "-o") { |
| driver.outputPath = args.front(); |
| args.pop_front(); |
| } else if (arg.substr(0, 2) == "-D") { |
| auto eq{arg.find('=')}; |
| if (eq == std::string::npos) { |
| predefinitions.emplace_back(arg.substr(2), "1"); |
| } else { |
| predefinitions.emplace_back(arg.substr(2, eq - 2), arg.substr(eq + 1)); |
| } |
| } else if (arg.substr(0, 2) == "-U") { |
| predefinitions.emplace_back(arg.substr(2), std::optional<std::string>{}); |
| } else if (arg == "-r8" || arg == "-fdefault-real-8") { |
| driver.defaultReal8 = true; |
| defaultKinds.set_defaultRealKind(8); |
| defaultKinds.set_doublePrecisionKind(16); |
| } else if (arg == "-fdefault-double-8") { |
| if (!driver.defaultReal8) { |
| // -fdefault-double-8 has to be used with -fdefault-real-8 |
| // to be compatible with gfortran. See: |
| // https://gcc.gnu.org/onlinedocs/gfortran/Fortran-Dialect-Options.html |
| llvm::errs() |
| << "Use of `-fdefault-double-8` requires `-fdefault-real-8`\n"; |
| return EXIT_FAILURE; |
| } |
| defaultKinds.set_doublePrecisionKind(8); |
| } else if (arg == "-i8" || arg == "-fdefault-integer-8") { |
| defaultKinds.set_defaultIntegerKind(8); |
| defaultKinds.set_subscriptIntegerKind(8); |
| defaultKinds.set_sizeIntegerKind(8); |
| if (isPGF90) { |
| driver.F18_FCArgs.push_back("-i8"); |
| } else { |
| driver.F18_FCArgs.push_back("-fdefault-integer-8"); |
| } |
| } else if (arg == "-flarge-sizes") { |
| defaultKinds.set_sizeIntegerKind(8); |
| } else if (arg == "-fno-large-sizes") { |
| defaultKinds.set_sizeIntegerKind(4); |
| } else if (arg == "-module") { |
| driver.moduleDirectory = args.front(); |
| args.pop_front(); |
| } else if (arg == "-module-dir") { |
| driver.moduleDirectory = args.front(); |
| driver.searchDirectories.push_back(driver.moduleDirectory); |
| args.pop_front(); |
| } else if (arg == "-module-suffix") { |
| driver.moduleFileSuffix = args.front(); |
| args.pop_front(); |
| } else if (arg == "-intrinsic-module-directory") { |
| driver.searchDirectories.push_back(args.front()); |
| args.pop_front(); |
| } else if (arg == "-futf-8") { |
| driver.encoding = Fortran::parser::Encoding::UTF_8; |
| } else if (arg == "-flatin") { |
| driver.encoding = Fortran::parser::Encoding::LATIN_1; |
| } else if (arg == "-fget-definition") { |
| // Receives 3 arguments: line, startColumn, endColumn. |
| options.needProvenanceRangeToCharBlockMappings = true; |
| driver.getDefinition = true; |
| char *endptr; |
| int arguments[3]; |
| for (int i = 0; i < 3; i++) { |
| if (args.empty()) { |
| llvm::errs() << "Must provide 3 arguments for -fget-definitions.\n"; |
| return EXIT_FAILURE; |
| } |
| arguments[i] = std::strtol(args.front().c_str(), &endptr, 10); |
| if (*endptr != '\0') { |
| llvm::errs() << "Invalid argument to -fget-definitions: " |
| << args.front() << '\n'; |
| return EXIT_FAILURE; |
| } |
| args.pop_front(); |
| } |
| driver.getDefinitionArgs = {arguments[0], arguments[1], arguments[2]}; |
| } else if (arg == "-fget-symbols-sources") { |
| driver.getSymbolsSources = true; |
| } else if (arg == "-byteswapio") { |
| driver.byteswapio = true; // TODO: Pass to lowering, generate call |
| } else if (arg == "-cpp") { |
| driver.forcePreprocessing = true; |
| } else if (arg == "-nocpp") { |
| driver.forcePreprocessing = false; |
| } else if (arg == "-h" || arg == "-help" || arg == "--help" || |
| arg == "-?") { |
| llvm::errs() |
| << "f18: LLVM Fortran compiler\n" |
| << "\n" |
| << "Usage: f18 [options] <input files>\n" |
| << "\n" |
| << "Defaults:\n" |
| << " When invoked with input files, and no options to tell\n" |
| << " it otherwise, f18 will unparse its input and pass that on to " |
| "an\n" |
| << " external compiler to continue the compilation.\n" |
| << " The external compiler is specified by the F18_FC environment\n" |
| << " variable. The default is 'gfortran'.\n" |
| << " If invoked with no input files, f18 reads source code from\n" |
| << " stdin and runs with -fdebug-measure-parse-tree -funparse.\n" |
| << "\n" |
| << "f18 options:\n" |
| << " -Mfixed | -Mfree | -ffixed-form | -ffree-form force the " |
| "source form\n" |
| << " -Mextend | -ffixed-line-length-132 132-column fixed form\n" |
| << " -f[no-]backslash enable[disable] \\escapes in literals\n" |
| << " -M[no]backslash disable[enable] \\escapes in literals\n" |
| << " -Mstandard enable conformance warnings\n" |
| << " -std=<standard> enable conformance warnings\n" |
| << " -r8 | -fdefault-real-8 | -i8 | -fdefault-integer-8 | " |
| "-fdefault-double-8 change default kinds of intrinsic types\n" |
| << " -Werror treat warnings as errors\n" |
| << " -ed enable fixed form D lines\n" |
| << " -E prescan & preprocess only\n" |
| << " -module dir module output directory (default .)\n" |
| << " -module-dir/-J <dir> Put MODULE files in <dir>\n" |
| << " -flatin interpret source as Latin-1 (ISO 8859-1) " |
| "rather than UTF-8\n" |
| << " -fsyntax-only parsing and semantics only, no output " |
| "except messages\n" |
| << " -funparse parse & reformat only, no code " |
| "generation\n" |
| << " -funparse-with-symbols parse, resolve symbols, and unparse\n" |
| << " -fdebug-measure-parse-tree\n" |
| << " -fdebug-dump-provenance\n" |
| << " -fdebug-dump-parse-tree\n" |
| << " -fdebug-dump-symbols\n" |
| << " -fdebug-instrumented-parse\n" |
| << " -fdebug-no-semantics disable semantic checks\n" |
| << " -fget-definition\n" |
| << " -fget-symbols-sources\n" |
| << " -v -c -o -I -D -U have their usual meanings\n" |
| << " -cpp / -nocpp force / inhibit macro replacement\n" |
| << " -help print this again\n" |
| << "Unrecognised options are passed through to the external " |
| "compiler\n" |
| << "set by F18_FC (see defaults).\n"; |
| return exitStatus; |
| } else if (arg == "-V" || arg == "--version") { |
| return printVersion(); |
| } else if (arg == "-fdebug-stack-trace") { |
| llvm::sys::PrintStackTraceOnErrorSignal(llvm::StringRef{}, true); |
| } else { |
| driver.F18_FCArgs.push_back(arg); |
| if (arg == "-v") { |
| if (args.size() > 1) { |
| driver.verbose = true; |
| } else { |
| return printVersion(); |
| } |
| } else if (arg == "-I") { |
| driver.F18_FCArgs.push_back(args.front()); |
| driver.searchDirectories.push_back(args.front()); |
| args.pop_front(); |
| } else if (arg.substr(0, 2) == "-I") { |
| driver.searchDirectories.push_back(arg.substr(2)); |
| } else if (arg == "-J") { |
| driver.F18_FCArgs.push_back(args.front()); |
| driver.moduleDirectory = args.front(); |
| driver.searchDirectories.push_back(driver.moduleDirectory); |
| args.pop_front(); |
| } else if (arg.substr(0, 2) == "-J") { |
| driver.moduleDirectory = arg.substr(2); |
| driver.searchDirectories.push_back(driver.moduleDirectory); |
| } |
| } |
| } |
| |
| if (driver.warnOnNonstandardUsage) { |
| options.features.WarnOnAllNonstandard(); |
| } |
| if (isPGF90) { |
| if (!options.features.IsEnabled( |
| Fortran::common::LanguageFeature::BackslashEscapes)) { |
| driver.F18_FCArgs.push_back( |
| "-Mbackslash"); // yes, this *disables* them in pgf90 |
| } |
| if (options.features.IsEnabled(Fortran::common::LanguageFeature::OpenMP)) { |
| driver.F18_FCArgs.push_back("-mp"); |
| } |
| |
| Fortran::parser::useHexadecimalEscapeSequences = false; |
| } else { |
| if (options.features.IsEnabled( |
| Fortran::common::LanguageFeature::BackslashEscapes)) { |
| driver.F18_FCArgs.push_back("-fbackslash"); |
| } |
| if (options.features.IsEnabled(Fortran::common::LanguageFeature::OpenMP)) { |
| driver.F18_FCArgs.push_back("-fopenmp"); |
| } |
| |
| Fortran::parser::useHexadecimalEscapeSequences = true; |
| } |
| |
| if (!anyFiles) { |
| driver.measureTree = true; |
| driver.dumpUnparse = true; |
| llvm::outs() << "Enter Fortran source\n" |
| << "Use EOF character (^D) to end file\n"; |
| CompileFortran("-", options, driver, defaultKinds); |
| return exitStatus; |
| } |
| for (const auto &path : fortranSources) { |
| options.predefinitions.clear(); |
| if (driver.forcePreprocessing) { |
| if (*driver.forcePreprocessing) { |
| options.predefinitions = predefinitions; |
| } |
| } else { |
| auto dot{path.rfind(".")}; |
| if (dot != std::string::npos) { |
| std::string suffix{path.substr(dot + 1)}; |
| if (suffix == "F" || suffix == "F90" || suffix == "F95" || |
| suffix == "CUF" || suffix == "F18") { |
| options.predefinitions = predefinitions; |
| } |
| } |
| } |
| std::string relo{CompileFortran(path, options, driver, defaultKinds)}; |
| if (!driver.compileOnly && !relo.empty()) { |
| objlist.push_back(relo); |
| } |
| } |
| for (const auto &path : otherSources) { |
| std::string relo{CompileOtherLanguage(path, driver)}; |
| if (!driver.compileOnly && !relo.empty()) { |
| objlist.push_back(relo); |
| } |
| } |
| if (!driver.compileOnly && !objlist.empty()) { |
| Link(liblist, objlist, driver); |
| } |
| return exitStatus; |
| } |