xref: /llvm-project/flang/unittests/Frontend/CodeGenActionTest.cpp (revision c870632ef6162fbdccaad8cd09420728220ad344)
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