xref: /llvm-project/mlir/unittests/IR/OperationSupportTest.cpp (revision 7d273fde110d7735512c3b71a83eb88e89d189cc)
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 
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 {
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 
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 
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 
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 
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 
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 &region = 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 
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 
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 
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   // Verify default attributes populated post op creation.
285   Operation *op = b.create<test::OpAttrMatch1>(b.getUnknownLoc(), req1, nullptr,
286                                                nullptr, req2);
287   auto opt = op->getAttr("default_valued_attr");
288   EXPECT_NE(opt, nullptr) << *op;
289 
290   op->destroy();
291 }
292 } // namespace
293