[flang][driver] Delete f18
(i.e. the old Flang driver)
This patch removes `f18`, a.k.a. the old driver. It is being replaced with the new driver, `flang-new`, which has reached feature parity with `f18` a while ago. This was discussed in [1] and also in [2]. With this change, `FLANG_BUILD_NEW_DRIVER` is no longer needed and is also deleted. This means that we are making the dependency on Clang permanent (i.e. it cannot be disabled with a CMake flag). LIT set-up is updated accordingly. All references to `f18` or `f18.cpp` are either updated or removed. The `F18_FC` variable from the `flang` bash script is replaced with `FLANG_FC`. The former is still supported for backwards compatibility. [1] https://lists.llvm.org/pipermail/flang-dev/2021-June/000742.html [2] https://reviews.llvm.org/D103177 Differential Revision: https://reviews.llvm.org/D105811
This commit is contained in:
parent
7217b01481
commit
7b73ca3043
@ -26,11 +26,6 @@ if (CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
|
||||
project(Flang)
|
||||
set(FLANG_STANDALONE_BUILD ON)
|
||||
|
||||
# For in-tree builds, this variable is inherited from
|
||||
# llvm-project/llvm/CMakeLists.txt. For out-of-tree builds, we need a
|
||||
# separate definition.
|
||||
option(FLANG_BUILD_NEW_DRIVER "Build the flang compiler driver" ON)
|
||||
|
||||
set(FLANG_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR})
|
||||
if (NOT MSVC_IDE)
|
||||
set(LLVM_ENABLE_ASSERTIONS ${ENABLE_ASSERTIONS}
|
||||
@ -46,24 +41,22 @@ if (CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
|
||||
get_filename_component(LLVM_DIR_ABSOLUTE ${LLVM_DIR} REALPATH)
|
||||
list(APPEND CMAKE_MODULE_PATH ${LLVM_DIR_ABSOLUTE})
|
||||
|
||||
if(FLANG_BUILD_NEW_DRIVER)
|
||||
# Users might specify a path to CLANG_DIR that's:
|
||||
# * a full path, or
|
||||
# * a path relative to the path of this script.
|
||||
# Append the absolute path to CLANG_DIR so that find_package works in both
|
||||
# cases.
|
||||
get_filename_component(
|
||||
CLANG_DIR_ABSOLUTE
|
||||
${CLANG_DIR}
|
||||
REALPATH
|
||||
${CMAKE_CURRENT_SOURCE_DIR})
|
||||
list(APPEND CMAKE_MODULE_PATH ${CLANG_DIR_ABSOLUTE})
|
||||
# Users might specify a path to CLANG_DIR that's:
|
||||
# * a full path, or
|
||||
# * a path relative to the path of this script.
|
||||
# Append the absolute path to CLANG_DIR so that find_package works in both
|
||||
# cases.
|
||||
get_filename_component(
|
||||
CLANG_DIR_ABSOLUTE
|
||||
${CLANG_DIR}
|
||||
REALPATH
|
||||
${CMAKE_CURRENT_SOURCE_DIR})
|
||||
list(APPEND CMAKE_MODULE_PATH ${CLANG_DIR_ABSOLUTE})
|
||||
|
||||
# TODO: Remove when libclangDriver is lifted out of Clang
|
||||
find_package(Clang REQUIRED PATHS "${CLANG_DIR_ABSOLUTE}" NO_DEFAULT_PATH)
|
||||
if (NOT Clang_FOUND)
|
||||
message(FATAL_ERROR "Failed to find Clang")
|
||||
endif()
|
||||
# TODO: Remove when libclangDriver is lifted out of Clang
|
||||
find_package(Clang REQUIRED PATHS "${CLANG_DIR_ABSOLUTE}" NO_DEFAULT_PATH)
|
||||
if (NOT Clang_FOUND)
|
||||
message(FATAL_ERROR "Failed to find Clang")
|
||||
endif()
|
||||
|
||||
# If LLVM links to zlib we need the imported targets so we can too.
|
||||
@ -80,9 +73,7 @@ if (CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
|
||||
include(HandleLLVMOptions)
|
||||
include(VersionFromVCS)
|
||||
|
||||
if(FLANG_BUILD_NEW_DRIVER)
|
||||
include(AddClang)
|
||||
endif()
|
||||
include(AddClang)
|
||||
|
||||
include(TableGen)
|
||||
find_package(MLIR REQUIRED CONFIG)
|
||||
@ -206,20 +197,18 @@ endif()
|
||||
set(FLANG_INTRINSIC_MODULES_DIR ${CMAKE_BINARY_DIR}/include/flang)
|
||||
set(FLANG_INCLUDE_DIR ${FLANG_BINARY_DIR}/include)
|
||||
|
||||
if(FLANG_BUILD_NEW_DRIVER)
|
||||
# TODO: Remove when libclangDriver is lifted out of Clang
|
||||
if(FLANG_STANDALONE_BUILD)
|
||||
set(CLANG_INCLUDE_DIR ${CLANG_INCLUDE_DIRS} )
|
||||
# No need to specify TableGen output dir as that's embedded in CLANG_DIR
|
||||
else()
|
||||
set(CLANG_INCLUDE_DIR ${LLVM_MAIN_SRC_DIR}/../clang/include )
|
||||
# Specify TableGen output dir for things like DiagnosticCommonKinds.inc,
|
||||
# DiagnosticDriverKinds.inc (required for reporting diagnostics)
|
||||
set(CLANG_TABLEGEN_OUTPUT_DIR ${CMAKE_BINARY_DIR}/tools/clang/include)
|
||||
include_directories(SYSTEM ${CLANG_TABLEGEN_OUTPUT_DIR})
|
||||
endif()
|
||||
include_directories(SYSTEM ${CLANG_INCLUDE_DIR})
|
||||
# TODO: Remove when libclangDriver is lifted out of Clang
|
||||
if(FLANG_STANDALONE_BUILD)
|
||||
set(CLANG_INCLUDE_DIR ${CLANG_INCLUDE_DIRS} )
|
||||
# No need to specify TableGen output dir as that's embedded in CLANG_DIR
|
||||
else()
|
||||
set(CLANG_INCLUDE_DIR ${LLVM_MAIN_SRC_DIR}/../clang/include )
|
||||
# Specify TableGen output dir for things like DiagnosticCommonKinds.inc,
|
||||
# DiagnosticDriverKinds.inc (required for reporting diagnostics)
|
||||
set(CLANG_TABLEGEN_OUTPUT_DIR ${CMAKE_BINARY_DIR}/tools/clang/include)
|
||||
include_directories(SYSTEM ${CLANG_TABLEGEN_OUTPUT_DIR})
|
||||
endif()
|
||||
include_directories(SYSTEM ${CLANG_INCLUDE_DIR})
|
||||
|
||||
# tco tool and FIR lib output directories
|
||||
if(FLANG_STANDALONE_BUILD)
|
||||
|
@ -12,7 +12,7 @@
|
||||
:local:
|
||||
```
|
||||
|
||||
I recently added a semantic check to the f18 compiler front end. This document
|
||||
I recently added a semantic check to the Flang compiler front end. This document
|
||||
describes my thought process and the resulting implementation.
|
||||
|
||||
For more information about the compiler, start with the
|
||||
@ -67,7 +67,7 @@ of the call to `intentOutFunc()`:
|
||||
|
||||
I also used this program to produce a parse tree for the program using the command:
|
||||
```bash
|
||||
f18 -fdebug-dump-parse-tree -fsyntax-only testfun.f90
|
||||
flang-new -fc1 -fdebug-dump-parse-tree testfun.f90
|
||||
```
|
||||
|
||||
Here's the relevant fragment of the parse tree produced by the compiler:
|
||||
@ -295,7 +295,7 @@ In `lib/Semantics/check-do.cpp`, I added an (almost empty) implementation:
|
||||
I then built the compiler with these changes and ran it on my test program.
|
||||
This time, I made sure to invoke semantic checking. Here's the command I used:
|
||||
```bash
|
||||
f18 -fdebug-resolve-names -fdebug-dump-parse-tree -funparse-with-symbols testfun.f90
|
||||
flang-new -fc1 -fdebug-unparse-with-symbols testfun.f90
|
||||
```
|
||||
|
||||
This produced the output:
|
||||
@ -361,7 +361,7 @@ I noted that a `SymbolSet` did not actually contain an
|
||||
full `semantics::Symbol` objects into the set. Ideally, we would be able to create an
|
||||
`std::set<Symbol &>` (a set of C++ references to symbols). But C++ doesn't
|
||||
support sets that contain references. This limitation is part of the rationale
|
||||
for the f18 implementation of type `common::Reference`, which is defined in
|
||||
for the Flang implementation of type `common::Reference`, which is defined in
|
||||
`include/flang/Common/reference.h`.
|
||||
|
||||
`SymbolRef`, the specialization of the template `common::Reference` for
|
||||
|
@ -6,6 +6,11 @@
|
||||
|
||||
-->
|
||||
|
||||
# Intro
|
||||
This document goes briefly over compiler phases in Flang. It focuses on the
|
||||
internal implementation and as such, it is intended for Flang developers rather
|
||||
than end-users.
|
||||
|
||||
# Overview of Compiler Phases
|
||||
|
||||
```eval_rst
|
||||
@ -33,7 +38,7 @@ See: [Preprocessing.md](Preprocessing.md).
|
||||
|
||||
**Entry point:** `parser::Parsing::Prescan`
|
||||
|
||||
**Command:** `f18 -E src.f90` dumps the cooked character stream
|
||||
**Command:** `flang-new -fc1 -E src.f90` dumps the cooked character stream
|
||||
|
||||
## Parse
|
||||
|
||||
@ -46,8 +51,8 @@ See: [Preprocessing.md](Preprocessing.md).
|
||||
**Entry point:** `parser::Parsing::Parse`
|
||||
|
||||
**Command:**
|
||||
- `f18 -fdebug-dump-parse-tree -fsyntax-only src.f90` dumps the parse tree
|
||||
- `f18 -funparse src.f90` converts the parse tree to normalized Fortran
|
||||
- `flang-new -fc1 -fdebug-dump-parse-tree src.f90` dumps the parse tree
|
||||
- `flang-new -fc1 -fdebug-unparse src.f90` converts the parse tree to normalized Fortran
|
||||
|
||||
## Validate Labels and Canonicalize Do Statements
|
||||
|
||||
@ -74,7 +79,7 @@ See: [Preprocessing.md](Preprocessing.md).
|
||||
|
||||
**Entry points:** `semantics::ResolveNames`, `semantics::RewriteParseTree`
|
||||
|
||||
**Command:** `f18 -fdebug-dump-symbols -fsyntax-only src.f90` dumps the
|
||||
**Command:** `flang-new -fc1 -fdebug-dump-symbols src.f90` dumps the
|
||||
tree of scopes and symbols in each scope
|
||||
|
||||
## Check DO CONCURRENT Constraints
|
||||
|
@ -184,8 +184,7 @@ public:
|
||||
useAnalyzedObjectsForUnparse_ = flag;
|
||||
}
|
||||
|
||||
/// Set the Fortran options to predifined defaults. These defaults are
|
||||
/// consistend with f18/f18.cpp.
|
||||
/// Set the Fortran options to predefined defaults.
|
||||
// TODO: We should map frontendOpts_ to parserOpts_ instead. For that, we
|
||||
// need to extend frontendOpts_ first. Next, we need to add the corresponding
|
||||
// compiler driver options in libclangDriver.
|
||||
|
@ -87,10 +87,6 @@ enum ActionKind {
|
||||
/// \return True if the file extension should be processed as fixed form
|
||||
bool isFixedFormSuffix(llvm::StringRef suffix);
|
||||
|
||||
// TODO: Find a more suitable location for this. Added for compability with
|
||||
// f18.cpp (this is equivalent to `asFortran` defined there).
|
||||
Fortran::parser::AnalyzedObjectsAsFortran getBasicAsFortran();
|
||||
|
||||
/// \param suffix The file extension
|
||||
/// \return True if the file extension should be processed as free form
|
||||
bool isFreeFormSuffix(llvm::StringRef suffix);
|
||||
|
@ -4,10 +4,7 @@ add_subdirectory(Decimal)
|
||||
add_subdirectory(Lower)
|
||||
add_subdirectory(Parser)
|
||||
add_subdirectory(Semantics)
|
||||
|
||||
if(FLANG_BUILD_NEW_DRIVER)
|
||||
add_subdirectory(Frontend)
|
||||
add_subdirectory(FrontendTool)
|
||||
endif()
|
||||
add_subdirectory(Frontend)
|
||||
add_subdirectory(FrontendTool)
|
||||
|
||||
add_subdirectory(Optimizer)
|
||||
|
@ -571,7 +571,6 @@ void CompilerInvocation::collectMacroDefinitions() {
|
||||
void CompilerInvocation::SetDefaultFortranOpts() {
|
||||
auto &fortranOptions = fortranOpts();
|
||||
|
||||
// These defaults are based on the defaults in f18/f18.cpp.
|
||||
std::vector<std::string> searchDirectories{"."s};
|
||||
fortranOptions.searchDirectories = searchDirectories;
|
||||
fortranOptions.isFixedForm = false;
|
||||
|
@ -32,13 +32,9 @@ set(FLANG_TEST_PARAMS
|
||||
flang_site_config=${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg.py)
|
||||
|
||||
set(FLANG_TEST_DEPENDS
|
||||
f18 FileCheck count not module_files fir-opt tco
|
||||
flang-new FileCheck count not module_files fir-opt tco
|
||||
)
|
||||
|
||||
if (FLANG_BUILD_NEW_DRIVER)
|
||||
list(APPEND FLANG_TEST_DEPENDS flang-new)
|
||||
endif()
|
||||
|
||||
if (FLANG_INCLUDE_TESTS)
|
||||
if (FLANG_GTEST_AVAIL)
|
||||
list(APPEND FLANG_TEST_DEPENDS FlangUnitTests)
|
||||
|
@ -1,12 +0,0 @@
|
||||
! REQUIRES: old-flang-driver
|
||||
|
||||
! RUN: %flang -h 2>&1 | FileCheck %s
|
||||
! RUN: %flang -help 2>&1 | FileCheck %s
|
||||
! RUN: %flang --help 2>&1 | FileCheck %s
|
||||
! RUN: %flang -? 2>&1 | FileCheck %s
|
||||
|
||||
! CHECK: f18: LLVM Fortran compiler
|
||||
|
||||
! CHECK: -help print this again
|
||||
! CHECK: Unrecognised options are passed through to the external compiler
|
||||
! CHECK: set by F18_FC (see defaults).
|
@ -40,10 +40,7 @@ config.excludes = ['Inputs', 'CMakeLists.txt', 'README.txt', 'LICENSE.txt']
|
||||
|
||||
# If the new Flang driver is enabled, add the corresponding feature to
|
||||
# config.
|
||||
if config.include_flang_new_driver_test:
|
||||
config.available_features.add('new-flang-driver')
|
||||
else:
|
||||
config.available_features.add('old-flang-driver')
|
||||
config.available_features.add('new-flang-driver')
|
||||
|
||||
# test_source_root: The root path where tests are located.
|
||||
config.test_source_root = os.path.dirname(__file__)
|
||||
@ -64,16 +61,10 @@ if config.flang_standalone_build:
|
||||
|
||||
# For each occurrence of a flang tool name, replace it with the full path to
|
||||
# the build directory holding that tool.
|
||||
tools = []
|
||||
if config.include_flang_new_driver_test:
|
||||
tools.append(ToolSubst('%flang', command=FindTool('flang-new'), unresolved='fatal'))
|
||||
tools.append(ToolSubst('%flang_fc1', command=FindTool('flang-new'),
|
||||
extra_args=['-fc1'], unresolved='fatal'))
|
||||
else:
|
||||
tools.append(ToolSubst('%flang', command=FindTool('f18'),
|
||||
unresolved='fatal'))
|
||||
tools.append(ToolSubst('%flang_fc1', command=FindTool('f18'),
|
||||
unresolved='fatal'))
|
||||
tools = [
|
||||
ToolSubst('%flang', command=FindTool('flang-new'), unresolved='fatal'),
|
||||
ToolSubst('%flang_fc1', command=FindTool('flang-new'), extra_args=['-fc1'],
|
||||
unresolved='fatal')]
|
||||
|
||||
# Define some variables to help us test that the flang runtime doesn't depend on
|
||||
# the C++ runtime libraries. For this we need a C compiler. If for some reason
|
||||
|
@ -14,11 +14,6 @@ config.python_executable = "@PYTHON_EXECUTABLE@"
|
||||
config.flang_standalone_build = @FLANG_STANDALONE_BUILD@
|
||||
config.cc = "@CMAKE_C_COMPILER@"
|
||||
|
||||
# Control the regression test for flang-new driver
|
||||
import lit.util
|
||||
config.include_flang_new_driver_test = \
|
||||
lit.util.pythonize_bool("@FLANG_BUILD_NEW_DRIVER@")
|
||||
|
||||
# Support substitution of the tools_dir with user parameters. This is
|
||||
# used when we can't determine the tool dir at configuration time.
|
||||
try:
|
||||
|
@ -7,9 +7,7 @@
|
||||
#===------------------------------------------------------------------------===#
|
||||
|
||||
add_subdirectory(f18)
|
||||
if(FLANG_BUILD_NEW_DRIVER)
|
||||
add_subdirectory(flang-driver)
|
||||
endif()
|
||||
add_subdirectory(flang-driver)
|
||||
add_subdirectory(tco)
|
||||
add_subdirectory(f18-parse-demo)
|
||||
add_subdirectory(fir-opt)
|
||||
|
@ -3,19 +3,6 @@ set(LLVM_LINK_COMPONENTS
|
||||
FrontendOpenMP
|
||||
Support
|
||||
)
|
||||
add_flang_tool(f18
|
||||
dump.cpp
|
||||
f18.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(f18
|
||||
PRIVATE
|
||||
FortranCommon
|
||||
FortranParser
|
||||
FortranEvaluate
|
||||
FortranSemantics
|
||||
FortranLower
|
||||
)
|
||||
|
||||
set(MODULES
|
||||
"__fortran_builtins"
|
||||
@ -30,11 +17,6 @@ set(MODULES
|
||||
"__fortran_type_info"
|
||||
)
|
||||
|
||||
target_include_directories(f18
|
||||
PRIVATE
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
)
|
||||
|
||||
# Create module files directly from the top-level module source directory
|
||||
foreach(filename ${MODULES})
|
||||
set(base ${FLANG_INTRINSIC_MODULES_DIR}/${filename})
|
||||
@ -47,9 +29,9 @@ foreach(filename ${MODULES})
|
||||
endif()
|
||||
add_custom_command(OUTPUT ${base}.mod
|
||||
COMMAND ${CMAKE_COMMAND} -E make_directory ${FLANG_INTRINSIC_MODULES_DIR}
|
||||
COMMAND f18 -fsyntax-only -module-dir ${FLANG_INTRINSIC_MODULES_DIR}
|
||||
COMMAND flang-new -fc1 -fsyntax-only -module-dir ${FLANG_INTRINSIC_MODULES_DIR}
|
||||
${FLANG_SOURCE_DIR}/module/${filename}.f90
|
||||
DEPENDS f18 ${FLANG_SOURCE_DIR}/module/${filename}.f90 ${depends}
|
||||
DEPENDS flang-new ${FLANG_SOURCE_DIR}/module/${filename}.f90 ${depends}
|
||||
)
|
||||
add_custom_command(OUTPUT ${base}.f18.mod
|
||||
DEPENDS ${base}.mod
|
||||
@ -60,15 +42,10 @@ endforeach()
|
||||
|
||||
add_custom_target(module_files ALL DEPENDS ${MODULE_FILES})
|
||||
|
||||
install(TARGETS f18 DESTINATION bin)
|
||||
|
||||
set(FLANG_DEFAULT_DRIVER "flang-new")
|
||||
if (NOT FLANG_BUILD_NEW_DRIVER)
|
||||
set(FLANG_DEFAULT_DRIVER "f18")
|
||||
endif()
|
||||
|
||||
# This flang shell script will only work in a POSIX shell.
|
||||
if (NOT WIN32)
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/flang.in ${CMAKE_BINARY_DIR}/bin/flang @ONLY)
|
||||
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/flang
|
||||
DESTINATION ${CMAKE_BINARY_DIR}/bin
|
||||
FILE_PERMISSIONS OWNER_EXECUTE OWNER_READ OWNER_WRITE)
|
||||
install(PROGRAMS ${CMAKE_BINARY_DIR}/bin/flang DESTINATION bin)
|
||||
endif()
|
||||
|
@ -1,849 +0,0 @@
|
||||
//===-- 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/FileUtilities.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 lineDirectives{true}; // -P disables
|
||||
bool syntaxOnly{false};
|
||||
bool dumpProvenance{false};
|
||||
bool noReformat{false}; // -E -fno-reformat
|
||||
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 useAnalyzedObjectsForUnparse{true};
|
||||
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 (options.prescanAndReformat) {
|
||||
parsing.messages().Emit(llvm::errs(), allCookedSources);
|
||||
if (driver.noReformat) {
|
||||
parsing.DumpCookedChars(llvm::outs());
|
||||
} else {
|
||||
parsing.EmitPreprocessedSource(llvm::outs(), driver.lineDirectives);
|
||||
}
|
||||
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, driver.debugModuleWriter};
|
||||
semantics.Perform();
|
||||
Fortran::semantics::RuntimeDerivedTypeTables tables;
|
||||
if (!semantics.AnyFatalError()) {
|
||||
tables =
|
||||
Fortran::semantics::BuildRuntimeDerivedTypeTables(semanticsContext);
|
||||
if (!tables.schemata) {
|
||||
llvm::errs() << driver.prefix
|
||||
<< "could not find module file for __fortran_type_info\n";
|
||||
}
|
||||
}
|
||||
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 {};
|
||||
}
|
||||
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) {
|
||||
// Prepare the output stream
|
||||
std::unique_ptr<llvm::raw_fd_ostream> os;
|
||||
std::string outputFile = "-";
|
||||
if (!driver.outputPath.empty()) {
|
||||
outputFile = driver.outputPath;
|
||||
}
|
||||
|
||||
std::error_code EC;
|
||||
os.reset(new llvm::raw_fd_ostream(
|
||||
outputFile, EC, llvm::sys::fs::OF_TextWithCRLF));
|
||||
if (EC) {
|
||||
llvm::errs() << EC.message() << "\n";
|
||||
std::exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
Unparse(*os, parseTree, driver.encoding, true /*capitalize*/,
|
||||
options.features.IsEnabled(
|
||||
Fortran::common::LanguageFeature::BackslashEscapes),
|
||||
nullptr /* action before each statement */,
|
||||
driver.useAnalyzedObjectsForUnparse ? &asFortran : nullptr);
|
||||
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.useAnalyzedObjectsForUnparse ? &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;
|
||||
}
|
||||
|
||||
// Generate the path to look for intrinsic modules
|
||||
static std::string getIntrinsicDir() {
|
||||
// TODO: Find a system independent API
|
||||
llvm::SmallString<128> driverPath;
|
||||
driverPath.assign(llvm::sys::fs::getMainExecutable(nullptr, nullptr));
|
||||
llvm::sys::path::remove_filename(driverPath);
|
||||
driverPath.append("/../include/flang/");
|
||||
return std::string(driverPath);
|
||||
}
|
||||
|
||||
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};
|
||||
|
||||
// Add the default intrinsic module directory to the list of search
|
||||
// directories
|
||||
driver.searchDirectories.push_back(getIntrinsicDir());
|
||||
|
||||
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() || arg == "-Xflang") {
|
||||
} 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 -fno-reformat 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" ||
|
||||
arg == "-std=f2018" || arg == "-pedantic") {
|
||||
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.find("-W") != std::string::npos) {
|
||||
if (arg == "-Werror")
|
||||
driver.warningsAreErrors = true;
|
||||
} else if (arg == "-ed") {
|
||||
options.features.Enable(Fortran::common::LanguageFeature::OldDebugLines);
|
||||
} else if (arg == "-E") {
|
||||
options.prescanAndReformat = true;
|
||||
} else if (arg == "-P") {
|
||||
driver.lineDirectives = false;
|
||||
} else if (arg == "-fno-reformat") {
|
||||
driver.noReformat = 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" ||
|
||||
arg == "-fimplicit-none") {
|
||||
options.features.Enable(
|
||||
Fortran::common::LanguageFeature::ImplicitNoneTypeAlways);
|
||||
} else if (arg == "-fno-implicit-none") {
|
||||
options.features.Enable(
|
||||
Fortran::common::LanguageFeature::ImplicitNoneTypeAlways, false);
|
||||
} 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 == "-fdebug-unparse-no-sema") {
|
||||
driver.debugNoSemantics = true;
|
||||
driver.dumpUnparse = true;
|
||||
} else if (arg == "-fdebug-dump-parse-tree-no-sema") {
|
||||
driver.debugNoSemantics = true;
|
||||
driver.dumpParseTree = true;
|
||||
driver.syntaxOnly = 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 == "-fno-analyzed-objects-for-unparse") {
|
||||
driver.useAnalyzedObjectsForUnparse = false;
|
||||
} 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" ||
|
||||
arg == "-fintrinsic-modules-path") {
|
||||
// prepend to the list of search directories
|
||||
driver.searchDirectories.insert(
|
||||
driver.searchDirectories.begin(), 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() << "error: invalid value '" << args.front()
|
||||
<< "' in 'fget-definition'" << '\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;
|
||||
}
|
@ -10,7 +10,7 @@
|
||||
# experimenting. You should be able to use it as a regular compiler driver. It
|
||||
# will:
|
||||
# * run Flang's compiler driver to unparse the input source files
|
||||
# * use the external compiler (defined via F18_FC environment variable) to
|
||||
# * use the external compiler (defined via FLANG_FC environment variable) to
|
||||
# compile the unparsed source files
|
||||
#===------------------------------------------------------------------------===#
|
||||
set -euo pipefail
|
||||
@ -182,7 +182,7 @@ categorise_opts()
|
||||
|
||||
if
|
||||
# The options claimed by Flang. This list needs to be compatible with
|
||||
# what's supported by Flang's compiler driver (i.e. `flang-new` and f18).
|
||||
# what's supported by Flang's compiler driver (i.e. `flang-new`).
|
||||
[[ $opt == "-cpp" ]] ||
|
||||
[[ $opt =~ ^-D.* ]] ||
|
||||
[[ $opt == "-E" ]] ||
|
||||
@ -244,7 +244,18 @@ preprocess() {
|
||||
local -n other_srcs=$2
|
||||
local -n opts=$3
|
||||
|
||||
local -r ext_fc="${F18_FC:-gfortran}"
|
||||
local ext_fc=""
|
||||
if [[ -v $FLANG_FC ]]; then
|
||||
ext_fc="${FLANG_FC}"
|
||||
elif [[ -v $F18_FC ]]; then
|
||||
# We support F18_FC for backwards compatibility.
|
||||
ext_fc="${F18_FC}"
|
||||
else
|
||||
ext_fc=gfortran
|
||||
fi
|
||||
|
||||
|
||||
local ext_fc="${FLANG_FC:-gfortran}"
|
||||
local -r wd=$(cd "$(dirname "$0")/.." && pwd)
|
||||
|
||||
# Use the provided output file name.
|
||||
@ -254,9 +265,9 @@ preprocess() {
|
||||
|
||||
# Preprocess fortran sources using Flang
|
||||
for idx in "${!fortran_srcs[@]}"; do
|
||||
if ! "$wd/bin/@FLANG_DEFAULT_DRIVER@" -E "${opts[@]}" "${fortran_srcs[$idx]}" ${output_definition:+$output_definition}
|
||||
if ! "$wd/bin/flang-new" -E "${opts[@]}" "${fortran_srcs[$idx]}" ${output_definition:+$output_definition}
|
||||
then status=$?
|
||||
echo flang: in "$PWD", @FLANG_DEFAULT_DRIVER@ failed with exit status $status: "$wd/bin/@FLANG_DEFAULT_DRIVER@" "${opts[@]}" "$@" >&2
|
||||
echo flang: in "$PWD", flang-new failed with exit status $status: "$wd/bin/flang-new" "${opts[@]}" "$@" >&2
|
||||
exit $status
|
||||
fi
|
||||
done
|
||||
@ -323,8 +334,7 @@ main() {
|
||||
# NOTE: We need `-fc1` to make sure that the frontend driver rather than
|
||||
# compiler driver is used. We also need to make sure that that's the first
|
||||
# flag that the driver will see (otherwise it assumes compiler/toolchain
|
||||
# driver mode).`f18` will just ignore this flag when uparsing, so it's fine
|
||||
# to add it here unconditionally.
|
||||
# driver mode).
|
||||
local flang_options=("-fc1")
|
||||
# Options for the external Fortran Compiler
|
||||
local ext_fc_options=()
|
||||
@ -349,11 +359,11 @@ main() {
|
||||
[[ ! -z ${INTRINSICS_MOD_DIR} ]] && flang_options+=("-intrinsics-module-directory ${INTRINSICS_MOD_DIR}")
|
||||
for idx in "${!fortran_source_files[@]}"; do
|
||||
set +e
|
||||
"$wd/bin/@FLANG_DEFAULT_DRIVER@" "${flang_options[@]}" "${fortran_source_files[$idx]}" -o "${unparsed_file_base}_${idx}.f90"
|
||||
"$wd/bin/flang-new" "${flang_options[@]}" "${fortran_source_files[$idx]}" -o "${unparsed_file_base}_${idx}.f90"
|
||||
ret_status=$?
|
||||
set -e
|
||||
if [[ $ret_status != 0 ]]; then
|
||||
echo flang: in "$PWD", @FLANG_DEFAULT_DRIVER@ failed with exit status "$ret_status": "$wd/bin/@FLANG_DEFAULT_DRIVER@" "${flang_options[@]}" "$@" >&2
|
||||
echo flang: in "$PWD", flang-new failed with exit status "$ret_status": "$wd/bin/flang-new" "${flang_options[@]}" "$@" >&2
|
||||
exit "$ret_status"
|
||||
fi
|
||||
done
|
@ -40,7 +40,4 @@ add_subdirectory(Optimizer)
|
||||
add_subdirectory(Decimal)
|
||||
add_subdirectory(Evaluate)
|
||||
add_subdirectory(Runtime)
|
||||
|
||||
if (FLANG_BUILD_NEW_DRIVER)
|
||||
add_subdirectory(Frontend)
|
||||
endif()
|
||||
add_subdirectory(Frontend)
|
||||
|
@ -81,9 +81,8 @@ if ("flang" IN_LIST LLVM_ENABLE_PROJECTS)
|
||||
list(APPEND LLVM_ENABLE_PROJECTS "mlir")
|
||||
endif()
|
||||
|
||||
option(FLANG_BUILD_NEW_DRIVER "Build the flang compiler driver" ON)
|
||||
if (FLANG_BUILD_NEW_DRIVER AND NOT "clang" IN_LIST LLVM_ENABLE_PROJECTS)
|
||||
message(FATAL_ERROR "Clang is not enabled, but it's required by the new Flang driver")
|
||||
if (NOT "clang" IN_LIST LLVM_ENABLE_PROJECTS)
|
||||
message(FATAL_ERROR "Clang is not enabled, but is required for the Flang driver")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user