| 1 | //===- unittests/Frontend/CodeGenActionTest.cpp --- FrontendAction tests --===// |
| 2 | // |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| 4 | // See https://llvm.org/LICENSE.txt for license information. |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| 6 | // |
| 7 | //===----------------------------------------------------------------------===// |
| 8 | // |
| 9 | // Unit tests for CodeGenAction. |
| 10 | // |
| 11 | //===----------------------------------------------------------------------===// |
| 12 | |
| 13 | #include "mlir/IR/Builders.h" |
| 14 | #include "flang/Frontend/CompilerInstance.h" |
| 15 | #include "flang/Frontend/FrontendActions.h" |
| 16 | #include "flang/Frontend/TextDiagnosticPrinter.h" |
| 17 | |
| 18 | #include "gtest/gtest.h" |
| 19 | |
| 20 | #include <memory> |
| 21 | |
| 22 | using namespace Fortran::frontend; |
| 23 | |
| 24 | namespace test { |
| 25 | class DummyDialect : public ::mlir::Dialect { |
| 26 | explicit DummyDialect(::mlir::MLIRContext *context) |
| 27 | : ::mlir::Dialect(getDialectNamespace(), context, |
| 28 | ::mlir::TypeID::get<DummyDialect>()) { |
| 29 | initialize(); |
| 30 | } |
| 31 | |
| 32 | void initialize(); |
| 33 | friend class ::mlir::MLIRContext; |
| 34 | |
| 35 | public: |
| 36 | ~DummyDialect() override = default; |
| 37 | static constexpr ::llvm::StringLiteral getDialectNamespace() { |
| 38 | return ::llvm::StringLiteral("dummy" ); |
| 39 | } |
| 40 | }; |
| 41 | |
| 42 | namespace dummy { |
| 43 | class FakeOp : public ::mlir::Op<FakeOp> { |
| 44 | public: |
| 45 | using Op::Op; |
| 46 | |
| 47 | static llvm::StringRef getOperationName() { return "dummy.fake" ; } |
| 48 | |
| 49 | static ::llvm::ArrayRef<::llvm::StringRef> getAttributeNames() { return {}; } |
| 50 | |
| 51 | static void build( |
| 52 | ::mlir::OpBuilder &odsBuilder, ::mlir::OperationState &odsState) {} |
| 53 | }; |
| 54 | } // namespace dummy |
| 55 | } // namespace test |
| 56 | |
| 57 | MLIR_DECLARE_EXPLICIT_TYPE_ID(::test::DummyDialect) |
| 58 | MLIR_DEFINE_EXPLICIT_TYPE_ID(::test::DummyDialect) |
| 59 | |
| 60 | namespace test { |
| 61 | |
| 62 | void DummyDialect::initialize() { addOperations<::test::dummy::FakeOp>(); } |
| 63 | } // namespace test |
| 64 | |
| 65 | // A test CodeGenAction to verify that we gracefully handle failure to convert |
| 66 | // from MLIR to LLVM IR. |
| 67 | class LLVMConversionFailureCodeGenAction : public CodeGenAction { |
| 68 | public: |
| 69 | LLVMConversionFailureCodeGenAction() |
| 70 | : CodeGenAction(BackendActionTy::Backend_EmitLL) { |
| 71 | mlirCtx = std::make_unique<mlir::MLIRContext>(); |
| 72 | mlirCtx->loadDialect<test::DummyDialect>(); |
| 73 | |
| 74 | mlir::Location loc(mlir::UnknownLoc::get(mlirCtx.get())); |
| 75 | mlirModule = mlir::ModuleOp::create(loc, "mod" ); |
| 76 | |
| 77 | mlir::OpBuilder builder(mlirCtx.get()); |
| 78 | builder.setInsertionPointToStart(&mlirModule->getRegion().front()); |
| 79 | // Create a fake op to trip conversion to LLVM. |
| 80 | builder.create<test::dummy::FakeOp>(loc); |
| 81 | |
| 82 | llvmCtx = std::make_unique<llvm::LLVMContext>(); |
| 83 | } |
| 84 | }; |
| 85 | |
| 86 | TEST(CodeGenAction, GracefullyHandleLLVMConversionFailure) { |
| 87 | std::string diagnosticOutput; |
| 88 | llvm::raw_string_ostream diagnosticsOS(diagnosticOutput); |
| 89 | clang::DiagnosticOptions diagOpts; |
| 90 | auto diagPrinter = std::make_unique<Fortran::frontend::TextDiagnosticPrinter>( |
| 91 | diagnosticsOS, diagOpts); |
| 92 | |
| 93 | CompilerInstance ci; |
| 94 | ci.createDiagnostics(diagPrinter.get(), /*ShouldOwnClient=*/false); |
| 95 | ci.setInvocation(std::make_shared<CompilerInvocation>()); |
| 96 | ci.setOutputStream(std::make_unique<llvm::raw_null_ostream>()); |
| 97 | ci.getInvocation().getCodeGenOpts().OptimizationLevel = 0; |
| 98 | |
| 99 | FrontendInputFile file("/dev/null" , InputKind()); |
| 100 | |
| 101 | LLVMConversionFailureCodeGenAction action; |
| 102 | action.setInstance(&ci); |
| 103 | action.setCurrentInput(file); |
| 104 | |
| 105 | consumeError(action.execute()); |
| 106 | ASSERT_EQ(diagnosticOutput, |
| 107 | "error: Lowering to LLVM IR failed\n" |
| 108 | "error: failed to create the LLVM module\n" ); |
| 109 | } |
| 110 | |