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 "../../test/lib/Dialect/Test/TestDialect.h"
11 #include "mlir/IR/Builders.h"
12 #include "mlir/IR/BuiltinTypes.h"
13 #include "llvm/ADT/BitVector.h"
14 #include "llvm/Support/FormatVariadic.h"
15 #include "gtest/gtest.h"
16
17 using namespace mlir;
18 using namespace mlir::detail;
19
createOp(MLIRContext * context,ArrayRef<Value> operands=llvm::None,ArrayRef<Type> resultTypes=llvm::None,unsigned int numRegions=0)20 static Operation *createOp(MLIRContext *context,
21 ArrayRef<Value> operands = llvm::None,
22 ArrayRef<Type> resultTypes = llvm::None,
23 unsigned int numRegions = 0) {
24 context->allowUnregisteredDialects();
25 return Operation::create(UnknownLoc::get(context),
26 OperationName("foo.bar", context), resultTypes,
27 operands, llvm::None, llvm::None, numRegions);
28 }
29
30 namespace {
TEST(OperandStorageTest,NonResizable)31 TEST(OperandStorageTest, NonResizable) {
32 MLIRContext context;
33 Builder builder(&context);
34
35 Operation *useOp =
36 createOp(&context, /*operands=*/llvm::None, builder.getIntegerType(16));
37 Value operand = useOp->getResult(0);
38
39 // Create a non-resizable operation with one operand.
40 Operation *user = createOp(&context, operand);
41
42 // The same number of operands is okay.
43 user->setOperands(operand);
44 EXPECT_EQ(user->getNumOperands(), 1u);
45
46 // Removing is okay.
47 user->setOperands(llvm::None);
48 EXPECT_EQ(user->getNumOperands(), 0u);
49
50 // Destroy the operations.
51 user->destroy();
52 useOp->destroy();
53 }
54
TEST(OperandStorageTest,Resizable)55 TEST(OperandStorageTest, Resizable) {
56 MLIRContext context;
57 Builder builder(&context);
58
59 Operation *useOp =
60 createOp(&context, /*operands=*/llvm::None, builder.getIntegerType(16));
61 Value operand = useOp->getResult(0);
62
63 // Create a resizable operation with one operand.
64 Operation *user = createOp(&context, operand);
65
66 // The same number of operands is okay.
67 user->setOperands(operand);
68 EXPECT_EQ(user->getNumOperands(), 1u);
69
70 // Removing is okay.
71 user->setOperands(llvm::None);
72 EXPECT_EQ(user->getNumOperands(), 0u);
73
74 // Adding more operands is okay.
75 user->setOperands({operand, operand, operand});
76 EXPECT_EQ(user->getNumOperands(), 3u);
77
78 // Destroy the operations.
79 user->destroy();
80 useOp->destroy();
81 }
82
TEST(OperandStorageTest,RangeReplace)83 TEST(OperandStorageTest, RangeReplace) {
84 MLIRContext context;
85 Builder builder(&context);
86
87 Operation *useOp =
88 createOp(&context, /*operands=*/llvm::None, builder.getIntegerType(16));
89 Value operand = useOp->getResult(0);
90
91 // Create a resizable operation with one operand.
92 Operation *user = createOp(&context, operand);
93
94 // Check setting with the same number of operands.
95 user->setOperands(/*start=*/0, /*length=*/1, operand);
96 EXPECT_EQ(user->getNumOperands(), 1u);
97
98 // Check setting with more operands.
99 user->setOperands(/*start=*/0, /*length=*/1, {operand, operand, operand});
100 EXPECT_EQ(user->getNumOperands(), 3u);
101
102 // Check setting with less operands.
103 user->setOperands(/*start=*/1, /*length=*/2, {operand});
104 EXPECT_EQ(user->getNumOperands(), 2u);
105
106 // Check inserting without replacing operands.
107 user->setOperands(/*start=*/2, /*length=*/0, {operand});
108 EXPECT_EQ(user->getNumOperands(), 3u);
109
110 // Check erasing operands.
111 user->setOperands(/*start=*/0, /*length=*/3, {});
112 EXPECT_EQ(user->getNumOperands(), 0u);
113
114 // Destroy the operations.
115 user->destroy();
116 useOp->destroy();
117 }
118
TEST(OperandStorageTest,MutableRange)119 TEST(OperandStorageTest, MutableRange) {
120 MLIRContext context;
121 Builder builder(&context);
122
123 Operation *useOp =
124 createOp(&context, /*operands=*/llvm::None, builder.getIntegerType(16));
125 Value operand = useOp->getResult(0);
126
127 // Create a resizable operation with one operand.
128 Operation *user = createOp(&context, operand);
129
130 // Check setting with the same number of operands.
131 MutableOperandRange mutableOperands(user);
132 mutableOperands.assign(operand);
133 EXPECT_EQ(mutableOperands.size(), 1u);
134 EXPECT_EQ(user->getNumOperands(), 1u);
135
136 // Check setting with more operands.
137 mutableOperands.assign({operand, operand, operand});
138 EXPECT_EQ(mutableOperands.size(), 3u);
139 EXPECT_EQ(user->getNumOperands(), 3u);
140
141 // Check with inserting a new operand.
142 mutableOperands.append({operand, operand});
143 EXPECT_EQ(mutableOperands.size(), 5u);
144 EXPECT_EQ(user->getNumOperands(), 5u);
145
146 // Check erasing operands.
147 mutableOperands.clear();
148 EXPECT_EQ(mutableOperands.size(), 0u);
149 EXPECT_EQ(user->getNumOperands(), 0u);
150
151 // Destroy the operations.
152 user->destroy();
153 useOp->destroy();
154 }
155
TEST(OperandStorageTest,RangeErase)156 TEST(OperandStorageTest, RangeErase) {
157 MLIRContext context;
158 Builder builder(&context);
159
160 Type type = builder.getNoneType();
161 Operation *useOp = createOp(&context, /*operands=*/llvm::None, {type, type});
162 Value operand1 = useOp->getResult(0);
163 Value operand2 = useOp->getResult(1);
164
165 // Create an operation with operands to erase.
166 Operation *user =
167 createOp(&context, {operand2, operand1, operand2, operand1});
168 BitVector eraseIndices(user->getNumOperands());
169
170 // Check erasing no operands.
171 user->eraseOperands(eraseIndices);
172 EXPECT_EQ(user->getNumOperands(), 4u);
173
174 // Check erasing disjoint operands.
175 eraseIndices.set(0);
176 eraseIndices.set(3);
177 user->eraseOperands(eraseIndices);
178 EXPECT_EQ(user->getNumOperands(), 2u);
179 EXPECT_EQ(user->getOperand(0), operand1);
180 EXPECT_EQ(user->getOperand(1), operand2);
181
182 // Destroy the operations.
183 user->destroy();
184 useOp->destroy();
185 }
186
TEST(OperationOrderTest,OrderIsAlwaysValid)187 TEST(OperationOrderTest, OrderIsAlwaysValid) {
188 MLIRContext context;
189 Builder builder(&context);
190
191 Operation *containerOp =
192 createOp(&context, /*operands=*/llvm::None, /*resultTypes=*/llvm::None,
193 /*numRegions=*/1);
194 Region ®ion = containerOp->getRegion(0);
195 Block *block = new Block();
196 region.push_back(block);
197
198 // Insert two operations, then iteratively add more operations in the middle
199 // of them. Eventually we will insert more than kOrderStride operations and
200 // the block order will need to be recomputed.
201 Operation *frontOp = createOp(&context);
202 Operation *backOp = createOp(&context);
203 block->push_back(frontOp);
204 block->push_back(backOp);
205
206 // Chosen to be larger than Operation::kOrderStride.
207 int kNumOpsToInsert = 10;
208 for (int i = 0; i < kNumOpsToInsert; ++i) {
209 Operation *op = createOp(&context);
210 block->getOperations().insert(backOp->getIterator(), op);
211 ASSERT_TRUE(op->isBeforeInBlock(backOp));
212 // Note verifyOpOrder() returns false if the order is valid.
213 ASSERT_FALSE(block->verifyOpOrder());
214 }
215
216 containerOp->destroy();
217 }
218
TEST(OperationFormatPrintTest,CanUseVariadicFormat)219 TEST(OperationFormatPrintTest, CanUseVariadicFormat) {
220 MLIRContext context;
221 Builder builder(&context);
222
223 Operation *op = createOp(&context);
224
225 std::string str = formatv("{0}", *op).str();
226 ASSERT_STREQ(str.c_str(), "\"foo.bar\"() : () -> ()");
227
228 op->destroy();
229 }
230
TEST(NamedAttrListTest,TestAppendAssign)231 TEST(NamedAttrListTest, TestAppendAssign) {
232 MLIRContext ctx;
233 NamedAttrList attrs;
234 Builder b(&ctx);
235
236 attrs.append(b.getStringAttr("foo"), b.getStringAttr("bar"));
237 attrs.append("baz", b.getStringAttr("boo"));
238
239 {
240 auto *it = attrs.begin();
241 EXPECT_EQ(it->getName(), b.getStringAttr("foo"));
242 EXPECT_EQ(it->getValue(), b.getStringAttr("bar"));
243 ++it;
244 EXPECT_EQ(it->getName(), b.getStringAttr("baz"));
245 EXPECT_EQ(it->getValue(), b.getStringAttr("boo"));
246 }
247
248 attrs.append("foo", b.getStringAttr("zoo"));
249 {
250 auto dup = attrs.findDuplicate();
251 ASSERT_TRUE(dup.has_value());
252 }
253
254 SmallVector<NamedAttribute> newAttrs = {
255 b.getNamedAttr("foo", b.getStringAttr("f")),
256 b.getNamedAttr("zoo", b.getStringAttr("z")),
257 };
258 attrs.assign(newAttrs);
259
260 auto dup = attrs.findDuplicate();
261 ASSERT_FALSE(dup.has_value());
262
263 {
264 auto *it = attrs.begin();
265 EXPECT_EQ(it->getName(), b.getStringAttr("foo"));
266 EXPECT_EQ(it->getValue(), b.getStringAttr("f"));
267 ++it;
268 EXPECT_EQ(it->getName(), b.getStringAttr("zoo"));
269 EXPECT_EQ(it->getValue(), b.getStringAttr("z"));
270 }
271
272 attrs.assign({});
273 ASSERT_TRUE(attrs.empty());
274 }
275
TEST(OperandStorageTest,PopulateDefaultAttrs)276 TEST(OperandStorageTest, PopulateDefaultAttrs) {
277 MLIRContext context;
278 context.getOrLoadDialect<test::TestDialect>();
279 Builder builder(&context);
280
281 OpBuilder b(&context);
282 auto req1 = b.getI32IntegerAttr(10);
283 auto req2 = b.getI32IntegerAttr(60);
284 Operation *op = b.create<test::OpAttrMatch1>(b.getUnknownLoc(), req1, nullptr,
285 nullptr, req2);
286 EXPECT_EQ(op->getAttr("default_valued_attr"), nullptr);
287 op->populateDefaultAttrs();
288 auto opt = op->getAttr("default_valued_attr");
289 EXPECT_NE(opt, nullptr) << *op;
290
291 op->destroy();
292 }
293 } // namespace
294