xref: /llvm-project/flang/unittests/Optimizer/Builder/Runtime/RuntimeCallTestBase.h (revision c870632ef6162fbdccaad8cd09420728220ad344)
11b3cd35aSValentin Clement //===- RuntimeCallTestBase.cpp -- Base for runtime call generation tests --===//
21b3cd35aSValentin Clement //
31b3cd35aSValentin Clement // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
41b3cd35aSValentin Clement // See https://llvm.org/LICENSE.txt for license information.
51b3cd35aSValentin Clement // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
61b3cd35aSValentin Clement //
71b3cd35aSValentin Clement //===----------------------------------------------------------------------===//
81b3cd35aSValentin Clement 
91b3cd35aSValentin Clement #ifndef FORTRAN_OPTIMIZER_BUILDER_RUNTIME_RUNTIMECALLTESTBASE_H
101b3cd35aSValentin Clement #define FORTRAN_OPTIMIZER_BUILDER_RUNTIME_RUNTIMECALLTESTBASE_H
111b3cd35aSValentin Clement 
121b3cd35aSValentin Clement #include "gtest/gtest.h"
131b3cd35aSValentin Clement #include "flang/Optimizer/Builder/FIRBuilder.h"
14b07ef9e7SRenaud-K #include "flang/Optimizer/Dialect/Support/KindMapping.h"
151b3cd35aSValentin Clement #include "flang/Optimizer/Support/InitFIR.h"
161b3cd35aSValentin Clement 
171b3cd35aSValentin Clement struct RuntimeCallTest : public testing::Test {
181b3cd35aSValentin Clement public:
191b3cd35aSValentin Clement   void SetUp() override {
2036550692SRiver Riddle     fir::support::loadDialects(context);
2136550692SRiver Riddle 
221b3cd35aSValentin Clement     mlir::OpBuilder builder(&context);
231b3cd35aSValentin Clement     auto loc = builder.getUnknownLoc();
241b3cd35aSValentin Clement 
251b3cd35aSValentin Clement     // Set up a Module with a dummy function operation inside.
261b3cd35aSValentin Clement     // Set the insertion point in the function entry block.
27*c870632eSMatthias Springer     moduleOp = builder.create<mlir::ModuleOp>(loc);
28*c870632eSMatthias Springer     builder.setInsertionPointToStart(moduleOp->getBody());
2958ceae95SRiver Riddle     mlir::func::FuncOp func =
30*c870632eSMatthias Springer         builder.create<mlir::func::FuncOp>(loc, "runtime_unit_tests_func",
3163b63c3dSKazu Hirata             builder.getFunctionType(std::nullopt, std::nullopt));
321b3cd35aSValentin Clement     auto *entryBlock = func.addEntryBlock();
331b3cd35aSValentin Clement     builder.setInsertionPointToStart(entryBlock);
341b3cd35aSValentin Clement 
351b3cd35aSValentin Clement     kindMap = std::make_unique<fir::KindMapping>(&context);
36*c870632eSMatthias Springer     firBuilder = std::make_unique<fir::FirOpBuilder>(builder, *kindMap);
371b3cd35aSValentin Clement 
385ebbcfa0SJosh Mottley     i1Ty = firBuilder->getI1Type();
391b3cd35aSValentin Clement     i8Ty = firBuilder->getI8Type();
401b3cd35aSValentin Clement     i16Ty = firBuilder->getIntegerType(16);
411b3cd35aSValentin Clement     i32Ty = firBuilder->getI32Type();
421b3cd35aSValentin Clement     i64Ty = firBuilder->getI64Type();
431b3cd35aSValentin Clement     i128Ty = firBuilder->getIntegerType(128);
441b3cd35aSValentin Clement 
451b3cd35aSValentin Clement     f32Ty = firBuilder->getF32Type();
461b3cd35aSValentin Clement     f64Ty = firBuilder->getF64Type();
471b3cd35aSValentin Clement     f80Ty = firBuilder->getF80Type();
481b3cd35aSValentin Clement     f128Ty = firBuilder->getF128Type();
491b3cd35aSValentin Clement 
50c4204c0bSjeanPerier     c4Ty = mlir::ComplexType::get(f32Ty);
51c4204c0bSjeanPerier     c8Ty = mlir::ComplexType::get(f64Ty);
52c4204c0bSjeanPerier     c10Ty = mlir::ComplexType::get(f80Ty);
53c4204c0bSjeanPerier     c16Ty = mlir::ComplexType::get(f128Ty);
54f6ae8e8cSValentin Clement 
55f6ae8e8cSValentin Clement     seqTy10 = fir::SequenceType::get(fir::SequenceType::Shape(1, 10), i32Ty);
56d59a0f58SValentin Clement     boxTy = fir::BoxType::get(mlir::NoneType::get(firBuilder->getContext()));
579f6aae46SSlava Zakharin 
589f6aae46SSlava Zakharin     char1Ty = fir::CharacterType::getSingleton(builder.getContext(), 1);
599f6aae46SSlava Zakharin     char2Ty = fir::CharacterType::getSingleton(builder.getContext(), 2);
609f6aae46SSlava Zakharin     char4Ty = fir::CharacterType::getSingleton(builder.getContext(), 4);
618ce1aed5SSlava Zakharin 
628ce1aed5SSlava Zakharin     logical1Ty = fir::LogicalType::get(builder.getContext(), 1);
638ce1aed5SSlava Zakharin     logical2Ty = fir::LogicalType::get(builder.getContext(), 2);
648ce1aed5SSlava Zakharin     logical4Ty = fir::LogicalType::get(builder.getContext(), 4);
658ce1aed5SSlava Zakharin     logical8Ty = fir::LogicalType::get(builder.getContext(), 8);
661b3cd35aSValentin Clement   }
671b3cd35aSValentin Clement 
681b3cd35aSValentin Clement   mlir::MLIRContext context;
69*c870632eSMatthias Springer   mlir::OwningOpRef<mlir::ModuleOp> moduleOp;
701b3cd35aSValentin Clement   std::unique_ptr<fir::KindMapping> kindMap;
711b3cd35aSValentin Clement   std::unique_ptr<fir::FirOpBuilder> firBuilder;
721b3cd35aSValentin Clement 
731b3cd35aSValentin Clement   // Commonly used types
745ebbcfa0SJosh Mottley   mlir::Type i1Ty;
751b3cd35aSValentin Clement   mlir::Type i8Ty;
761b3cd35aSValentin Clement   mlir::Type i16Ty;
771b3cd35aSValentin Clement   mlir::Type i32Ty;
781b3cd35aSValentin Clement   mlir::Type i64Ty;
791b3cd35aSValentin Clement   mlir::Type i128Ty;
801b3cd35aSValentin Clement   mlir::Type f32Ty;
811b3cd35aSValentin Clement   mlir::Type f64Ty;
821b3cd35aSValentin Clement   mlir::Type f80Ty;
831b3cd35aSValentin Clement   mlir::Type f128Ty;
841b3cd35aSValentin Clement   mlir::Type c4Ty;
851b3cd35aSValentin Clement   mlir::Type c8Ty;
861b3cd35aSValentin Clement   mlir::Type c10Ty;
871b3cd35aSValentin Clement   mlir::Type c16Ty;
88f6ae8e8cSValentin Clement   mlir::Type seqTy10;
89d59a0f58SValentin Clement   mlir::Type boxTy;
909f6aae46SSlava Zakharin   mlir::Type char1Ty;
919f6aae46SSlava Zakharin   mlir::Type char2Ty;
929f6aae46SSlava Zakharin   mlir::Type char4Ty;
938ce1aed5SSlava Zakharin   mlir::Type logical1Ty;
948ce1aed5SSlava Zakharin   mlir::Type logical2Ty;
958ce1aed5SSlava Zakharin   mlir::Type logical4Ty;
968ce1aed5SSlava Zakharin   mlir::Type logical8Ty;
971b3cd35aSValentin Clement };
981b3cd35aSValentin Clement 
991b3cd35aSValentin Clement /// Check that the \p op is a `fir::CallOp` operation and its name matches
1001b3cd35aSValentin Clement /// \p fctName and the number of arguments is equal to \p nbArgs.
1011b3cd35aSValentin Clement /// Most runtime calls have two additional location arguments added. These are
1021b3cd35aSValentin Clement /// added in this check when \p addLocArgs is true.
10399961b4fSValentin Clement static inline void checkCallOp(mlir::Operation *op, llvm::StringRef fctName,
1041b3cd35aSValentin Clement     unsigned nbArgs, bool addLocArgs = true) {
1051b3cd35aSValentin Clement   EXPECT_TRUE(mlir::isa<fir::CallOp>(*op));
1061b3cd35aSValentin Clement   auto callOp = mlir::dyn_cast<fir::CallOp>(*op);
107c82fb16fSKazu Hirata   EXPECT_TRUE(callOp.getCallee().has_value());
108149ad3d5SShraiysh Vaishay   mlir::SymbolRefAttr callee = *callOp.getCallee();
1091b3cd35aSValentin Clement   EXPECT_EQ(fctName, callee.getRootReference().getValue());
1101b3cd35aSValentin Clement   // sourceFile and sourceLine are added arguments.
1111b3cd35aSValentin Clement   if (addLocArgs)
1121b3cd35aSValentin Clement     nbArgs += 2;
113149ad3d5SShraiysh Vaishay   EXPECT_EQ(nbArgs, callOp.getArgs().size());
1141b3cd35aSValentin Clement }
1151b3cd35aSValentin Clement 
1161b3cd35aSValentin Clement /// Check the call operation from the \p result value. In some cases the
1171b3cd35aSValentin Clement /// value is directly used in the call and sometimes there is an indirection
1181b3cd35aSValentin Clement /// through a `fir.convert` operation. Once the `fir.call` operation is
1191b3cd35aSValentin Clement /// retrieved the check is made by `checkCallOp`.
1201b3cd35aSValentin Clement ///
1211b3cd35aSValentin Clement /// Directly used in `fir.call`.
1221b3cd35aSValentin Clement /// ```
1231b3cd35aSValentin Clement /// %result = arith.constant 1 : i32
1241b3cd35aSValentin Clement /// %0 = fir.call @foo(%result) : (i32) -> i1
1251b3cd35aSValentin Clement /// ```
1261b3cd35aSValentin Clement ///
1271b3cd35aSValentin Clement /// Value used in `fir.call` through `fir.convert` indirection.
1281b3cd35aSValentin Clement /// ```
1291b3cd35aSValentin Clement /// %result = arith.constant 1 : i32
1301b3cd35aSValentin Clement /// %arg = fir.convert %result : (i32) -> i16
1311b3cd35aSValentin Clement /// %0 = fir.call @foo(%arg) : (i16) -> i1
1321b3cd35aSValentin Clement /// ```
13399961b4fSValentin Clement static inline void checkCallOpFromResultBox(mlir::Value result,
1341b3cd35aSValentin Clement     llvm::StringRef fctName, unsigned nbArgs, bool addLocArgs = true) {
1351b3cd35aSValentin Clement   EXPECT_TRUE(result.hasOneUse());
1361b3cd35aSValentin Clement   const auto &u = result.user_begin();
1371b3cd35aSValentin Clement   if (mlir::isa<fir::CallOp>(*u))
1381b3cd35aSValentin Clement     return checkCallOp(*u, fctName, nbArgs, addLocArgs);
1391b3cd35aSValentin Clement   auto convOp = mlir::dyn_cast<fir::ConvertOp>(*u);
1401b3cd35aSValentin Clement   EXPECT_NE(nullptr, convOp);
1411b3cd35aSValentin Clement   checkCallOpFromResultBox(convOp.getResult(), fctName, nbArgs, addLocArgs);
1421b3cd35aSValentin Clement }
1431b3cd35aSValentin Clement 
144ce8022faSJosh Mottley /// Check the operations in \p block for a `fir::CallOp` operation where the
145ce8022faSJosh Mottley /// function being called shares its function name with \p fctName and the
146ce8022faSJosh Mottley /// number of arguments is equal to \p nbArgs. Note that this check only cares
147ce8022faSJosh Mottley /// if the operation exists, and not the order in when the operation is called.
148ce8022faSJosh Mottley /// This results in exiting the test as soon as the first correct instance of
149ce8022faSJosh Mottley /// `fir::CallOp` is found).
150ce8022faSJosh Mottley static inline void checkBlockForCallOp(
151ce8022faSJosh Mottley     mlir::Block *block, llvm::StringRef fctName, unsigned nbArgs) {
152ce8022faSJosh Mottley   assert(block && "mlir::Block given is a nullptr");
153ce8022faSJosh Mottley   for (auto &op : block->getOperations()) {
154ce8022faSJosh Mottley     if (auto callOp = mlir::dyn_cast<fir::CallOp>(op)) {
155149ad3d5SShraiysh Vaishay       if (fctName == callOp.getCallee()->getRootReference().getValue()) {
156149ad3d5SShraiysh Vaishay         EXPECT_EQ(nbArgs, callOp.getArgs().size());
157ce8022faSJosh Mottley         return;
158ce8022faSJosh Mottley       }
159ce8022faSJosh Mottley     }
160ce8022faSJosh Mottley   }
161ce8022faSJosh Mottley   FAIL() << "No calls to " << fctName << " were found!";
162ce8022faSJosh Mottley }
163ce8022faSJosh Mottley 
1641b3cd35aSValentin Clement #endif // FORTRAN_OPTIMIZER_BUILDER_RUNTIME_RUNTIMECALLTESTBASE_H
165