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