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 auto diagPrinter = std::make_unique<Fortran::frontend::TextDiagnosticPrinter>( 90 diagnosticsOS, new clang::DiagnosticOptions()); 91 92 CompilerInstance ci; 93 ci.createDiagnostics(diagPrinter.get(), /*ShouldOwnClient=*/false); 94 ci.setInvocation(std::make_shared<CompilerInvocation>()); 95 ci.setOutputStream(std::make_unique<llvm::raw_null_ostream>()); 96 ci.getInvocation().getCodeGenOpts().OptimizationLevel = 0; 97 98 FrontendInputFile file("/dev/null", InputKind()); 99 100 LLVMConversionFailureCodeGenAction action; 101 action.setInstance(&ci); 102 action.setCurrentInput(file); 103 104 consumeError(action.execute()); 105 ASSERT_EQ(diagnosticOutput, 106 "error: Lowering to LLVM IR failed\n" 107 "error: failed to create the LLVM module\n"); 108 } 109