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 = 76 std::make_unique<mlir::ModuleOp>(mlir::ModuleOp::create(loc, "mod")); 77 78 mlir::OpBuilder builder(mlirCtx.get()); 79 builder.setInsertionPointToStart(&mlirModule->getRegion().front()); 80 // Create a fake op to trip conversion to LLVM. 81 builder.create<test::dummy::FakeOp>(loc); 82 83 llvmCtx = std::make_unique<llvm::LLVMContext>(); 84 } 85 }; 86 87 TEST(CodeGenAction, GracefullyHandleLLVMConversionFailure) { 88 std::string diagnosticOutput; 89 llvm::raw_string_ostream diagnosticsOS(diagnosticOutput); 90 auto diagPrinter = std::make_unique<Fortran::frontend::TextDiagnosticPrinter>( 91 diagnosticsOS, new clang::DiagnosticOptions()); 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