1 //===- OperationSupportTest.cpp - Operation support unit 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 #include "mlir/IR/OperationSupport.h"
10 #include "mlir/IR/Builders.h"
11 #include "mlir/IR/BuiltinTypes.h"
12 #include "gtest/gtest.h"
13
14 using namespace mlir;
15 using namespace mlir::detail;
16
createOp(MLIRContext * context,ArrayRef<Value> operands=llvm::None,ArrayRef<Type> resultTypes=llvm::None,unsigned int numRegions=0)17 static Operation *createOp(MLIRContext *context,
18 ArrayRef<Value> operands = llvm::None,
19 ArrayRef<Type> resultTypes = llvm::None,
20 unsigned int numRegions = 0) {
21 context->allowUnregisteredDialects();
22 return Operation::create(UnknownLoc::get(context),
23 OperationName("foo.bar", context), resultTypes,
24 operands, llvm::None, llvm::None, numRegions);
25 }
26
27 namespace {
TEST(OperandStorageTest,NonResizable)28 TEST(OperandStorageTest, NonResizable) {
29 MLIRContext context;
30 Builder builder(&context);
31
32 Operation *useOp =
33 createOp(&context, /*operands=*/llvm::None, builder.getIntegerType(16));
34 Value operand = useOp->getResult(0);
35
36 // Create a non-resizable operation with one operand.
37 Operation *user = createOp(&context, operand);
38
39 // The same number of operands is okay.
40 user->setOperands(operand);
41 EXPECT_EQ(user->getNumOperands(), 1u);
42
43 // Removing is okay.
44 user->setOperands(llvm::None);
45 EXPECT_EQ(user->getNumOperands(), 0u);
46
47 // Destroy the operations.
48 user->destroy();
49 useOp->destroy();
50 }
51
TEST(OperandStorageTest,Resizable)52 TEST(OperandStorageTest, Resizable) {
53 MLIRContext context;
54 Builder builder(&context);
55
56 Operation *useOp =
57 createOp(&context, /*operands=*/llvm::None, builder.getIntegerType(16));
58 Value operand = useOp->getResult(0);
59
60 // Create a resizable operation with one operand.
61 Operation *user = createOp(&context, operand);
62
63 // The same number of operands is okay.
64 user->setOperands(operand);
65 EXPECT_EQ(user->getNumOperands(), 1u);
66
67 // Removing is okay.
68 user->setOperands(llvm::None);
69 EXPECT_EQ(user->getNumOperands(), 0u);
70
71 // Adding more operands is okay.
72 user->setOperands({operand, operand, operand});
73 EXPECT_EQ(user->getNumOperands(), 3u);
74
75 // Destroy the operations.
76 user->destroy();
77 useOp->destroy();
78 }
79
TEST(OperandStorageTest,RangeReplace)80 TEST(OperandStorageTest, RangeReplace) {
81 MLIRContext context;
82 Builder builder(&context);
83
84 Operation *useOp =
85 createOp(&context, /*operands=*/llvm::None, builder.getIntegerType(16));
86 Value operand = useOp->getResult(0);
87
88 // Create a resizable operation with one operand.
89 Operation *user = createOp(&context, operand);
90
91 // Check setting with the same number of operands.
92 user->setOperands(/*start=*/0, /*length=*/1, operand);
93 EXPECT_EQ(user->getNumOperands(), 1u);
94
95 // Check setting with more operands.
96 user->setOperands(/*start=*/0, /*length=*/1, {operand, operand, operand});
97 EXPECT_EQ(user->getNumOperands(), 3u);
98
99 // Check setting with less operands.
100 user->setOperands(/*start=*/1, /*length=*/2, {operand});
101 EXPECT_EQ(user->getNumOperands(), 2u);
102
103 // Check inserting without replacing operands.
104 user->setOperands(/*start=*/2, /*length=*/0, {operand});
105 EXPECT_EQ(user->getNumOperands(), 3u);
106
107 // Check erasing operands.
108 user->setOperands(/*start=*/0, /*length=*/3, {});
109 EXPECT_EQ(user->getNumOperands(), 0u);
110
111 // Destroy the operations.
112 user->destroy();
113 useOp->destroy();
114 }
115
TEST(OperandStorageTest,MutableRange)116 TEST(OperandStorageTest, MutableRange) {
117 MLIRContext context;
118 Builder builder(&context);
119
120 Operation *useOp =
121 createOp(&context, /*operands=*/llvm::None, builder.getIntegerType(16));
122 Value operand = useOp->getResult(0);
123
124 // Create a resizable operation with one operand.
125 Operation *user = createOp(&context, operand);
126
127 // Check setting with the same number of operands.
128 MutableOperandRange mutableOperands(user);
129 mutableOperands.assign(operand);
130 EXPECT_EQ(mutableOperands.size(), 1u);
131 EXPECT_EQ(user->getNumOperands(), 1u);
132
133 // Check setting with more operands.
134 mutableOperands.assign({operand, operand, operand});
135 EXPECT_EQ(mutableOperands.size(), 3u);
136 EXPECT_EQ(user->getNumOperands(), 3u);
137
138 // Check with inserting a new operand.
139 mutableOperands.append({operand, operand});
140 EXPECT_EQ(mutableOperands.size(), 5u);
141 EXPECT_EQ(user->getNumOperands(), 5u);
142
143 // Check erasing operands.
144 mutableOperands.clear();
145 EXPECT_EQ(mutableOperands.size(), 0u);
146 EXPECT_EQ(user->getNumOperands(), 0u);
147
148 // Destroy the operations.
149 user->destroy();
150 useOp->destroy();
151 }
152
TEST(OperationOrderTest,OrderIsAlwaysValid)153 TEST(OperationOrderTest, OrderIsAlwaysValid) {
154 MLIRContext context;
155 Builder builder(&context);
156
157 Operation *containerOp =
158 createOp(&context, /*operands=*/llvm::None, /*resultTypes=*/llvm::None,
159 /*numRegions=*/1);
160 Region ®ion = containerOp->getRegion(0);
161 Block *block = new Block();
162 region.push_back(block);
163
164 // Insert two operations, then iteratively add more operations in the middle
165 // of them. Eventually we will insert more than kOrderStride operations and
166 // the block order will need to be recomputed.
167 Operation *frontOp = createOp(&context);
168 Operation *backOp = createOp(&context);
169 block->push_back(frontOp);
170 block->push_back(backOp);
171
172 // Chosen to be larger than Operation::kOrderStride.
173 int kNumOpsToInsert = 10;
174 for (int i = 0; i < kNumOpsToInsert; ++i) {
175 Operation *op = createOp(&context);
176 block->getOperations().insert(backOp->getIterator(), op);
177 ASSERT_TRUE(op->isBeforeInBlock(backOp));
178 // Note verifyOpOrder() returns false if the order is valid.
179 ASSERT_FALSE(block->verifyOpOrder());
180 }
181
182 containerOp->destroy();
183 }
184
185 } // end namespace
186