1 //===- OperationSupportTest.cpp - Operation support unit tests ------------===//
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
7 //===----------------------------------------------------------------------===//
9 #include "mlir/IR/OperationSupport.h"
10 #include "../../test/lib/Dialect/Test/TestDialect.h"
11 #include "../../test/lib/Dialect/Test/TestOps.h"
12 #include "mlir/IR/Builders.h"
13 #include "mlir/IR/BuiltinTypes.h"
14 #include "llvm/ADT/BitVector.h"
15 #include "llvm/Support/FormatVariadic.h"
16 #include "gtest/gtest.h"
19 using namespace mlir::detail
;
21 static Operation
*createOp(MLIRContext
*context
,
22 ArrayRef
<Value
> operands
= std::nullopt
,
23 ArrayRef
<Type
> resultTypes
= std::nullopt
,
24 unsigned int numRegions
= 0) {
25 context
->allowUnregisteredDialects();
26 return Operation::create(
27 UnknownLoc::get(context
), OperationName("foo.bar", context
), resultTypes
,
28 operands
, std::nullopt
, nullptr, std::nullopt
, numRegions
);
32 TEST(OperandStorageTest
, NonResizable
) {
34 Builder
builder(&context
);
37 createOp(&context
, /*operands=*/std::nullopt
, builder
.getIntegerType(16));
38 Value operand
= useOp
->getResult(0);
40 // Create a non-resizable operation with one operand.
41 Operation
*user
= createOp(&context
, operand
);
43 // The same number of operands is okay.
44 user
->setOperands(operand
);
45 EXPECT_EQ(user
->getNumOperands(), 1u);
48 user
->setOperands(std::nullopt
);
49 EXPECT_EQ(user
->getNumOperands(), 0u);
51 // Destroy the operations.
56 TEST(OperandStorageTest
, Resizable
) {
58 Builder
builder(&context
);
61 createOp(&context
, /*operands=*/std::nullopt
, builder
.getIntegerType(16));
62 Value operand
= useOp
->getResult(0);
64 // Create a resizable operation with one operand.
65 Operation
*user
= createOp(&context
, operand
);
67 // The same number of operands is okay.
68 user
->setOperands(operand
);
69 EXPECT_EQ(user
->getNumOperands(), 1u);
72 user
->setOperands(std::nullopt
);
73 EXPECT_EQ(user
->getNumOperands(), 0u);
75 // Adding more operands is okay.
76 user
->setOperands({operand
, operand
, operand
});
77 EXPECT_EQ(user
->getNumOperands(), 3u);
79 // Destroy the operations.
84 TEST(OperandStorageTest
, RangeReplace
) {
86 Builder
builder(&context
);
89 createOp(&context
, /*operands=*/std::nullopt
, builder
.getIntegerType(16));
90 Value operand
= useOp
->getResult(0);
92 // Create a resizable operation with one operand.
93 Operation
*user
= createOp(&context
, operand
);
95 // Check setting with the same number of operands.
96 user
->setOperands(/*start=*/0, /*length=*/1, operand
);
97 EXPECT_EQ(user
->getNumOperands(), 1u);
99 // Check setting with more operands.
100 user
->setOperands(/*start=*/0, /*length=*/1, {operand
, operand
, operand
});
101 EXPECT_EQ(user
->getNumOperands(), 3u);
103 // Check setting with less operands.
104 user
->setOperands(/*start=*/1, /*length=*/2, {operand
});
105 EXPECT_EQ(user
->getNumOperands(), 2u);
107 // Check inserting without replacing operands.
108 user
->setOperands(/*start=*/2, /*length=*/0, {operand
});
109 EXPECT_EQ(user
->getNumOperands(), 3u);
111 // Check erasing operands.
112 user
->setOperands(/*start=*/0, /*length=*/3, {});
113 EXPECT_EQ(user
->getNumOperands(), 0u);
115 // Destroy the operations.
120 TEST(OperandStorageTest
, MutableRange
) {
122 Builder
builder(&context
);
125 createOp(&context
, /*operands=*/std::nullopt
, builder
.getIntegerType(16));
126 Value operand
= useOp
->getResult(0);
128 // Create a resizable operation with one operand.
129 Operation
*user
= createOp(&context
, operand
);
131 // Check setting with the same number of operands.
132 MutableOperandRange
mutableOperands(user
);
133 mutableOperands
.assign(operand
);
134 EXPECT_EQ(mutableOperands
.size(), 1u);
135 EXPECT_EQ(user
->getNumOperands(), 1u);
137 // Check setting with more operands.
138 mutableOperands
.assign({operand
, operand
, operand
});
139 EXPECT_EQ(mutableOperands
.size(), 3u);
140 EXPECT_EQ(user
->getNumOperands(), 3u);
142 // Check with inserting a new operand.
143 mutableOperands
.append({operand
, operand
});
144 EXPECT_EQ(mutableOperands
.size(), 5u);
145 EXPECT_EQ(user
->getNumOperands(), 5u);
147 // Check erasing operands.
148 mutableOperands
.clear();
149 EXPECT_EQ(mutableOperands
.size(), 0u);
150 EXPECT_EQ(user
->getNumOperands(), 0u);
152 // Destroy the operations.
157 TEST(OperandStorageTest
, RangeErase
) {
159 Builder
builder(&context
);
161 Type type
= builder
.getNoneType();
163 createOp(&context
, /*operands=*/std::nullopt
, {type
, type
});
164 Value operand1
= useOp
->getResult(0);
165 Value operand2
= useOp
->getResult(1);
167 // Create an operation with operands to erase.
169 createOp(&context
, {operand2
, operand1
, operand2
, operand1
});
170 BitVector
eraseIndices(user
->getNumOperands());
172 // Check erasing no operands.
173 user
->eraseOperands(eraseIndices
);
174 EXPECT_EQ(user
->getNumOperands(), 4u);
176 // Check erasing disjoint operands.
179 user
->eraseOperands(eraseIndices
);
180 EXPECT_EQ(user
->getNumOperands(), 2u);
181 EXPECT_EQ(user
->getOperand(0), operand1
);
182 EXPECT_EQ(user
->getOperand(1), operand2
);
184 // Destroy the operations.
189 TEST(OperationOrderTest
, OrderIsAlwaysValid
) {
191 Builder
builder(&context
);
193 Operation
*containerOp
= createOp(&context
, /*operands=*/std::nullopt
,
194 /*resultTypes=*/std::nullopt
,
196 Region
®ion
= containerOp
->getRegion(0);
197 Block
*block
= new Block();
198 region
.push_back(block
);
200 // Insert two operations, then iteratively add more operations in the middle
201 // of them. Eventually we will insert more than kOrderStride operations and
202 // the block order will need to be recomputed.
203 Operation
*frontOp
= createOp(&context
);
204 Operation
*backOp
= createOp(&context
);
205 block
->push_back(frontOp
);
206 block
->push_back(backOp
);
208 // Chosen to be larger than Operation::kOrderStride.
209 int kNumOpsToInsert
= 10;
210 for (int i
= 0; i
< kNumOpsToInsert
; ++i
) {
211 Operation
*op
= createOp(&context
);
212 block
->getOperations().insert(backOp
->getIterator(), op
);
213 ASSERT_TRUE(op
->isBeforeInBlock(backOp
));
214 // Note verifyOpOrder() returns false if the order is valid.
215 ASSERT_FALSE(block
->verifyOpOrder());
218 containerOp
->destroy();
221 TEST(OperationFormatPrintTest
, CanUseVariadicFormat
) {
223 Builder
builder(&context
);
225 Operation
*op
= createOp(&context
);
227 std::string str
= formatv("{0}", *op
).str();
228 ASSERT_STREQ(str
.c_str(), "\"foo.bar\"() : () -> ()");
233 TEST(NamedAttrListTest
, TestAppendAssign
) {
238 attrs
.append(b
.getStringAttr("foo"), b
.getStringAttr("bar"));
239 attrs
.append("baz", b
.getStringAttr("boo"));
242 auto *it
= attrs
.begin();
243 EXPECT_EQ(it
->getName(), b
.getStringAttr("foo"));
244 EXPECT_EQ(it
->getValue(), b
.getStringAttr("bar"));
246 EXPECT_EQ(it
->getName(), b
.getStringAttr("baz"));
247 EXPECT_EQ(it
->getValue(), b
.getStringAttr("boo"));
250 attrs
.append("foo", b
.getStringAttr("zoo"));
252 auto dup
= attrs
.findDuplicate();
253 ASSERT_TRUE(dup
.has_value());
256 SmallVector
<NamedAttribute
> newAttrs
= {
257 b
.getNamedAttr("foo", b
.getStringAttr("f")),
258 b
.getNamedAttr("zoo", b
.getStringAttr("z")),
260 attrs
.assign(newAttrs
);
262 auto dup
= attrs
.findDuplicate();
263 ASSERT_FALSE(dup
.has_value());
266 auto *it
= attrs
.begin();
267 EXPECT_EQ(it
->getName(), b
.getStringAttr("foo"));
268 EXPECT_EQ(it
->getValue(), b
.getStringAttr("f"));
270 EXPECT_EQ(it
->getName(), b
.getStringAttr("zoo"));
271 EXPECT_EQ(it
->getValue(), b
.getStringAttr("z"));
275 ASSERT_TRUE(attrs
.empty());
278 TEST(OperandStorageTest
, PopulateDefaultAttrs
) {
280 context
.getOrLoadDialect
<test::TestDialect
>();
281 Builder
builder(&context
);
283 OpBuilder
b(&context
);
284 auto req1
= b
.getI32IntegerAttr(10);
285 auto req2
= b
.getI32IntegerAttr(60);
286 // Verify default attributes populated post op creation.
287 Operation
*op
= b
.create
<test::OpAttrMatch1
>(b
.getUnknownLoc(), req1
, nullptr,
289 auto opt
= op
->getInherentAttr("default_valued_attr");
290 EXPECT_NE(opt
, nullptr) << *op
;
295 TEST(OperationEquivalenceTest
, HashWorksWithFlags
) {
297 context
.getOrLoadDialect
<test::TestDialect
>();
299 auto *op1
= createOp(&context
);
300 // `op1` has an unknown loc.
301 auto *op2
= createOp(&context
);
302 op2
->setLoc(NameLoc::get(StringAttr::get(&context
, "foo")));
303 auto getHash
= [](Operation
*op
, OperationEquivalence::Flags flags
) {
304 return OperationEquivalence::computeHash(
305 op
, OperationEquivalence::ignoreHashValue
,
306 OperationEquivalence::ignoreHashValue
, flags
);
308 EXPECT_EQ(getHash(op1
, OperationEquivalence::IgnoreLocations
),
309 getHash(op2
, OperationEquivalence::IgnoreLocations
));
310 EXPECT_NE(getHash(op1
, OperationEquivalence::None
),
311 getHash(op2
, OperationEquivalence::None
));