diff --git a/flang/CMakeLists.txt b/flang/CMakeLists.txt --- a/flang/CMakeLists.txt +++ b/flang/CMakeLists.txt @@ -108,7 +108,6 @@ endif() link_directories("${LLVM_LIBRARY_DIR}") - set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib${LLVM_LIBDIR_SUFFIX}) @@ -138,6 +137,14 @@ endif() endif() +# Add Clang libraries used by the flang-tmp driver +set(CLANG_MAIN_SRC_DIR ${LLVM_MAIN_SRC_DIR}/../clang/include ) # --src-root +set(CLANG_INCLUDE_DIR ${LLVM_MAIN_SRC_DIR}/../clang/include ) # --includedir +set(CLANG_TABLEGEN_OUTPUT_DIR ${CMAKE_BINARY_DIR}/tools/clang/include) +set(CLANG_TABLEGEN_EXE $) +include_directories(SYSTEM ${CLANG_INCLUDE_DIR}) +include_directories(SYSTEM ${CLANG_TABLEGEN_OUTPUT_DIR}) + if(LINK_WITH_FIR) # tco tool and FIR lib output directories set(LLVM_RUNTIME_OUTPUT_INTDIR ${CMAKE_BINARY_DIR}/bin) diff --git a/flang/include/flang/Frontend/TextDiagnosticPrinter.h b/flang/include/flang/Frontend/TextDiagnosticPrinter.h new file mode 100644 --- /dev/null +++ b/flang/include/flang/Frontend/TextDiagnosticPrinter.h @@ -0,0 +1,27 @@ +//===--- TextDiagnosticPrinter.h - Text Diagnostic Client -------*- C++ -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// This is a dummy implemenation of concrete diagnostic client for flang. +// TODO: Print diagnostics to standard error. +// +//===----------------------------------------------------------------------===// + +#include "clang/Basic/Diagnostic.h" +#include "llvm/ADT/IntrusiveRefCntPtr.h" + +class TextDiagnosticPrinter : public clang::DiagnosticConsumer { + llvm::raw_ostream &OS; + clang::IntrusiveRefCntPtr DiagOpts; + + unsigned OwnsOutputStream : 1; + +public: + TextDiagnosticPrinter(llvm::raw_ostream &os, clang::DiagnosticOptions *diags, + bool OwnsOutputStream = false); + ~TextDiagnosticPrinter() override; +}; diff --git a/flang/lib/CMakeLists.txt b/flang/lib/CMakeLists.txt --- a/flang/lib/CMakeLists.txt +++ b/flang/lib/CMakeLists.txt @@ -1,6 +1,7 @@ add_subdirectory(Common) add_subdirectory(Evaluate) add_subdirectory(Decimal) +add_subdirectory(Frontend) add_subdirectory(Lower) add_subdirectory(Parser) add_subdirectory(Semantics) diff --git a/flang/lib/Frontend/CMakeLists.txt b/flang/lib/Frontend/CMakeLists.txt new file mode 100644 --- /dev/null +++ b/flang/lib/Frontend/CMakeLists.txt @@ -0,0 +1,16 @@ +add_library(flangFrontend + TextDiagnosticPrinter.cpp + ) + +target_link_libraries(flangFrontend + LLVMOption + LLVMSupport + clangBasic + clangDriver +) + +install (TARGETS flangFrontend + ARCHIVE DESTINATION lib + LIBRARY DESTINATION lib + RUNTIME DESTINATION bin +) diff --git a/flang/lib/Frontend/TextDiagnosticPrinter.cpp b/flang/lib/Frontend/TextDiagnosticPrinter.cpp new file mode 100644 --- /dev/null +++ b/flang/lib/Frontend/TextDiagnosticPrinter.cpp @@ -0,0 +1,26 @@ +//===--- TextDiagnosticPrinter.cpp - Diagnostic Printer -------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// This diagnostic client ATM only creates and destroys the object. +// TODO: Diagnostic client should print the diagnostic messages for flang. +// +//===----------------------------------------------------------------------===// + +#include "flang/Frontend/TextDiagnosticPrinter.h" +#include "clang/Basic/DiagnosticOptions.h" +#include "llvm/Support/raw_ostream.h" + +TextDiagnosticPrinter::TextDiagnosticPrinter(llvm::raw_ostream &os, + clang::DiagnosticOptions *diags, + bool _OwnsOutputStream) + : OS(os), DiagOpts(diags), OwnsOutputStream(_OwnsOutputStream) {} + +TextDiagnosticPrinter::~TextDiagnosticPrinter() { + if (OwnsOutputStream) + delete &OS; +} diff --git a/flang/test/Driver/flang.F90 b/flang/test/Driver/flang.F90 new file mode 100644 --- /dev/null +++ b/flang/test/Driver/flang.F90 @@ -0,0 +1,51 @@ +! Check that flang -fc1 is invoke. + +! This is a copy of flang.f90 because the driver has logic in it which +! differentiates between F90 and f90 files. Flang will not treat these files +! differently. + +! Test various output types: +! * -E +! * -fsyntax-only +! * -emit-llvm -S +! * -emit-llvm +! * -S +! * (no type specified, resulting in an object file) + +! All invocations should begin with flang-tmp -fc1. +! ALL-LABEL: "{{[^"]*}}flang-tmp" "-fc1" + +! Check that f90 files are not treated as "previously preprocessed". + +! RUN: %flang-tmp -### -E %s 2>&1 | FileCheck --check-prefixes=ALL,CHECK-E %s +! CHECK-E-NOT: previously preprocessed input +! CHECK-E-DAG: "-E" +! CHECK-E-DAG: "-o" "-" + +! RUN: %flang-tmp -### -emit-ast %s 2>&1 | FileCheck --check-prefixes=ALL,CHECK-EMIT-AST %s +! CHECK-EMIT-AST-DAG: "-triple" +! CHECK-EMIT-AST-DAG: "-emit-ast" +! CHECK-EMIT-AST-DAG: "-o" "{{[^"]*}}.ast" + +! RUN: %flang-tmp -### -fsyntax-only %s 2>&1 | FileCheck --check-prefixes=ALL,CHECK-SYNTAX-ONLY %s +! CHECK-SYNTAX-ONLY-NOT: "-o" +! CHECK-SYNTAX-ONLY-DAG: "-fsyntax-only" + +! RUN: %flang-tmp -### -emit-llvm -S %s 2>&1 | FileCheck --check-prefixes=ALL,CHECK-EMIT-LLVM-IR %s +! CHECK-EMIT-LLVM-IR-DAG: "-emit-llvm" +! CHECK-EMIT-LLVM-IR-DAG: "-o" "{{[^"]*}}.ll" + +! RUN: %flang-tmp -### -emit-llvm %s 2>&1 | FileCheck --check-prefixes=ALL,CHECK-EMIT-LLVM-BC %s +! CHECK-EMIT-LLVM-BC-DAG: "-emit-llvm-bc" +! CHECK-EMIT-LLVM-BC-DAG: "-o" "{{[^"]*}}.bc" + +! RUN: %flang-tmp -### -S %s 2>&1 | FileCheck --check-prefixes=ALL,CHECK-S %s +! CHECK-S-DAG: "-S" +! CHECK-S-DAG: "-o" "{{[^"]*}}.s" + +! RUN: %flang-tmp -### %s 2>&1 | FileCheck --check-prefixes=ALL,CHECK-EMIT-OBJ %s +! CHECK-EMIT-OBJ-DAG: "-emit-obj" +! CHECK-EMIT-OBJ-DAG: "-o" "{{[^"]*}}.o" + +! Should end in the input file. +! ALL: "{{.*}}flang.F90"{{$}} diff --git a/flang/test/Driver/flang.f90 b/flang/test/Driver/flang.f90 new file mode 100644 --- /dev/null +++ b/flang/test/Driver/flang.f90 @@ -0,0 +1,51 @@ +! Check that flang -fc1 is invoked when in. + +! This is a copy of flang.F90 because the driver has logic in it which +! differentiates between F90 and f90 files. Flang will not treat these files +! differently. + +! Test various output types: +! * -E +! * -fsyntax-only +! * -emit-llvm -S +! * -emit-llvm +! * -S +! * (no type specified, resulting in an object file) + +! All invocations should begin with flang-tmp -fc1. +! ALL-LABEL: "{{[^"]*}}flang-tmp" "-fc1" + +! Check that f90 files are not treated as "previously preprocessed" + +! RUN: %flang-tmp -### -E %s 2>&1 | FileCheck --check-prefixes=ALL,CHECK-E %s +! CHECK-E-NOT: previously preprocessed input +! CHECK-E-DAG: "-E" +! CHECK-E-DAG: "-o" "-" + +! RUN: %flang-tmp -### -emit-ast %s 2>&1 | FileCheck --check-prefixes=ALL,CHECK-EMIT-AST %s +! CHECK-EMIT-AST-DAG: "-triple" +! CHECK-EMIT-AST-DAG: "-emit-ast" +! CHECK-EMIT-AST-DAG: "-o" "{{[^"]*}}.ast" + +! RUN: %flang-tmp -### -fsyntax-only %s 2>&1 | FileCheck --check-prefixes=ALL,CHECK-SYNTAX-ONLY %s +! CHECK-SYNTAX-ONLY-NOT: "-o" +! CHECK-SYNTAX-ONLY-DAG: "-fsyntax-only" + +! RUN: %flang-tmp -### -emit-llvm -S %s 2>&1 | FileCheck --check-prefixes=ALL,CHECK-EMIT-LLVM-IR %s +! CHECK-EMIT-LLVM-IR-DAG: "-emit-llvm" +! CHECK-EMIT-LLVM-IR-DAG: "-o" "{{[^"]*}}.ll" + +! RUN: %flang-tmp -### -emit-llvm %s 2>&1 | FileCheck --check-prefixes=ALL,CHECK-EMIT-LLVM-BC %s +! CHECK-EMIT-LLVM-BC-DAG: "-emit-llvm-bc" +! CHECK-EMIT-LLVM-BC-DAG: "-o" "{{[^"]*}}.bc" + +! RUN: %flang-tmp -### -S %s 2>&1 | FileCheck --check-prefixes=ALL,CHECK-S %s +! CHECK-S-DAG: "-S" +! CHECK-S-DAG: "-o" "{{[^"]*}}.s" + +! RUN: %flang-tmp -### %s 2>&1 | FileCheck --check-prefixes=ALL,CHECK-EMIT-OBJ %s +! CHECK-EMIT-OBJ-DAG: "-emit-obj" +! CHECK-EMIT-OBJ-DAG: "-o" "{{[^"]*}}.o" + +! Should end in the input file. +! ALL: "{{.*}}flang.f90"{{$}} diff --git a/flang/test/lit.cfg.py b/flang/test/lit.cfg.py --- a/flang/test/lit.cfg.py +++ b/flang/test/lit.cfg.py @@ -64,6 +64,7 @@ flang_includes = "-I" + config.flang_intrinsic_modules_dir tools = [ToolSubst('%flang', command=FindTool('flang'), unresolved='fatal'), + ToolSubst('%flang-tmp', command=FindTool('flang-tmp'), unresolved='fatal'), ToolSubst('%f18', command=FindTool('f18'), unresolved='fatal'), ToolSubst('%f18_with_includes', command=FindTool('f18'), extra_args=[flang_includes], unresolved='fatal')] diff --git a/flang/tools/CMakeLists.txt b/flang/tools/CMakeLists.txt --- a/flang/tools/CMakeLists.txt +++ b/flang/tools/CMakeLists.txt @@ -7,6 +7,7 @@ #===------------------------------------------------------------------------===# add_subdirectory(f18) +add_subdirectory(flang) if(LINK_WITH_FIR) add_subdirectory(tco) endif() diff --git a/flang/tools/flang/CMakeLists.txt b/flang/tools/flang/CMakeLists.txt new file mode 100644 --- /dev/null +++ b/flang/tools/flang/CMakeLists.txt @@ -0,0 +1,23 @@ +# Infrastructure to build flang driver entry point. Flang driver dependes on +# LLVM libraries. + +# Set your project compile flags. +link_directories(${LLVM_LIBRARY_DIR}) + +add_executable(flang-tmp + driver.cpp +) + +# Link against LLVM and Clang libraries +target_link_libraries(flang-tmp + PRIVATE + ${LLVM_COMMON_LIBS} + flangFrontend + clangDriver + clangBasic + LLVMSupport + LLVMTarget + LLVMOption +) + +install(TARGETS flang-tmp DESTINATION bin) diff --git a/flang/tools/flang/driver.cpp b/flang/tools/flang/driver.cpp new file mode 100644 --- /dev/null +++ b/flang/tools/flang/driver.cpp @@ -0,0 +1,71 @@ +//===-- main.cpp - Flang e Driver -----------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// This is the entry point to the flang driver; it is a thin wrapper +// for functionality in the Driver flang library. +// +//===----------------------------------------------------------------------===// +#include "flang/Frontend/TextDiagnosticPrinter.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/DiagnosticIDs.h" +#include "clang/Basic/DiagnosticOptions.h" +#include "clang/Driver/Compilation.h" +#include "clang/Driver/Driver.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/IntrusiveRefCntPtr.h" +#include "llvm/Option/ArgList.h" +#include "llvm/Support/Host.h" +#include "llvm/Support/InitLLVM.h" +#include "llvm/Support/VirtualFileSystem.h" + +std::string GetExecutablePath(const char *Argv0) { + // This just needs to be some symbol in the binary; C++ doesn't + // allow taking the address of ::main however. + void *P = (void *)(intptr_t)GetExecutablePath; + return llvm::sys::fs::getMainExecutable(Argv0, P); +} + +// This lets us create the DiagnosticsEngine with a properly-filled-out +// DiagnosticOptions instance +static clang::DiagnosticOptions * +CreateAndPopulateDiagOpts(llvm::ArrayRef argv) { + auto *DiagOpts = new clang::DiagnosticOptions; + return DiagOpts; +} + +int main(int argc_, const char **argv_) { + + llvm::InitLLVM X(argc_, argv_); + llvm::SmallVector argv(argv_, argv_ + argc_); + + clang::driver::ParsedClangName TargetandMode("flang", "--driver-mode=flang"); + std::string Path = GetExecutablePath(argv[0]); + + // Give to the driver the name of the frontend + // It is a temporary solution for a temporary problem + // To be removed when flang-tmp is the main driver + argv.push_back("-fortran-fe"); + argv.push_back(basename(argv[0])); + + llvm::IntrusiveRefCntPtr DiagOpts = + CreateAndPopulateDiagOpts(argv); + llvm::IntrusiveRefCntPtr DiagID( + new clang::DiagnosticIDs()); + TextDiagnosticPrinter *DiagClient = + new TextDiagnosticPrinter(llvm::errs(), &*DiagOpts); + clang::DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagClient); + + clang::driver::Driver TheDriver(Path, llvm::sys::getDefaultTargetTriple(), + Diags); + TheDriver.setTargetAndMode(TargetandMode); + std::unique_ptr C( + TheDriver.BuildCompilation(argv)); + llvm::SmallVector, 4> + FailingCommands; + return TheDriver.ExecuteCompilation(*C, FailingCommands); +}