diff options
author | Andrzej Warzynski <andrzej.warzynski@arm.com> | 2022-02-24 17:34:27 +0000 |
---|---|---|
committer | Andrzej Warzynski <andrzej.warzynski@arm.com> | 2022-03-09 15:48:09 +0000 |
commit | 38101b4e95aa4983b7acf1e6351309db9ce5761b (patch) | |
tree | 104565d5c4188f2bafcfc5043c9877d5bddfa4af /flang/lib/Frontend | |
parent | 3dd7877b27dcd0d2b8e0d3a3ac156390248fe612 (diff) | |
download | llvm-38101b4e95aa4983b7acf1e6351309db9ce5761b.zip llvm-38101b4e95aa4983b7acf1e6351309db9ce5761b.tar.gz llvm-38101b4e95aa4983b7acf1e6351309db9ce5761b.tar.bz2 |
[flang][driver] Add support for -S and implement -c/-emit-obj
This patch adds support for:
* `-S` in Flang's compiler and frontend drivers,
and implements:
* `-emit-obj` in Flang's frontend driver and `-c` in Flang's compiler
driver (this is consistent with Clang).
(these options were already available before, but only as placeholders).
The semantics of these options in Clang and Flang are identical.
The `EmitObjAction` frontend action is renamed as `BackendAction`. This
new name more accurately reflects the fact that this action will
primarily run the code-gen/backend pipeline in LLVM. It also makes more
sense as an action implementing both `-emit-obj` and `-S` (originally,
it was just `-emit-obj`).
`tripleName` from FirContext.cpp is deleted and, when a target triple is
required, `mlir::LLVM::LLVMDialect::getTargetTripleAttrName()` is used
instead. In practice, this means that `fir.triple` is replaced with
`llvm.target_triple`. The former was effectively ignored. The latter is
used when lowering from the LLVM dialect in MLIR to LLVM IR (i.e. it's
embedded in the generated LLVM IR module). The driver can then re-use
it when configuring the backend. With this change, the LLVM IR files
generated by e.g. `tco` will from now on contain the correct target
triple.
The code-gen.f90 test is replaced with code-gen-x86.f90 and
code-gen-aarch64.f90. With 2 seperate files we can verify that
`--target` is correctly taken into account. LIT configuration is updated
to enable e.g.:
```
! REQUIRES: aarch64-registered-target
```
Differential Revision: https://reviews.llvm.org/D120568
Diffstat (limited to 'flang/lib/Frontend')
-rw-r--r-- | flang/lib/Frontend/CMakeLists.txt | 2 | ||||
-rw-r--r-- | flang/lib/Frontend/CompilerInvocation.cpp | 3 | ||||
-rw-r--r-- | flang/lib/Frontend/FrontendActions.cpp | 94 |
3 files changed, 94 insertions, 5 deletions
diff --git a/flang/lib/Frontend/CMakeLists.txt b/flang/lib/Frontend/CMakeLists.txt index 4f54ab7..a68e0e9 100644 --- a/flang/lib/Frontend/CMakeLists.txt +++ b/flang/lib/Frontend/CMakeLists.txt @@ -27,6 +27,8 @@ add_flang_library(flangFrontend FortranLower clangBasic clangDriver + LLVMAnalysis + LLVMTarget FIRDialect FIRSupport FIRBuilder diff --git a/flang/lib/Frontend/CompilerInvocation.cpp b/flang/lib/Frontend/CompilerInvocation.cpp index a1d7309..d1b0d0e 100644 --- a/flang/lib/Frontend/CompilerInvocation.cpp +++ b/flang/lib/Frontend/CompilerInvocation.cpp @@ -153,6 +153,9 @@ static bool ParseFrontendArgs(FrontendOptions &opts, llvm::opt::ArgList &args, case clang::driver::options::OPT_emit_obj: opts.programAction = EmitObj; break; + case clang::driver::options::OPT_S: + opts.programAction = EmitAssembly; + break; case clang::driver::options::OPT_fdebug_unparse: opts.programAction = DebugUnparse; break; diff --git a/flang/lib/Frontend/FrontendActions.cpp b/flang/lib/Frontend/FrontendActions.cpp index c72460f..e30f6af 100644 --- a/flang/lib/Frontend/FrontendActions.cpp +++ b/flang/lib/Frontend/FrontendActions.cpp @@ -31,7 +31,13 @@ #include "mlir/Pass/PassManager.h" #include "mlir/Target/LLVMIR/ModuleTranslation.h" #include "llvm/ADT/StringRef.h" +#include "llvm/Analysis/TargetLibraryInfo.h" +#include "llvm/Analysis/TargetTransformInfo.h" +#include "llvm/IR/LegacyPassManager.h" +#include "llvm/MC/TargetRegistry.h" +#include "llvm/Passes/PassBuilder.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/Target/TargetMachine.h" #include <clang/Basic/Diagnostic.h> #include <memory> @@ -417,7 +423,6 @@ void CodeGenAction::GenerateLLVMIR() { pm.addPass(std::make_unique<Fortran::lower::VerifierPass>()); pm.enableVerifier(/*verifyPasses=*/true); - mlir::PassPipelineCLParser passPipeline("", "Compiler passes to run"); // Create the pass pipeline fir::createMLIRToLLVMPassPipeline(pm); @@ -490,11 +495,90 @@ void EmitMLIRAction::ExecuteAction() { mlirModule->print(*os); } -void EmitObjAction::ExecuteAction() { +void BackendAction::ExecuteAction() { CompilerInstance &ci = this->instance(); - unsigned DiagID = ci.diagnostics().getCustomDiagID( - clang::DiagnosticsEngine::Error, "code-generation is not available yet"); - ci.diagnostics().Report(DiagID); + // Generate an LLVM module if it's not already present (it will already be + // present if the input file is an LLVM IR/BC file). + if (!llvmModule) + GenerateLLVMIR(); + + // Create `Target` + std::string error; + const std::string &theTriple = llvmModule->getTargetTriple(); + const llvm::Target *theTarget = + llvm::TargetRegistry::lookupTarget(theTriple, error); + // TODO: Make this a diagnostic once `flang-new` can consume LLVM IR files + // (in which users could use unsupported triples) + assert(theTarget && "Failed to create Target"); + + // Create `TargetMachine` + std::unique_ptr<llvm::TargetMachine> TM; + TM.reset(theTarget->createTargetMachine(theTriple, /*CPU=*/"", + /*Features=*/"", llvm::TargetOptions(), llvm::None)); + assert(TM && "Failed to create TargetMachine"); + llvmModule->setDataLayout(TM->createDataLayout()); + + // If the output stream is a file, generate it and define the corresponding + // output stream. If a pre-defined output stream is available, we will use + // that instead. + // + // NOTE: `os` is a smart pointer that will be destroyed at the end of this + // method. However, it won't be written to until `CodeGenPasses` is + // destroyed. By defining `os` before `CodeGenPasses`, we make sure that the + // output stream won't be destroyed before it is written to. This only + // applies when an output file is used (i.e. there is no pre-defined output + // stream). + // TODO: Revisit once the new PM is ready (i.e. when `CodeGenPasses` is + // updated to use it). + std::unique_ptr<llvm::raw_pwrite_stream> os; + if (ci.IsOutputStreamNull()) { + // Get the output buffer/file + switch (action) { + case BackendActionTy::Backend_EmitAssembly: + os = ci.CreateDefaultOutputFile( + /*Binary=*/false, /*InFile=*/GetCurrentFileOrBufferName(), "s"); + break; + case BackendActionTy::Backend_EmitObj: + os = ci.CreateDefaultOutputFile( + /*Binary=*/true, /*InFile=*/GetCurrentFileOrBufferName(), "o"); + break; + } + if (!os) { + unsigned diagID = ci.diagnostics().getCustomDiagID( + clang::DiagnosticsEngine::Error, "failed to create the output file"); + ci.diagnostics().Report(diagID); + return; + } + } + + // Create an LLVM code-gen pass pipeline. Currently only the legacy pass + // manager is supported. + // TODO: Switch to the new PM once it's available in the backend. + llvm::legacy::PassManager CodeGenPasses; + CodeGenPasses.add( + createTargetTransformInfoWrapperPass(TM->getTargetIRAnalysis())); + llvm::Triple triple(theTriple); + + std::unique_ptr<llvm::TargetLibraryInfoImpl> TLII = + std::make_unique<llvm::TargetLibraryInfoImpl>(triple); + assert(TLII && "Failed to create TargetLibraryInfo"); + CodeGenPasses.add(new llvm::TargetLibraryInfoWrapperPass(*TLII)); + + llvm::CodeGenFileType cgft = (action == BackendActionTy::Backend_EmitAssembly) + ? llvm::CodeGenFileType::CGFT_AssemblyFile + : llvm::CodeGenFileType::CGFT_ObjectFile; + if (TM->addPassesToEmitFile(CodeGenPasses, + ci.IsOutputStreamNull() ? *os : ci.GetOutputStream(), nullptr, + cgft)) { + unsigned diagID = + ci.diagnostics().getCustomDiagID(clang::DiagnosticsEngine::Error, + "emission of this file type is not supported"); + ci.diagnostics().Report(diagID); + return; + } + + // Run the code-gen passes + CodeGenPasses.run(*llvmModule); } void InitOnlyAction::ExecuteAction() { |