File: RuntimeCallTestBase.h

package info (click to toggle)
swiftlang 6.0.3-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 2,519,992 kB
  • sloc: cpp: 9,107,863; ansic: 2,040,022; asm: 1,135,751; python: 296,500; objc: 82,456; f90: 60,502; lisp: 34,951; pascal: 19,946; sh: 18,133; perl: 7,482; ml: 4,937; javascript: 4,117; makefile: 3,840; awk: 3,535; xml: 914; fortran: 619; cs: 573; ruby: 573
file content (154 lines) | stat: -rw-r--r-- 5,880 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
//===- 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/Dialect/Support/KindMapping.h"
#include "flang/Optimizer/Support/InitFIR.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::func::FuncOp func =
        mlir::func::FuncOp::create(loc, "runtime_unit_tests_func",
            builder.getFunctionType(std::nullopt, std::nullopt));
    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()));

    char1Ty = fir::CharacterType::getSingleton(builder.getContext(), 1);
    char2Ty = fir::CharacterType::getSingleton(builder.getContext(), 2);
    char4Ty = fir::CharacterType::getSingleton(builder.getContext(), 4);
  }

  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;
  mlir::Type char1Ty;
  mlir::Type char2Ty;
  mlir::Type char4Ty;
};

/// 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().has_value());
  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