Skip to content

Commit 38101b4

Browse files
committed
[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
1 parent 3dd7877 commit 38101b4

23 files changed

+285
-39
lines changed

clang/include/clang/Driver/Options.td

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -750,7 +750,7 @@ def Rpass_analysis_EQ : Joined<["-"], "Rpass-analysis=">, Group<R_value_Group>,
750750
"name matches the given POSIX regular expression">;
751751
def R_Joined : Joined<["-"], "R">, Group<R_Group>, Flags<[CC1Option, CoreOption]>,
752752
MetaVarName<"<remark>">, HelpText<"Enable the specified remark">;
753-
def S : Flag<["-"], "S">, Flags<[NoXarchOption,CC1Option]>, Group<Action_Group>,
753+
def S : Flag<["-"], "S">, Flags<[NoXarchOption,CC1Option,FlangOption,FC1Option]>, Group<Action_Group>,
754754
HelpText<"Only run preprocess and compilation steps">;
755755
def Tbss : JoinedOrSeparate<["-"], "Tbss">, Group<T_Group>,
756756
MetaVarName<"<addr>">, HelpText<"Set starting address of BSS to <addr>">;

flang/include/flang/Frontend/FrontendActions.h

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -192,8 +192,19 @@ class EmitLLVMAction : public CodeGenAction {
192192
void ExecuteAction() override;
193193
};
194194

195-
class EmitObjAction : public CodeGenAction {
195+
class BackendAction : public CodeGenAction {
196+
public:
197+
enum class BackendActionTy {
198+
Backend_EmitAssembly, ///< Emit native assembly files
199+
Backend_EmitObj ///< Emit native object files
200+
};
201+
202+
BackendAction(BackendActionTy act) : action{act} {};
203+
204+
private:
196205
void ExecuteAction() override;
206+
207+
BackendActionTy action;
197208
};
198209

199210
} // namespace Fortran::frontend

flang/include/flang/Frontend/FrontendOptions.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@ enum ActionKind {
4040
/// Emit a .o file.
4141
EmitObj,
4242

43+
/// Emit a .s file.
44+
EmitAssembly,
45+
4346
/// Parse, unparse the parse-tree and output a Fortran source file
4447
DebugUnparse,
4548

flang/lib/Frontend/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ add_flang_library(flangFrontend
2727
FortranLower
2828
clangBasic
2929
clangDriver
30+
LLVMAnalysis
31+
LLVMTarget
3032
FIRDialect
3133
FIRSupport
3234
FIRBuilder

flang/lib/Frontend/CompilerInvocation.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,9 @@ static bool ParseFrontendArgs(FrontendOptions &opts, llvm::opt::ArgList &args,
153153
case clang::driver::options::OPT_emit_obj:
154154
opts.programAction = EmitObj;
155155
break;
156+
case clang::driver::options::OPT_S:
157+
opts.programAction = EmitAssembly;
158+
break;
156159
case clang::driver::options::OPT_fdebug_unparse:
157160
opts.programAction = DebugUnparse;
158161
break;

flang/lib/Frontend/FrontendActions.cpp

Lines changed: 89 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,13 @@
3131
#include "mlir/Pass/PassManager.h"
3232
#include "mlir/Target/LLVMIR/ModuleTranslation.h"
3333
#include "llvm/ADT/StringRef.h"
34+
#include "llvm/Analysis/TargetLibraryInfo.h"
35+
#include "llvm/Analysis/TargetTransformInfo.h"
36+
#include "llvm/IR/LegacyPassManager.h"
37+
#include "llvm/MC/TargetRegistry.h"
38+
#include "llvm/Passes/PassBuilder.h"
3439
#include "llvm/Support/ErrorHandling.h"
40+
#include "llvm/Target/TargetMachine.h"
3541
#include <clang/Basic/Diagnostic.h>
3642
#include <memory>
3743

@@ -417,7 +423,6 @@ void CodeGenAction::GenerateLLVMIR() {
417423

418424
pm.addPass(std::make_unique<Fortran::lower::VerifierPass>());
419425
pm.enableVerifier(/*verifyPasses=*/true);
420-
mlir::PassPipelineCLParser passPipeline("", "Compiler passes to run");
421426

422427
// Create the pass pipeline
423428
fir::createMLIRToLLVMPassPipeline(pm);
@@ -490,11 +495,90 @@ void EmitMLIRAction::ExecuteAction() {
490495
mlirModule->print(*os);
491496
}
492497

493-
void EmitObjAction::ExecuteAction() {
498+
void BackendAction::ExecuteAction() {
494499
CompilerInstance &ci = this->instance();
495-
unsigned DiagID = ci.diagnostics().getCustomDiagID(
496-
clang::DiagnosticsEngine::Error, "code-generation is not available yet");
497-
ci.diagnostics().Report(DiagID);
500+
// Generate an LLVM module if it's not already present (it will already be
501+
// present if the input file is an LLVM IR/BC file).
502+
if (!llvmModule)
503+
GenerateLLVMIR();
504+
505+
// Create `Target`
506+
std::string error;
507+
const std::string &theTriple = llvmModule->getTargetTriple();
508+
const llvm::Target *theTarget =
509+
llvm::TargetRegistry::lookupTarget(theTriple, error);
510+
// TODO: Make this a diagnostic once `flang-new` can consume LLVM IR files
511+
// (in which users could use unsupported triples)
512+
assert(theTarget && "Failed to create Target");
513+
514+
// Create `TargetMachine`
515+
std::unique_ptr<llvm::TargetMachine> TM;
516+
TM.reset(theTarget->createTargetMachine(theTriple, /*CPU=*/"",
517+
/*Features=*/"", llvm::TargetOptions(), llvm::None));
518+
assert(TM && "Failed to create TargetMachine");
519+
llvmModule->setDataLayout(TM->createDataLayout());
520+
521+
// If the output stream is a file, generate it and define the corresponding
522+
// output stream. If a pre-defined output stream is available, we will use
523+
// that instead.
524+
//
525+
// NOTE: `os` is a smart pointer that will be destroyed at the end of this
526+
// method. However, it won't be written to until `CodeGenPasses` is
527+
// destroyed. By defining `os` before `CodeGenPasses`, we make sure that the
528+
// output stream won't be destroyed before it is written to. This only
529+
// applies when an output file is used (i.e. there is no pre-defined output
530+
// stream).
531+
// TODO: Revisit once the new PM is ready (i.e. when `CodeGenPasses` is
532+
// updated to use it).
533+
std::unique_ptr<llvm::raw_pwrite_stream> os;
534+
if (ci.IsOutputStreamNull()) {
535+
// Get the output buffer/file
536+
switch (action) {
537+
case BackendActionTy::Backend_EmitAssembly:
538+
os = ci.CreateDefaultOutputFile(
539+
/*Binary=*/false, /*InFile=*/GetCurrentFileOrBufferName(), "s");
540+
break;
541+
case BackendActionTy::Backend_EmitObj:
542+
os = ci.CreateDefaultOutputFile(
543+
/*Binary=*/true, /*InFile=*/GetCurrentFileOrBufferName(), "o");
544+
break;
545+
}
546+
if (!os) {
547+
unsigned diagID = ci.diagnostics().getCustomDiagID(
548+
clang::DiagnosticsEngine::Error, "failed to create the output file");
549+
ci.diagnostics().Report(diagID);
550+
return;
551+
}
552+
}
553+
554+
// Create an LLVM code-gen pass pipeline. Currently only the legacy pass
555+
// manager is supported.
556+
// TODO: Switch to the new PM once it's available in the backend.
557+
llvm::legacy::PassManager CodeGenPasses;
558+
CodeGenPasses.add(
559+
createTargetTransformInfoWrapperPass(TM->getTargetIRAnalysis()));
560+
llvm::Triple triple(theTriple);
561+
562+
std::unique_ptr<llvm::TargetLibraryInfoImpl> TLII =
563+
std::make_unique<llvm::TargetLibraryInfoImpl>(triple);
564+
assert(TLII && "Failed to create TargetLibraryInfo");
565+
CodeGenPasses.add(new llvm::TargetLibraryInfoWrapperPass(*TLII));
566+
567+
llvm::CodeGenFileType cgft = (action == BackendActionTy::Backend_EmitAssembly)
568+
? llvm::CodeGenFileType::CGFT_AssemblyFile
569+
: llvm::CodeGenFileType::CGFT_ObjectFile;
570+
if (TM->addPassesToEmitFile(CodeGenPasses,
571+
ci.IsOutputStreamNull() ? *os : ci.GetOutputStream(), nullptr,
572+
cgft)) {
573+
unsigned diagID =
574+
ci.diagnostics().getCustomDiagID(clang::DiagnosticsEngine::Error,
575+
"emission of this file type is not supported");
576+
ci.diagnostics().Report(diagID);
577+
return;
578+
}
579+
580+
// Run the code-gen passes
581+
CodeGenPasses.run(*llvmModule);
498582
}
499583

500584
void InitOnlyAction::ExecuteAction() {

flang/lib/FrontendTool/ExecuteCompilerInvocation.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,11 @@ static std::unique_ptr<FrontendAction> CreateFrontendBaseAction(
3838
case EmitLLVM:
3939
return std::make_unique<EmitLLVMAction>();
4040
case EmitObj:
41-
return std::make_unique<EmitObjAction>();
41+
return std::make_unique<BackendAction>(
42+
BackendAction::BackendActionTy::Backend_EmitObj);
43+
case EmitAssembly:
44+
return std::make_unique<BackendAction>(
45+
BackendAction::BackendActionTy::Backend_EmitAssembly);
4246
case DebugUnparse:
4347
return std::make_unique<DebugUnparseAction>();
4448
case DebugUnparseNoSema:

flang/lib/Optimizer/Support/FIRContext.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,19 +12,20 @@
1212

1313
#include "flang/Optimizer/Support/FIRContext.h"
1414
#include "flang/Optimizer/Support/KindMapping.h"
15+
#include "mlir/Dialect/LLVMIR/LLVMDialect.h"
1516
#include "mlir/IR/BuiltinAttributes.h"
1617
#include "mlir/IR/BuiltinOps.h"
1718
#include "llvm/Support/Host.h"
1819

19-
static constexpr const char *tripleName = "fir.triple";
20-
2120
void fir::setTargetTriple(mlir::ModuleOp mod, llvm::StringRef triple) {
2221
auto target = fir::determineTargetTriple(triple);
23-
mod->setAttr(tripleName, mlir::StringAttr::get(mod.getContext(), target));
22+
mod->setAttr(mlir::LLVM::LLVMDialect::getTargetTripleAttrName(),
23+
mlir::StringAttr::get(mod.getContext(), target));
2424
}
2525

2626
llvm::Triple fir::getTargetTriple(mlir::ModuleOp mod) {
27-
if (auto target = mod->getAttrOfType<mlir::StringAttr>(tripleName))
27+
if (auto target = mod->getAttrOfType<mlir::StringAttr>(
28+
mlir::LLVM::LLVMDialect::getTargetTripleAttrName()))
2829
return llvm::Triple(target.getValue());
2930
return llvm::Triple(llvm::sys::getDefaultTargetTriple());
3031
}

flang/test/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ set(FLANG_TEST_PARAMS
4646
flang_site_config=${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg.py)
4747

4848
set(FLANG_TEST_DEPENDS
49-
flang-new llvm-config FileCheck count not module_files fir-opt tco bbc
49+
flang-new llvm-config FileCheck count not module_files fir-opt tco bbc llvm-objdump
5050
)
5151

5252
if (FLANG_INCLUDE_TESTS)
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
! Test -emit-obj (X86)
2+
3+
! REQUIRES: aarch64-registered-target, x86-registered-target
4+
5+
!-------------
6+
! RUN COMMANDS
7+
!-------------
8+
! RUN: rm -f %t.o
9+
! RUN: %flang_fc1 -emit-obj -triple aarch64-unknown-linux-gnu %s -o %t.o
10+
! RUN: llvm-objdump --triple aarch64-unknown-linux-gnu --disassemble-all %t.o | FileCheck %s --check-prefix=CORRECT_TRIPLE
11+
! RUN: rm -f %t.o
12+
! RUN: %flang -c --target=aarch64-unknown-linux-gnu %s -o %t.o
13+
! RUN: llvm-objdump --triple aarch64-unknown-linux-gnu --disassemble-all %t.o | FileCheck %s --check-prefix=CORRECT_TRIPLE
14+
15+
! RUN: %flang -c --target=aarch64-unknown-linux-gnu %s -o %t.o
16+
! RUN: llvm-objdump --triple x86_64-unknown-linux-gnu --disassemble-all %t.o | FileCheck %s --check-prefix=INCORRECT_TRIPLE
17+
18+
!----------------
19+
! EXPECTED OUTPUT
20+
!----------------
21+
! CORRECT_TRIPLE-LABEL: <_QQmain>:
22+
! CORRECT_TRIPLE-NEXT: ret
23+
24+
! When incorrect triple is used to disassemble, there won't be a ret instruction at all.
25+
! INCORRECT_TRIPLE-LABEL: <_QQmain>:
26+
! INCORRECT_TRIPLE-NOT: ret
27+
28+
!------
29+
! INPUT
30+
!------
31+
end program

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

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
! Test -emit-obj (X86)
2+
3+
! REQUIRES: x86-registered-target, aarch64-registered-target
4+
! UNSUPPORTED: darwin, macos
5+
6+
!-------------
7+
! RUN COMMANDS
8+
!-------------
9+
! RUN: rm -f %t.o
10+
! RUN: %flang_fc1 -triple x86_64-unknown-linux-gnu -emit-obj %s -o %t.o
11+
! RUN: llvm-objdump --triple x86_64-unknown-linux-gnu --disassemble-all %t.o | FileCheck %s --check-prefix=CORRECT_TRIPLE
12+
! RUN: rm -f %t.o
13+
! RUN: %flang --target=x86_64-unknown-linux-gnu -c %s -o %t.o
14+
! RUN: llvm-objdump --triple x86_64-unknown-linux-gnu --disassemble-all %t.o | FileCheck %s --check-prefix=CORRECT_TRIPLE
15+
16+
! RUN: %flang -c --target=x86_64-unknown-linux-gnu %s -o %t.o
17+
! RUN: llvm-objdump --triple aarch64-unknown-linux-gnu --disassemble-all %t.o | FileCheck %s --check-prefix=INCORRECT_TRIPLE
18+
19+
!----------------
20+
! EXPECTED OUTPUT
21+
!----------------
22+
! CORRECT_TRIPLE-LABEL: <_QQmain>:
23+
! CORRECT_TRIPLE-NEXT: retq
24+
25+
! When incorrect triple is used to disassemble, there won't be a ret(q) instruction at all.
26+
! INCORRECT_TRIPLE-LABEL: <_QQmain>:
27+
! INCORRECT_TRIPLE-NOT: ret
28+
29+
!------
30+
! INPUT
31+
!------
32+
end program

flang/test/Driver/code-gen.f90

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

flang/test/Driver/driver-help-hidden.f90

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@
5555
! CHECK-NEXT: -print-target-triple Print the normalized target triple
5656
! CHECK-NEXT: -P Disable linemarker output in -E mode
5757
! CHECK-NEXT: -std=<value> Language standard to compile for
58+
! CHECK-NEXT: -S Only run preprocess and compilation steps
5859
! CHECK-NEXT: --target=<value> Generate code for the given target
5960
! CHECK-NEXT: -U <macro> Undefine macro <macro>
6061
! CHECK-NEXT: --version Print version information

flang/test/Driver/driver-help.f90

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@
5555
! HELP-NEXT: -print-target-triple Print the normalized target triple
5656
! HELP-NEXT: -P Disable linemarker output in -E mode
5757
! HELP-NEXT: -std=<value> Language standard to compile for
58+
! HELP-NEXT: -S Only run preprocess and compilation steps
5859
! HELP-NEXT: --target=<value> Generate code for the given target
5960
! HELP-NEXT: -U <macro> Undefine macro <macro>
6061
! HELP-NEXT: --version Print version information
@@ -128,6 +129,7 @@
128129
! HELP-FC1-NEXT: -plugin <name> Use the named plugin action instead of the default action (use "help" to list available options)
129130
! HELP-FC1-NEXT: -P Disable linemarker output in -E mode
130131
! HELP-FC1-NEXT: -std=<value> Language standard to compile for
132+
! HELP-FC1-NEXT: -S Only run preprocess and compilation steps
131133
! HELP-FC1-NEXT: -test-io Run the InputOuputTest action. Use for development and testing only.
132134
! HELP-FC1-NEXT: -triple <value> Specify target triple (e.g. i686-apple-darwin9)
133135
! HELP-FC1-NEXT: -U <macro> Undefine macro <macro>
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
! Test -S (AArch64)
2+
3+
! REQUIRES: aarch64-registered-target
4+
5+
!-------------
6+
! RUN COMMANDS
7+
!-------------
8+
! RUN: %flang_fc1 -S -triple aarch64-unknown-linux-gnu %s -o - | FileCheck %s
9+
! RUN: %flang -S -target aarch64-unknown-linux-gnu %s -o - | FileCheck %s
10+
11+
!----------------
12+
! EXPECTED OUTPUT
13+
!----------------
14+
! CHECK-LABEL: _QQmain:
15+
! CHECK-NEXT: .Lfunc_begin0:
16+
! CHECK: ret
17+
18+
!------
19+
! INPUT
20+
!------
21+
end program

flang/test/Driver/emit-asm-x86.f90

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
! Test -S (X86)
2+
3+
! REQUIRES: x86-registered-target
4+
5+
!-------------
6+
! RUN COMMANDS
7+
!-------------
8+
! RUN: %flang_fc1 -S -triple x86_64-unknown-linux-gnu %s -o - | FileCheck %s
9+
! RUN: %flang -S -target x86_64-unknown-linux-gnu %s -o - | FileCheck %s
10+
11+
!----------------
12+
! EXPECTED OUTPUT
13+
!----------------
14+
! CHECK-LABEL: _QQmain:
15+
! CHECK-NEXT: .Lfunc_begin0:
16+
! CHECK: ret
17+
18+
!------
19+
! INPUT
20+
!------
21+
end program

flang/test/Driver/syntax-only.f90

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,15 @@
1313
! RUN: %flang -fsyntax-only %s 2>&1 | FileCheck %s --allow-empty
1414
! RUN: %flang_fc1 %s 2>&1 | FileCheck %s --allow-empty
1515

16-
! RUN: not %flang %s 2>&1 | FileCheck %s --check-prefix=NO_FSYNTAX_ONLY
17-
! RUN: not %flang_fc1 -emit-obj %s 2>&1 | FileCheck %s --check-prefix=NO_FSYNTAX_ONLY
16+
! RUN: rm -rf %t/non-existent-dir/
17+
! RUN: not %flang -c %s -o %t/non-existent-dir/syntax-only.o 2>&1 | FileCheck %s --check-prefix=NO_FSYNTAX_ONLY
18+
! RUN: not %flang_fc1 -emit-obj %s -o %t/non-existent-dir/syntax-only.o 2>&1 | FileCheck %s --check-prefix=NO_FSYNTAX_ONLY
1819

1920
!-----------------
2021
! EXPECTED OUTPUT
2122
!-----------------
2223
! CHECK-NOT: error
23-
! NO_FSYNTAX_ONLY: error: code-generation is not available yet
24+
! NO_FSYNTAX_ONLY: error: failed to create the output file
2425

2526
!-------
2627
! INPUT

0 commit comments

Comments
 (0)