119 lines · cpp
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-exception6//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 22using namespace Fortran::frontend;23 24namespace test {25class 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 35public:36 ~DummyDialect() override = default;37 static constexpr ::llvm::StringLiteral getDialectNamespace() {38 return ::llvm::StringLiteral("dummy");39 }40};41 42namespace dummy {43class FakeOp : public ::mlir::Op<FakeOp> {44public: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 static FakeOp create(55 ::mlir::OpBuilder &odsBuilder, ::mlir::Location location) {56 ::mlir::OperationState state(location, getOperationName());57 build(odsBuilder, state);58 auto res = ::llvm::dyn_cast<FakeOp>(odsBuilder.create(state));59 assert(res && "builder didn't return the right type");60 return res;61 }62};63} // namespace dummy64} // namespace test65 66MLIR_DECLARE_EXPLICIT_TYPE_ID(::test::DummyDialect)67MLIR_DEFINE_EXPLICIT_TYPE_ID(::test::DummyDialect)68 69namespace test {70 71void DummyDialect::initialize() { addOperations<::test::dummy::FakeOp>(); }72} // namespace test73 74// A test CodeGenAction to verify that we gracefully handle failure to convert75// from MLIR to LLVM IR.76class LLVMConversionFailureCodeGenAction : public CodeGenAction {77public:78 LLVMConversionFailureCodeGenAction()79 : CodeGenAction(BackendActionTy::Backend_EmitLL) {80 mlirCtx = std::make_unique<mlir::MLIRContext>();81 mlirCtx->loadDialect<test::DummyDialect>();82 83 mlir::Location loc(mlir::UnknownLoc::get(mlirCtx.get()));84 mlirModule = mlir::ModuleOp::create(loc, "mod");85 86 mlir::OpBuilder builder(mlirCtx.get());87 builder.setInsertionPointToStart(&mlirModule->getRegion().front());88 // Create a fake op to trip conversion to LLVM.89 test::dummy::FakeOp::create(builder, loc);90 91 llvmCtx = std::make_unique<llvm::LLVMContext>();92 }93};94 95TEST(CodeGenAction, GracefullyHandleLLVMConversionFailure) {96 std::string diagnosticOutput;97 llvm::raw_string_ostream diagnosticsOS(diagnosticOutput);98 clang::DiagnosticOptions diagOpts;99 auto diagPrinter = std::make_unique<Fortran::frontend::TextDiagnosticPrinter>(100 diagnosticsOS, diagOpts);101 102 CompilerInstance ci;103 ci.createDiagnostics(diagPrinter.get(), /*ShouldOwnClient=*/false);104 ci.setInvocation(std::make_shared<CompilerInvocation>());105 ci.setOutputStream(std::make_unique<llvm::raw_null_ostream>());106 ci.getInvocation().getCodeGenOpts().OptimizationLevel = 0;107 108 FrontendInputFile file("/dev/null", InputKind());109 110 LLVMConversionFailureCodeGenAction action;111 action.setInstance(&ci);112 action.setCurrentInput(file);113 114 consumeError(action.execute());115 ASSERT_EQ(diagnosticOutput,116 "error: Lowering to LLVM IR failed\n"117 "error: failed to create the LLVM module\n");118}119