[flang][driver] Add support for consuming LLVM IR/BC files

This change makes sure that Flang's driver recognises LLVM IR and BC as
supported file formats. To this end, `isFortran` is extended and renamed
as `isSupportedByFlang` (the latter better reflects the new
functionality).

New tests are added to verify that the target triple is correctly
overridden by the frontend driver's default value or the value specified
with `-triple`. Strictly speaking, this is not a functionality that's
new in this patch (it was added in D124664). This patch simply enables
us to write such tests and hence I'm including them here.

Differential Revision: https://reviews.llvm.org/D124667
This commit is contained in:
Andrzej Warzynski 2022-04-22 09:07:31 +00:00
parent ad2263de9f
commit b9f3b7f89a
11 changed files with 139 additions and 17 deletions

View File

@ -66,6 +66,9 @@ namespace types {
/// isAcceptedByClang - Can clang handle this input type.
bool isAcceptedByClang(ID Id);
/// isAcceptedByFlang - Can flang handle this input type.
bool isAcceptedByFlang(ID Id);
/// isDerivedFromC - Is the input derived from C.
///
/// That is, does the lexer follow the rules of
@ -92,9 +95,6 @@ namespace types {
/// isOpenCL - Is this an "OpenCL" input.
bool isOpenCL(ID Id);
/// isFortran - Is this a Fortran input.
bool isFortran(ID Id);
/// isSrcFile - Is this a source file, i.e. something that still has to be
/// preprocessed. The logic behind this is the same that decides if the first
/// compilation phase is a preprocessing one.

View File

@ -6050,11 +6050,12 @@ bool Driver::ShouldUseClangCompiler(const JobAction &JA) const {
bool Driver::ShouldUseFlangCompiler(const JobAction &JA) const {
// Say "no" if there is not exactly one input of a type flang understands.
if (JA.size() != 1 ||
!types::isFortran((*JA.input_begin())->getType()))
!types::isAcceptedByFlang((*JA.input_begin())->getType()))
return false;
// And say "no" if this is not a kind of action flang understands.
if (!isa<PreprocessJobAction>(JA) && !isa<CompileJobAction>(JA) && !isa<BackendJobAction>(JA))
if (!isa<PreprocessJobAction>(JA) && !isa<CompileJobAction>(JA) &&
!isa<BackendJobAction>(JA))
return false;
return true;

View File

@ -159,6 +159,20 @@ bool types::isAcceptedByClang(ID Id) {
}
}
bool types::isAcceptedByFlang(ID Id) {
switch (Id) {
default:
return false;
case TY_Fortran:
case TY_PP_Fortran:
return true;
case TY_LLVM_IR:
case TY_LLVM_BC:
return true;
}
}
bool types::isDerivedFromC(ID Id) {
switch (Id) {
default:
@ -272,16 +286,6 @@ bool types::isHIP(ID Id) {
}
}
bool types::isFortran(ID Id) {
switch (Id) {
default:
return false;
case TY_Fortran: case TY_PP_Fortran:
return true;
}
}
bool types::isSrcFile(ID Id) {
return Id != TY_Object && getPreprocessedType(Id) != TY_INVALID;
}

View File

@ -40,6 +40,7 @@ add_flang_library(flangFrontend
LINK_COMPONENTS
Passes
Analysis
IRReader
Option
Support
Target

View File

@ -73,6 +73,19 @@ bool PrescanAndSemaDebugAction::BeginSourceFileAction() {
}
bool CodeGenAction::BeginSourceFileAction() {
llvmCtx = std::make_unique<llvm::LLVMContext>();
// If the input is an LLVM file, just parse it and return.
if (this->currentInput().kind().GetLanguage() == Language::LLVM_IR) {
llvm::SMDiagnostic err;
llvmModule = llvm::parseIRFile(currentInput().file(), err, *llvmCtx);
return (nullptr != llvmModule);
}
// Otherwise, generate an MLIR module from the input Fortran source
assert(currentInput().kind().GetLanguage() == Language::Fortran &&
"Invalid input type - expecting a Fortran file");
bool res = RunPrescan() && RunParse() && RunSemanticChecks();
if (!res)
return res;
@ -448,7 +461,6 @@ void CodeGenAction::GenerateLLVMIR() {
// Translate to LLVM IR
llvm::Optional<llvm::StringRef> moduleName = mlirModule->getName();
llvmCtx = std::make_unique<llvm::LLVMContext>();
llvmModule = mlir::translateModuleToLLVMIR(
*mlirModule, *llvmCtx, moduleName ? *moduleName : "FIRModule");

View File

@ -35,5 +35,9 @@ InputKind FrontendOptions::GetInputKindForExtension(llvm::StringRef extension) {
if (isFixedFormSuffix(extension) || isFreeFormSuffix(extension)) {
return Language::Fortran;
}
if (extension == "bc" || extension == "ll")
return Language::LLVM_IR;
return Language::Unknown;
}

View File

@ -0,0 +1,30 @@
; Verify that the driver can consume LLVM BC files. The expected assembly is
; fairly generic (tested on AArch64 and X86_64), but we may need to tweak when
; testing on other platforms. Note that the actual output doesn't matter as
; long as it's in Assembly format.
;-------------
; RUN COMMANDS
;-------------
; RUN: rm -f %t.bc
; RUN: %flang_fc1 -emit-llvm-bc %s -o %t.bc
; RUN: %flang_fc1 -S -o - %t.bc | FileCheck %s
; RUN: rm -f %t.bc
; RUN: rm -f %t.bc
; RUN: %flang -c -emit-llvm %s -o %t.bc
; RUN: %flang -S -o - %t.bc | FileCheck %s
; RUN: rm -f %t.bc
;----------------
; EXPECTED OUTPUT
;----------------
; CHECK-LABEL: foo:
; CHECK: ret
;------
; INPUT
;------
define void @foo() {
ret void
}

View File

@ -0,0 +1,23 @@
; Verify that the driver can consume LLVM IR files. The expected assembly is
; fairly generic (verified on AArch64 and X86_64), but we may need to tweak when
; testing on other platforms. Note that the actual output doesn't matter
; as long as it's in Assembly format.
;-------------
; RUN COMMANDS
;-------------
; RUN: %flang_fc1 -S %s -o - | FileCheck %s
; RUN: %flang -S %s -o - | FileCheck %s
;----------------
; EXPECTED OUTPUT
;----------------
; CHECK-LABEL: foo:
; CHECK: ret
;------
; INPUT
;------
define void @foo() {
ret void
}

View File

@ -0,0 +1,21 @@
; Verify that the module triple is overridden by the driver - even when the
; module triple is missing.
; NOTE: At the time of writing, the tested behaviour was consistent with Clang
;-------------
; RUN COMMANDS
;-------------
; RUN: %flang_fc1 -S %s -o - 2>&1 | FileCheck %s
; RUN: %flang -S %s -o - 2>&1 | FileCheck %s
;----------------
; EXPECTED OUTPUT
;----------------
; CHECK: warning: overriding the module target triple with {{.*}}
;------
; INPUT
;------
define void @foo() {
ret void
}

View File

@ -0,0 +1,25 @@
; Verify that the module triple is overridden by the driver - even in the presence
; of a module triple.
; NOTE: At the time of writing, the tested behaviour was consistent with Clang
;-------------
; RUN COMMANDS
;-------------
; RUN: %flang_fc1 -S %s -o - 2>&1 | FileCheck %s
; RUN: %flang -S %s -o - 2>&1 | FileCheck %s
;----------------
; EXPECTED OUTPUT
;----------------
; CHECK: warning: overriding the module target triple with {{.*}}
;------
; INPUT
;------
; For the triple to be overridden by the driver, it needs to be different to the host triple.
; Use a random string to guarantee that.
target triple = "invalid-triple"
define void @foo() {
ret void
}

View File

@ -27,7 +27,8 @@ config.test_format = lit.formats.ShTest(not llvm_config.use_lit_shell)
# suffixes: A list of file extensions to treat as test files.
config.suffixes = ['.c', '.cpp', '.f', '.F', '.ff', '.FOR', '.for', '.f77', '.f90', '.F90',
'.ff90', '.f95', '.F95', '.ff95', '.fpp', '.FPP', '.cuf'
'.CUF', '.f18', '.F18', '.fir', '.f03', '.F03', '.f08', '.F08']
'.CUF', '.f18', '.F18', '.fir', '.f03', '.F03', '.f08',
'.F08', '.ll']
config.substitutions.append(('%PATH%', config.environment['PATH']))
config.substitutions.append(('%llvmshlibdir', config.llvm_shlib_dir))