Skip to content

Commit 5e3c7fd

Browse files
banach-spacejeanPerier
authored andcommitted
[flang][driver] Add support for -emit-obj in the frontend driver
This patch implements the `EmitObjAction` frontend action. The `CodeGenAction` is extended to contain an instance of `llvm::LLVMCtx` and `llvm::Module`. These variables are unlikely to be needed in other, non-code-gen actions (or in `CompilerInstance` or `CompilerInvocation`), so these should be the right location. Also, a member method for generating LLVM IR is added (see `GenerateLLVMIR`). The target triple is hard-coded as `native`, i.e. no cross-compilation is supported at this stage. `tripleName` in FirContext.cpp is updated from `fir.triple` to `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 that 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. As these tests are arch specific (they check the generated assembly), support for `!REQUIRES: <arch>-registered-target` was added in LIT. The current approach is a bit fragile and will cause problems if multiple targets are available (e.g. X86 and AArch64). That's because `!REQUIRES: X86-registered-target` will be satisfied even on AArch64 targets if the X86 backend is enabled (through e.g. `LLVM_ENABLE_TARGETS`). However, the test could fail as currently `flang-new -fc1 -emit-obj` always generates code for the host architecture. This can be fixed by adding support for `-target`.
1 parent 7f47063 commit 5e3c7fd

File tree

13 files changed

+133
-40
lines changed

13 files changed

+133
-40
lines changed

flang/include/flang/Frontend/CompilerInstance.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,6 @@ class CompilerInstance {
7474
std::unique_ptr<llvm::raw_pwrite_stream> outputStream_;
7575

7676
std::unique_ptr<mlir::MLIRContext> mlirCtx_;
77-
7877
std::unique_ptr<mlir::ModuleOp> mlirModule_;
7978

8079
public:

flang/include/flang/Frontend/FrontendActions.h

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
#include "flang/Frontend/FrontendAction.h"
1313
#include "flang/Semantics/semantics.h"
14+
#include "llvm/IR/Module.h"
1415
#include <memory>
1516

1617
namespace Fortran::frontend {
@@ -34,10 +35,6 @@ class InputOutputTestAction : public FrontendAction {
3435
void ExecuteAction() override;
3536
};
3637

37-
class EmitObjAction : public FrontendAction {
38-
void ExecuteAction() override;
39-
};
40-
4138
class InitOnlyAction : public FrontendAction {
4239
void ExecuteAction() override;
4340
};
@@ -153,6 +150,14 @@ class CodeGenAction : public FrontendAction {
153150

154151
void ExecuteAction() override = 0;
155152
bool BeginSourceFileAction() override;
153+
154+
protected:
155+
/// @name LLVM IR
156+
std::unique_ptr<llvm::LLVMContext> llvmCtx_;
157+
std::unique_ptr<llvm::Module> llvmModule_;
158+
/// }
159+
160+
void GenerateLLVMIR();
156161
};
157162

158163
class EmitMLIRAction : public CodeGenAction {
@@ -163,6 +168,10 @@ class EmitLLVMAction : public CodeGenAction {
163168
void ExecuteAction() override;
164169
};
165170

171+
class EmitObjAction : public CodeGenAction {
172+
void ExecuteAction() override;
173+
};
174+
166175
} // namespace Fortran::frontend
167176

168177
#endif // LLVM_FLANG_FRONTEND_FRONTENDACTIONS_H

flang/lib/Frontend/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ add_flang_library(flangFrontend
2525
FortranLower
2626
clangBasic
2727
clangDriver
28+
LLVMAnalysis
2829
FIRDialect
2930
FIRAnalysis
3031
FIRSupport

flang/lib/Frontend/FrontendActions.cpp

Lines changed: 74 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,10 @@
2020
#include "flang/Lower/Support/Verifier.h"
2121
#include "flang/Optimizer/CodeGen/CodeGen.h"
2222
#include "flang/Optimizer/Dialect/FIRType.h"
23-
#include "flang/Optimizer/Support//Utils.h"
2423
#include "flang/Optimizer/Support/FIRContext.h"
2524
#include "flang/Optimizer/Support/InitFIR.h"
2625
#include "flang/Optimizer/Support/KindMapping.h"
26+
#include "flang/Optimizer/Support/Utils.h"
2727
#include "flang/Optimizer/Transforms/Passes.h"
2828
#include "flang/Parser/dump-parse-tree.h"
2929
#include "flang/Parser/parsing.h"
@@ -34,11 +34,18 @@
3434
#include "flang/Semantics/semantics.h"
3535
#include "flang/Semantics/unparse-with-symbols.h"
3636
#include "llvm/ADT/StringRef.h"
37+
#include "llvm/Analysis/TargetLibraryInfo.h"
38+
#include "llvm/Analysis/TargetTransformInfo.h"
39+
#include "llvm/IR/LegacyPassManager.h"
40+
#include "llvm/Support/CodeGen.h"
3741
#include "llvm/Support/ErrorHandling.h"
42+
#include "llvm/MC/TargetRegistry.h"
3843
#include "llvm/Support/raw_ostream.h"
44+
#include "llvm/Target/TargetMachine.h"
3945
#include <clang/Basic/Diagnostic.h>
4046

4147
using namespace Fortran::frontend;
48+
using namespace llvm;
4249

4350
//===----------------------------------------------------------------------===//
4451
// Custom BeginSourceFileAction
@@ -436,15 +443,16 @@ void EmitMLIRAction::ExecuteAction() {
436443

437444
#include "flang/Tools/CLOptions.inc"
438445

439-
void EmitLLVMAction::ExecuteAction() {
446+
// Lower the previously generated MLIR module into an LLVM IR module
447+
void CodeGenAction::GenerateLLVMIR() {
440448
CompilerInstance &ci = this->instance();
441449
auto mlirMod = ci.mlirModule();
442450

443451
auto &ctx = ci.mlirCtx();
444452
fir::support::loadDialects(ctx);
445453
fir::support::registerLLVMTranslation(ctx);
446454

447-
// Set-up the pass manager
455+
// Set-up the MLIR pass manager
448456
fir::setTargetTriple(mlirMod, "native");
449457
auto &defKinds = ci.invocation().semanticsContext().defaultKinds();
450458
fir::KindMapping kindMap(&ci.mlirCtx(),
@@ -468,16 +476,21 @@ void EmitLLVMAction::ExecuteAction() {
468476

469477
// Translate to LLVM IR
470478
auto optName = mlirMod.getName();
471-
llvm::LLVMContext llvmCtx;
472-
auto llvmModule = (mlir::translateModuleToLLVMIR(
473-
mlirMod, llvmCtx, optName ? *optName : "FIRModule"));
479+
llvmCtx_ = std::make_unique<llvm::LLVMContext>();
480+
llvmModule_ = mlir::translateModuleToLLVMIR(
481+
mlirMod, *llvmCtx_, optName ? *optName : "FIRModule");
474482

475-
if (!llvmModule) {
483+
if (!llvmModule_) {
476484
unsigned diagID = ci.diagnostics().getCustomDiagID(
477485
clang::DiagnosticsEngine::Error, "failed to create the LLVM module");
478486
ci.diagnostics().Report(diagID);
479487
return;
480488
}
489+
}
490+
491+
void EmitLLVMAction::ExecuteAction() {
492+
CompilerInstance &ci = this->instance();
493+
GenerateLLVMIR();
481494

482495
// Print the generated LLVM IR. If there is no pre-defined output stream to
483496
// print to, create an output file.
@@ -495,20 +508,69 @@ void EmitLLVMAction::ExecuteAction() {
495508
}
496509

497510
if (!ci.IsOutputStreamNull()) {
498-
llvmModule->print(
511+
llvmModule_->print(
499512
ci.GetOutputStream(), /*AssemblyAnnotationWriter=*/nullptr);
500513
} else {
501-
llvmModule->print(*os, /*AssemblyAnnotationWriter=*/nullptr);
514+
llvmModule_->print(*os, /*AssemblyAnnotationWriter=*/nullptr);
502515
}
503516

504517
return;
505518
}
506519

507520
void EmitObjAction::ExecuteAction() {
508521
CompilerInstance &ci = this->instance();
509-
unsigned DiagID = ci.diagnostics().getCustomDiagID(
510-
clang::DiagnosticsEngine::Error, "code-generation is not available yet");
511-
ci.diagnostics().Report(DiagID);
522+
GenerateLLVMIR();
523+
524+
// Create `Target`
525+
std::string error;
526+
std::string theTriple = llvmModule_->getTargetTriple();
527+
const llvm::Target *theTarget =
528+
TargetRegistry::lookupTarget(theTriple, error);
529+
assert(theTarget && "Failed to create Target");
530+
531+
// Create `TargetMachine`
532+
std::unique_ptr<TargetMachine> TM;
533+
TM.reset(theTarget->createTargetMachine(
534+
theTriple, /*CPU=*/"", /*Features=*/"", llvm::TargetOptions(), None));
535+
llvmModule_->setDataLayout(TM->createDataLayout());
536+
assert(TM && "Failed to create TargetMachine");
537+
538+
// Create an LLVM code-gen pass pipeline. Currently only the legacy pass
539+
// manager is supported.
540+
// TODO: Switch to the new PM once it's available in the backend.
541+
legacy::PassManager CodeGenPasses;
542+
CodeGenPasses.add(createTargetTransformInfoWrapperPass(TargetIRAnalysis()));
543+
Triple triple(llvmModule_->getTargetTriple());
544+
std::unique_ptr<llvm::TargetLibraryInfoImpl> TLII =
545+
std::make_unique<llvm::TargetLibraryInfoImpl>(triple);
546+
CodeGenPasses.add(new TargetLibraryInfoWrapperPass(*TLII));
547+
548+
// Get the output buffer/file
549+
std::unique_ptr<llvm::raw_pwrite_stream> os{ci.CreateDefaultOutputFile(
550+
/*Binary=*/true, /*InFile=*/GetCurrentFileOrBufferName(), "o")};
551+
if (!os) {
552+
unsigned diagID = ci.diagnostics().getCustomDiagID(
553+
clang::DiagnosticsEngine::Error, "failed to create the output file");
554+
ci.diagnostics().Report(diagID);
555+
return;
556+
}
557+
558+
if (TM->addPassesToEmitFile(CodeGenPasses, *os, nullptr,
559+
/*CodeGenFileType*/ llvm::CodeGenFileType::CGFT_ObjectFile))
560+
assert(false && "Something went wrong");
561+
// The output stream, `os`, is a smart pointer that will be destroyed at the
562+
// end of this method. However, it won't be written to until `CodeGenPasses`
563+
// is destroyed. Hence, we need to release `as` here as otherwise it will be
564+
// destroyed before it is written to. This pointer is later wrapped into a
565+
// smart pointer inside `LLVMTargetMachine::createMCStreamer`, so no
566+
// resources are leaked.
567+
// TODO: Implement a safer way to pass `os` around.
568+
os.release();
569+
570+
// Run the code-gen passes
571+
CodeGenPasses.run(*llvmModule_);
572+
573+
return;
512574
}
513575

514576
void InitOnlyAction::ExecuteAction() {

flang/lib/Optimizer/Support/FIRContext.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
#include "mlir/IR/BuiltinOps.h"
1717
#include "llvm/Support/Host.h"
1818

19-
static constexpr const char *tripleName = "fir.triple";
19+
static constexpr const char *tripleName = "llvm.target_triple";
2020

2121
void fir::setTargetTriple(mlir::ModuleOp mod, llvm::StringRef triple) {
2222
auto target = fir::determineTargetTriple(triple);
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
! TODO Add `-target <arch>` once that's available
2+
3+
! RUN: rm -f %t.o
4+
! RUN: %flang_fc1 -emit-obj %s -o %t.o
5+
! RUN: llvm-objdump --disassemble-all %t.o | FileCheck %s
6+
! RUN: rm -f %t.o
7+
! RUN: %flang -c %s -o %t.o
8+
! RUN: llvm-objdump --disassemble-all %t.o | FileCheck %s
9+
10+
! REQUIRES: aarch64-registered-target
11+
12+
! CHECK-LABEL: <_QQmain>:
13+
! CHECK-NEXT: ret
14+
15+
end program

flang/test/Driver/code-gen-x86.f90

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
! TODO Add `-target <arch>` once that's available
2+
3+
! RUN: rm -f %t.o
4+
! RUN: %flang_fc1 -emit-obj %s -o %t.o
5+
! RUN: llvm-objdump --disassemble-all %t.o | FileCheck %s
6+
! RUN: rm -f %t.o
7+
! RUN: %flang -c %s -o %t.o
8+
! RUN: llvm-objdump --disassemble-all %t.o | FileCheck %s
9+
10+
! REQUIRES: x86-registered-target
11+
12+
! CHECK-LABEL: <_QQmain>:
13+
! CHECK-NEXT: retq
14+
15+
end program

flang/test/Driver/code-gen.f90

Lines changed: 0 additions & 19 deletions
This file was deleted.

flang/test/Driver/syntax-only.f90

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,13 @@
77
! RUN LINES
88
!-----------
99
! RUN: not %flang -fsyntax-only %s 2>&1 | FileCheck %s --check-prefix=FSYNTAX_ONLY
10-
! RUN: not %flang %s 2>&1 | FileCheck %s --check-prefix=NO_FSYNTAX_ONLY
1110

1211
!-----------------
1312
! EXPECTED OUTPUT
1413
!-----------------
1514
! FSYNTAX_ONLY: IF statement is not allowed in IF statement
1615
! FSYNTAX_ONLY_NEXT: Semantic errors in {{.*}}syntax-only.f90
1716

18-
! NO_FSYNTAX_ONLY: error: code-generation is not available yet
19-
2017
!-------
2118
! INPUT
2219
!-------

flang/test/Fir/complex.fir

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
// RUN: %CC %t print_complex.o
55
// RUN: ./a.out | FileCheck %s --check-prefix=EXECHECK
66

7+
// REQUIRES: x86-registered-target
8+
79
// EXECHECK: <0.935893, 2.252526>
810

911
// LLVMIR-LABEL: define <2 x float> @foo(<2 x float> %

0 commit comments

Comments
 (0)