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 &region = 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