19ffdc930SRiver Riddle //===- OperationSupportTest.cpp - Operation support unit tests ------------===//
29ffdc930SRiver Riddle //
330857107SMehdi Amini // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
456222a06SMehdi Amini // See https://llvm.org/LICENSE.txt for license information.
556222a06SMehdi Amini // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
69ffdc930SRiver Riddle //
756222a06SMehdi Amini //===----------------------------------------------------------------------===//
89ffdc930SRiver Riddle
99ffdc930SRiver Riddle #include "mlir/IR/OperationSupport.h"
1082140ad7SJacques Pienaar #include "../../test/lib/Dialect/Test/TestDialect.h"
11*e95e94adSJeff Niu #include "../../test/lib/Dialect/Test/TestOps.h"
129ffdc930SRiver Riddle #include "mlir/IR/Builders.h"
1309f7a55fSRiver Riddle #include "mlir/IR/BuiltinTypes.h"
14a776ecb6SRiver Riddle #include "llvm/ADT/BitVector.h"
15d6296c3bSVladislav Vinogradov #include "llvm/Support/FormatVariadic.h"
169ffdc930SRiver Riddle #include "gtest/gtest.h"
179ffdc930SRiver Riddle
189ffdc930SRiver Riddle using namespace mlir;
199ffdc930SRiver Riddle using namespace mlir::detail;
209ffdc930SRiver Riddle
createOp(MLIRContext * context,ArrayRef<Value> operands=std::nullopt,ArrayRef<Type> resultTypes=std::nullopt,unsigned int numRegions=0)214dfd1b5fSRiver Riddle static Operation *createOp(MLIRContext *context,
223a77eb66SKazu Hirata ArrayRef<Value> operands = std::nullopt,
233a77eb66SKazu Hirata ArrayRef<Type> resultTypes = std::nullopt,
248bdbe295SJames Molloy unsigned int numRegions = 0) {
25bab5bcf8SMehdi Amini context->allowUnregisteredDialects();
265e118f93SMehdi Amini return Operation::create(
275e118f93SMehdi Amini UnknownLoc::get(context), OperationName("foo.bar", context), resultTypes,
285e118f93SMehdi Amini operands, std::nullopt, nullptr, std::nullopt, numRegions);
299ffdc930SRiver Riddle }
309ffdc930SRiver Riddle
31bab5bcf8SMehdi Amini namespace {
TEST(OperandStorageTest,NonResizable)329ffdc930SRiver Riddle TEST(OperandStorageTest, NonResizable) {
33e7021232SMehdi Amini MLIRContext context;
349ffdc930SRiver Riddle Builder builder(&context);
359ffdc930SRiver Riddle
369ffdc930SRiver Riddle Operation *useOp =
373a77eb66SKazu Hirata createOp(&context, /*operands=*/std::nullopt, builder.getIntegerType(16));
38e62a6956SRiver Riddle Value operand = useOp->getResult(0);
399ffdc930SRiver Riddle
40af9760feSRiver Riddle // Create a non-resizable operation with one operand.
41108abd2fSRiver Riddle Operation *user = createOp(&context, operand);
429ffdc930SRiver Riddle
439ffdc930SRiver Riddle // The same number of operands is okay.
449ffdc930SRiver Riddle user->setOperands(operand);
451b94395eSAlex Zinenko EXPECT_EQ(user->getNumOperands(), 1u);
469ffdc930SRiver Riddle
479ffdc930SRiver Riddle // Removing is okay.
483a77eb66SKazu Hirata user->setOperands(std::nullopt);
491b94395eSAlex Zinenko EXPECT_EQ(user->getNumOperands(), 0u);
509ffdc930SRiver Riddle
51af9760feSRiver Riddle // Destroy the operations.
529ffdc930SRiver Riddle user->destroy();
539ffdc930SRiver Riddle useOp->destroy();
549ffdc930SRiver Riddle }
559ffdc930SRiver Riddle
TEST(OperandStorageTest,Resizable)569ffdc930SRiver Riddle TEST(OperandStorageTest, Resizable) {
57e7021232SMehdi Amini MLIRContext context;
589ffdc930SRiver Riddle Builder builder(&context);
599ffdc930SRiver Riddle
609ffdc930SRiver Riddle Operation *useOp =
613a77eb66SKazu Hirata createOp(&context, /*operands=*/std::nullopt, builder.getIntegerType(16));
62e62a6956SRiver Riddle Value operand = useOp->getResult(0);
639ffdc930SRiver Riddle
64af9760feSRiver Riddle // Create a resizable operation with one operand.
65108abd2fSRiver Riddle Operation *user = createOp(&context, operand);
669ffdc930SRiver Riddle
679ffdc930SRiver Riddle // The same number of operands is okay.
689ffdc930SRiver Riddle user->setOperands(operand);
691b94395eSAlex Zinenko EXPECT_EQ(user->getNumOperands(), 1u);
709ffdc930SRiver Riddle
719ffdc930SRiver Riddle // Removing is okay.
723a77eb66SKazu Hirata user->setOperands(std::nullopt);
731b94395eSAlex Zinenko EXPECT_EQ(user->getNumOperands(), 0u);
749ffdc930SRiver Riddle
759ffdc930SRiver Riddle // Adding more operands is okay.
769ffdc930SRiver Riddle user->setOperands({operand, operand, operand});
771b94395eSAlex Zinenko EXPECT_EQ(user->getNumOperands(), 3u);
789ffdc930SRiver Riddle
79af9760feSRiver Riddle // Destroy the operations.
809ffdc930SRiver Riddle user->destroy();
819ffdc930SRiver Riddle useOp->destroy();
829ffdc930SRiver Riddle }
839ffdc930SRiver Riddle
TEST(OperandStorageTest,RangeReplace)84108abd2fSRiver Riddle TEST(OperandStorageTest, RangeReplace) {
85e7021232SMehdi Amini MLIRContext context;
86108abd2fSRiver Riddle Builder builder(&context);
87108abd2fSRiver Riddle
88108abd2fSRiver Riddle Operation *useOp =
893a77eb66SKazu Hirata createOp(&context, /*operands=*/std::nullopt, builder.getIntegerType(16));
90108abd2fSRiver Riddle Value operand = useOp->getResult(0);
91108abd2fSRiver Riddle
92108abd2fSRiver Riddle // Create a resizable operation with one operand.
93108abd2fSRiver Riddle Operation *user = createOp(&context, operand);
94108abd2fSRiver Riddle
95108abd2fSRiver Riddle // Check setting with the same number of operands.
96108abd2fSRiver Riddle user->setOperands(/*start=*/0, /*length=*/1, operand);
97108abd2fSRiver Riddle EXPECT_EQ(user->getNumOperands(), 1u);
98108abd2fSRiver Riddle
99108abd2fSRiver Riddle // Check setting with more operands.
100108abd2fSRiver Riddle user->setOperands(/*start=*/0, /*length=*/1, {operand, operand, operand});
101108abd2fSRiver Riddle EXPECT_EQ(user->getNumOperands(), 3u);
102108abd2fSRiver Riddle
103108abd2fSRiver Riddle // Check setting with less operands.
104108abd2fSRiver Riddle user->setOperands(/*start=*/1, /*length=*/2, {operand});
105108abd2fSRiver Riddle EXPECT_EQ(user->getNumOperands(), 2u);
106108abd2fSRiver Riddle
107108abd2fSRiver Riddle // Check inserting without replacing operands.
108108abd2fSRiver Riddle user->setOperands(/*start=*/2, /*length=*/0, {operand});
109108abd2fSRiver Riddle EXPECT_EQ(user->getNumOperands(), 3u);
110108abd2fSRiver Riddle
111108abd2fSRiver Riddle // Check erasing operands.
112108abd2fSRiver Riddle user->setOperands(/*start=*/0, /*length=*/3, {});
113108abd2fSRiver Riddle EXPECT_EQ(user->getNumOperands(), 0u);
114108abd2fSRiver Riddle
115108abd2fSRiver Riddle // Destroy the operations.
116108abd2fSRiver Riddle user->destroy();
117108abd2fSRiver Riddle useOp->destroy();
118108abd2fSRiver Riddle }
119108abd2fSRiver Riddle
TEST(OperandStorageTest,MutableRange)120108abd2fSRiver Riddle TEST(OperandStorageTest, MutableRange) {
121e7021232SMehdi Amini MLIRContext context;
122108abd2fSRiver Riddle Builder builder(&context);
123108abd2fSRiver Riddle
124108abd2fSRiver Riddle Operation *useOp =
1253a77eb66SKazu Hirata createOp(&context, /*operands=*/std::nullopt, builder.getIntegerType(16));
126108abd2fSRiver Riddle Value operand = useOp->getResult(0);
127108abd2fSRiver Riddle
128108abd2fSRiver Riddle // Create a resizable operation with one operand.
129108abd2fSRiver Riddle Operation *user = createOp(&context, operand);
130108abd2fSRiver Riddle
131108abd2fSRiver Riddle // Check setting with the same number of operands.
132108abd2fSRiver Riddle MutableOperandRange mutableOperands(user);
133108abd2fSRiver Riddle mutableOperands.assign(operand);
134108abd2fSRiver Riddle EXPECT_EQ(mutableOperands.size(), 1u);
135108abd2fSRiver Riddle EXPECT_EQ(user->getNumOperands(), 1u);
136108abd2fSRiver Riddle
137108abd2fSRiver Riddle // Check setting with more operands.
138108abd2fSRiver Riddle mutableOperands.assign({operand, operand, operand});
139108abd2fSRiver Riddle EXPECT_EQ(mutableOperands.size(), 3u);
140108abd2fSRiver Riddle EXPECT_EQ(user->getNumOperands(), 3u);
141108abd2fSRiver Riddle
142108abd2fSRiver Riddle // Check with inserting a new operand.
143108abd2fSRiver Riddle mutableOperands.append({operand, operand});
144108abd2fSRiver Riddle EXPECT_EQ(mutableOperands.size(), 5u);
145108abd2fSRiver Riddle EXPECT_EQ(user->getNumOperands(), 5u);
146108abd2fSRiver Riddle
147108abd2fSRiver Riddle // Check erasing operands.
148108abd2fSRiver Riddle mutableOperands.clear();
149108abd2fSRiver Riddle EXPECT_EQ(mutableOperands.size(), 0u);
150108abd2fSRiver Riddle EXPECT_EQ(user->getNumOperands(), 0u);
151108abd2fSRiver Riddle
152108abd2fSRiver Riddle // Destroy the operations.
153108abd2fSRiver Riddle user->destroy();
154108abd2fSRiver Riddle useOp->destroy();
155108abd2fSRiver Riddle }
156108abd2fSRiver Riddle
TEST(OperandStorageTest,RangeErase)157a776ecb6SRiver Riddle TEST(OperandStorageTest, RangeErase) {
158a776ecb6SRiver Riddle MLIRContext context;
159a776ecb6SRiver Riddle Builder builder(&context);
160a776ecb6SRiver Riddle
161a776ecb6SRiver Riddle Type type = builder.getNoneType();
1623a77eb66SKazu Hirata Operation *useOp =
1633a77eb66SKazu Hirata createOp(&context, /*operands=*/std::nullopt, {type, type});
164a776ecb6SRiver Riddle Value operand1 = useOp->getResult(0);
165a776ecb6SRiver Riddle Value operand2 = useOp->getResult(1);
166a776ecb6SRiver Riddle
167a776ecb6SRiver Riddle // Create an operation with operands to erase.
168a776ecb6SRiver Riddle Operation *user =
169a776ecb6SRiver Riddle createOp(&context, {operand2, operand1, operand2, operand1});
170d10d49dcSRiver Riddle BitVector eraseIndices(user->getNumOperands());
171a776ecb6SRiver Riddle
172a776ecb6SRiver Riddle // Check erasing no operands.
173a776ecb6SRiver Riddle user->eraseOperands(eraseIndices);
174a776ecb6SRiver Riddle EXPECT_EQ(user->getNumOperands(), 4u);
175a776ecb6SRiver Riddle
176a776ecb6SRiver Riddle // Check erasing disjoint operands.
177a776ecb6SRiver Riddle eraseIndices.set(0);
178a776ecb6SRiver Riddle eraseIndices.set(3);
179a776ecb6SRiver Riddle user->eraseOperands(eraseIndices);
180a776ecb6SRiver Riddle EXPECT_EQ(user->getNumOperands(), 2u);
181a776ecb6SRiver Riddle EXPECT_EQ(user->getOperand(0), operand1);
182a776ecb6SRiver Riddle EXPECT_EQ(user->getOperand(1), operand2);
183a776ecb6SRiver Riddle
184a776ecb6SRiver Riddle // Destroy the operations.
185a776ecb6SRiver Riddle user->destroy();
186a776ecb6SRiver Riddle useOp->destroy();
187a776ecb6SRiver Riddle }
188a776ecb6SRiver Riddle
TEST(OperationOrderTest,OrderIsAlwaysValid)1898bdbe295SJames Molloy TEST(OperationOrderTest, OrderIsAlwaysValid) {
190e7021232SMehdi Amini MLIRContext context;
1918bdbe295SJames Molloy Builder builder(&context);
1928bdbe295SJames Molloy
1933a77eb66SKazu Hirata Operation *containerOp = createOp(&context, /*operands=*/std::nullopt,
1943a77eb66SKazu Hirata /*resultTypes=*/std::nullopt,
1958bdbe295SJames Molloy /*numRegions=*/1);
1968bdbe295SJames Molloy Region ®ion = containerOp->getRegion(0);
1978bdbe295SJames Molloy Block *block = new Block();
1988bdbe295SJames Molloy region.push_back(block);
1998bdbe295SJames Molloy
2008bdbe295SJames Molloy // Insert two operations, then iteratively add more operations in the middle
2018bdbe295SJames Molloy // of them. Eventually we will insert more than kOrderStride operations and
2028bdbe295SJames Molloy // the block order will need to be recomputed.
2038bdbe295SJames Molloy Operation *frontOp = createOp(&context);
2048bdbe295SJames Molloy Operation *backOp = createOp(&context);
2058bdbe295SJames Molloy block->push_back(frontOp);
2068bdbe295SJames Molloy block->push_back(backOp);
2078bdbe295SJames Molloy
2088bdbe295SJames Molloy // Chosen to be larger than Operation::kOrderStride.
2098bdbe295SJames Molloy int kNumOpsToInsert = 10;
2108bdbe295SJames Molloy for (int i = 0; i < kNumOpsToInsert; ++i) {
2118bdbe295SJames Molloy Operation *op = createOp(&context);
2128bdbe295SJames Molloy block->getOperations().insert(backOp->getIterator(), op);
2138bdbe295SJames Molloy ASSERT_TRUE(op->isBeforeInBlock(backOp));
2148bdbe295SJames Molloy // Note verifyOpOrder() returns false if the order is valid.
2158bdbe295SJames Molloy ASSERT_FALSE(block->verifyOpOrder());
2168bdbe295SJames Molloy }
2178bdbe295SJames Molloy
2188bdbe295SJames Molloy containerOp->destroy();
2198bdbe295SJames Molloy }
2208bdbe295SJames Molloy
TEST(OperationFormatPrintTest,CanUseVariadicFormat)221d6296c3bSVladislav Vinogradov TEST(OperationFormatPrintTest, CanUseVariadicFormat) {
222d6296c3bSVladislav Vinogradov MLIRContext context;
223d6296c3bSVladislav Vinogradov Builder builder(&context);
224d6296c3bSVladislav Vinogradov
225d6296c3bSVladislav Vinogradov Operation *op = createOp(&context);
226d6296c3bSVladislav Vinogradov
227d6296c3bSVladislav Vinogradov std::string str = formatv("{0}", *op).str();
228d6296c3bSVladislav Vinogradov ASSERT_STREQ(str.c_str(), "\"foo.bar\"() : () -> ()");
22917664a25SVladislav Vinogradov
23017664a25SVladislav Vinogradov op->destroy();
231d6296c3bSVladislav Vinogradov }
232d6296c3bSVladislav Vinogradov
TEST(NamedAttrListTest,TestAppendAssign)23321bb463eSMogball TEST(NamedAttrListTest, TestAppendAssign) {
23421bb463eSMogball MLIRContext ctx;
23521bb463eSMogball NamedAttrList attrs;
23621bb463eSMogball Builder b(&ctx);
23721bb463eSMogball
2380aa30726SMogball attrs.append(b.getStringAttr("foo"), b.getStringAttr("bar"));
23921bb463eSMogball attrs.append("baz", b.getStringAttr("boo"));
24021bb463eSMogball
24121bb463eSMogball {
24202b6fb21SMehdi Amini auto *it = attrs.begin();
2430c7890c8SRiver Riddle EXPECT_EQ(it->getName(), b.getStringAttr("foo"));
2440c7890c8SRiver Riddle EXPECT_EQ(it->getValue(), b.getStringAttr("bar"));
24521bb463eSMogball ++it;
2460c7890c8SRiver Riddle EXPECT_EQ(it->getName(), b.getStringAttr("baz"));
2470c7890c8SRiver Riddle EXPECT_EQ(it->getValue(), b.getStringAttr("boo"));
24821bb463eSMogball }
24921bb463eSMogball
25021bb463eSMogball attrs.append("foo", b.getStringAttr("zoo"));
25121bb463eSMogball {
25221bb463eSMogball auto dup = attrs.findDuplicate();
253491d2701SKazu Hirata ASSERT_TRUE(dup.has_value());
25421bb463eSMogball }
25521bb463eSMogball
25621bb463eSMogball SmallVector<NamedAttribute> newAttrs = {
25721bb463eSMogball b.getNamedAttr("foo", b.getStringAttr("f")),
25821bb463eSMogball b.getNamedAttr("zoo", b.getStringAttr("z")),
25921bb463eSMogball };
26021bb463eSMogball attrs.assign(newAttrs);
26121bb463eSMogball
26221bb463eSMogball auto dup = attrs.findDuplicate();
263491d2701SKazu Hirata ASSERT_FALSE(dup.has_value());
26421bb463eSMogball
26521bb463eSMogball {
26602b6fb21SMehdi Amini auto *it = attrs.begin();
2670c7890c8SRiver Riddle EXPECT_EQ(it->getName(), b.getStringAttr("foo"));
2680c7890c8SRiver Riddle EXPECT_EQ(it->getValue(), b.getStringAttr("f"));
26921bb463eSMogball ++it;
2700c7890c8SRiver Riddle EXPECT_EQ(it->getName(), b.getStringAttr("zoo"));
2710c7890c8SRiver Riddle EXPECT_EQ(it->getValue(), b.getStringAttr("z"));
27221bb463eSMogball }
27321bb463eSMogball
27421bb463eSMogball attrs.assign({});
27521bb463eSMogball ASSERT_TRUE(attrs.empty());
27621bb463eSMogball }
27782140ad7SJacques Pienaar
TEST(OperandStorageTest,PopulateDefaultAttrs)27882140ad7SJacques Pienaar TEST(OperandStorageTest, PopulateDefaultAttrs) {
27982140ad7SJacques Pienaar MLIRContext context;
28082140ad7SJacques Pienaar context.getOrLoadDialect<test::TestDialect>();
28182140ad7SJacques Pienaar Builder builder(&context);
28282140ad7SJacques Pienaar
28382140ad7SJacques Pienaar OpBuilder b(&context);
28482140ad7SJacques Pienaar auto req1 = b.getI32IntegerAttr(10);
28582140ad7SJacques Pienaar auto req2 = b.getI32IntegerAttr(60);
2867d273fdeSJacques Pienaar // Verify default attributes populated post op creation.
28782140ad7SJacques Pienaar Operation *op = b.create<test::OpAttrMatch1>(b.getUnknownLoc(), req1, nullptr,
28882140ad7SJacques Pienaar nullptr, req2);
289830b9b07SMehdi Amini auto opt = op->getInherentAttr("default_valued_attr");
29082140ad7SJacques Pienaar EXPECT_NE(opt, nullptr) << *op;
29182140ad7SJacques Pienaar
29282140ad7SJacques Pienaar op->destroy();
29382140ad7SJacques Pienaar }
294fd824782SHideto Ueno
TEST(OperationEquivalenceTest,HashWorksWithFlags)295fd824782SHideto Ueno TEST(OperationEquivalenceTest, HashWorksWithFlags) {
296fd824782SHideto Ueno MLIRContext context;
297fd824782SHideto Ueno context.getOrLoadDialect<test::TestDialect>();
298fd824782SHideto Ueno
299df8d5c17SMehdi Amini auto *op1 = createOp(&context);
300fd824782SHideto Ueno // `op1` has an unknown loc.
301df8d5c17SMehdi Amini auto *op2 = createOp(&context);
302fd824782SHideto Ueno op2->setLoc(NameLoc::get(StringAttr::get(&context, "foo")));
303fd824782SHideto Ueno auto getHash = [](Operation *op, OperationEquivalence::Flags flags) {
304fd824782SHideto Ueno return OperationEquivalence::computeHash(
305fd824782SHideto Ueno op, OperationEquivalence::ignoreHashValue,
306fd824782SHideto Ueno OperationEquivalence::ignoreHashValue, flags);
307fd824782SHideto Ueno };
308fd824782SHideto Ueno EXPECT_EQ(getHash(op1, OperationEquivalence::IgnoreLocations),
309fd824782SHideto Ueno getHash(op2, OperationEquivalence::IgnoreLocations));
310fd824782SHideto Ueno EXPECT_NE(getHash(op1, OperationEquivalence::None),
311fd824782SHideto Ueno getHash(op2, OperationEquivalence::None));
312fd824782SHideto Ueno op1->destroy();
313fd824782SHideto Ueno op2->destroy();
314fd824782SHideto Ueno }
315fd824782SHideto Ueno
316be0a7e9fSMehdi Amini } // namespace
317