Files
clang-p2996/flang/unittests/Optimizer/Builder/Runtime/RuntimeCallTestBase.h
River Riddle 3655069234 [mlir] Move the Builtin FuncOp to the Func dialect
This commit moves FuncOp out of the builtin dialect, and into the Func
dialect. This move has been planned in some capacity from the moment
we made FuncOp an operation (years ago). This commit handles the
functional aspects of the move, but various aspects are left untouched
to ease migration: func::FuncOp is re-exported into mlir to reduce
the actual API churn, the assembly format still accepts the unqualified
`func`. These temporary measures will remain for a little while to
simplify migration before being removed.

Differential Revision: https://reviews.llvm.org/D121266
2022-03-16 17:07:03 -07:00

147 lines
5.4 KiB
C++

//===- RuntimeCallTestBase.cpp -- Base for runtime call generation tests --===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef FORTRAN_OPTIMIZER_BUILDER_RUNTIME_RUNTIMECALLTESTBASE_H
#define FORTRAN_OPTIMIZER_BUILDER_RUNTIME_RUNTIMECALLTESTBASE_H
#include "gtest/gtest.h"
#include "flang/Optimizer/Builder/FIRBuilder.h"
#include "flang/Optimizer/Support/InitFIR.h"
#include "flang/Optimizer/Support/KindMapping.h"
struct RuntimeCallTest : public testing::Test {
public:
void SetUp() override {
fir::support::loadDialects(context);
mlir::OpBuilder builder(&context);
auto loc = builder.getUnknownLoc();
// Set up a Module with a dummy function operation inside.
// Set the insertion point in the function entry block.
mlir::ModuleOp mod = builder.create<mlir::ModuleOp>(loc);
mlir::FuncOp func = mlir::FuncOp::create(loc, "runtime_unit_tests_func",
builder.getFunctionType(llvm::None, llvm::None));
auto *entryBlock = func.addEntryBlock();
mod.push_back(mod);
builder.setInsertionPointToStart(entryBlock);
kindMap = std::make_unique<fir::KindMapping>(&context);
firBuilder = std::make_unique<fir::FirOpBuilder>(mod, *kindMap);
i1Ty = firBuilder->getI1Type();
i8Ty = firBuilder->getI8Type();
i16Ty = firBuilder->getIntegerType(16);
i32Ty = firBuilder->getI32Type();
i64Ty = firBuilder->getI64Type();
i128Ty = firBuilder->getIntegerType(128);
f32Ty = firBuilder->getF32Type();
f64Ty = firBuilder->getF64Type();
f80Ty = firBuilder->getF80Type();
f128Ty = firBuilder->getF128Type();
c4Ty = fir::ComplexType::get(firBuilder->getContext(), 4);
c8Ty = fir::ComplexType::get(firBuilder->getContext(), 8);
c10Ty = fir::ComplexType::get(firBuilder->getContext(), 10);
c16Ty = fir::ComplexType::get(firBuilder->getContext(), 16);
seqTy10 = fir::SequenceType::get(fir::SequenceType::Shape(1, 10), i32Ty);
boxTy = fir::BoxType::get(mlir::NoneType::get(firBuilder->getContext()));
}
mlir::MLIRContext context;
std::unique_ptr<fir::KindMapping> kindMap;
std::unique_ptr<fir::FirOpBuilder> firBuilder;
// Commonly used types
mlir::Type i1Ty;
mlir::Type i8Ty;
mlir::Type i16Ty;
mlir::Type i32Ty;
mlir::Type i64Ty;
mlir::Type i128Ty;
mlir::Type f32Ty;
mlir::Type f64Ty;
mlir::Type f80Ty;
mlir::Type f128Ty;
mlir::Type c4Ty;
mlir::Type c8Ty;
mlir::Type c10Ty;
mlir::Type c16Ty;
mlir::Type seqTy10;
mlir::Type boxTy;
};
/// Check that the \p op is a `fir::CallOp` operation and its name matches
/// \p fctName and the number of arguments is equal to \p nbArgs.
/// Most runtime calls have two additional location arguments added. These are
/// added in this check when \p addLocArgs is true.
static inline void checkCallOp(mlir::Operation *op, llvm::StringRef fctName,
unsigned nbArgs, bool addLocArgs = true) {
EXPECT_TRUE(mlir::isa<fir::CallOp>(*op));
auto callOp = mlir::dyn_cast<fir::CallOp>(*op);
EXPECT_TRUE(callOp.getCallee().hasValue());
mlir::SymbolRefAttr callee = *callOp.getCallee();
EXPECT_EQ(fctName, callee.getRootReference().getValue());
// sourceFile and sourceLine are added arguments.
if (addLocArgs)
nbArgs += 2;
EXPECT_EQ(nbArgs, callOp.getArgs().size());
}
/// Check the call operation from the \p result value. In some cases the
/// value is directly used in the call and sometimes there is an indirection
/// through a `fir.convert` operation. Once the `fir.call` operation is
/// retrieved the check is made by `checkCallOp`.
///
/// Directly used in `fir.call`.
/// ```
/// %result = arith.constant 1 : i32
/// %0 = fir.call @foo(%result) : (i32) -> i1
/// ```
///
/// Value used in `fir.call` through `fir.convert` indirection.
/// ```
/// %result = arith.constant 1 : i32
/// %arg = fir.convert %result : (i32) -> i16
/// %0 = fir.call @foo(%arg) : (i16) -> i1
/// ```
static inline void checkCallOpFromResultBox(mlir::Value result,
llvm::StringRef fctName, unsigned nbArgs, bool addLocArgs = true) {
EXPECT_TRUE(result.hasOneUse());
const auto &u = result.user_begin();
if (mlir::isa<fir::CallOp>(*u))
return checkCallOp(*u, fctName, nbArgs, addLocArgs);
auto convOp = mlir::dyn_cast<fir::ConvertOp>(*u);
EXPECT_NE(nullptr, convOp);
checkCallOpFromResultBox(convOp.getResult(), fctName, nbArgs, addLocArgs);
}
/// Check the operations in \p block for a `fir::CallOp` operation where the
/// function being called shares its function name with \p fctName and the
/// number of arguments is equal to \p nbArgs. Note that this check only cares
/// if the operation exists, and not the order in when the operation is called.
/// This results in exiting the test as soon as the first correct instance of
/// `fir::CallOp` is found).
static inline void checkBlockForCallOp(
mlir::Block *block, llvm::StringRef fctName, unsigned nbArgs) {
assert(block && "mlir::Block given is a nullptr");
for (auto &op : block->getOperations()) {
if (auto callOp = mlir::dyn_cast<fir::CallOp>(op)) {
if (fctName == callOp.getCallee()->getRootReference().getValue()) {
EXPECT_EQ(nbArgs, callOp.getArgs().size());
return;
}
}
}
FAIL() << "No calls to " << fctName << " were found!";
}
#endif // FORTRAN_OPTIMIZER_BUILDER_RUNTIME_RUNTIMECALLTESTBASE_H