1 //===- OpBuildGen.cpp - TableGen OpBuildGen 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 // Test TableGen generated build() methods on Operations. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #include "TestDialect.h" 14 #include "mlir/IR/Attributes.h" 15 #include "mlir/IR/Builders.h" 16 #include "mlir/IR/BuiltinTypes.h" 17 #include "mlir/IR/Dialect.h" 18 #include "gmock/gmock.h" 19 #include <vector> 20 21 namespace mlir { 22 23 //===----------------------------------------------------------------------===// 24 // Test Fixture 25 //===----------------------------------------------------------------------===// 26 27 static MLIRContext &getContext() { 28 static MLIRContext ctx; 29 ctx.getOrLoadDialect<test::TestDialect>(); 30 return ctx; 31 } 32 /// Test fixture for providing basic utilities for testing. 33 class OpBuildGenTest : public ::testing::Test { 34 protected: 35 OpBuildGenTest() 36 : ctx(getContext()), builder(&ctx), loc(builder.getUnknownLoc()), 37 i32Ty(builder.getI32Type()), f32Ty(builder.getF32Type()), 38 cstI32(builder.create<test::TableGenConstant>(loc, i32Ty)), 39 cstF32(builder.create<test::TableGenConstant>(loc, f32Ty)), 40 noAttrs(), attrStorage{builder.getNamedAttr("attr0", 41 builder.getBoolAttr(true)), 42 builder.getNamedAttr( 43 "attr1", builder.getI32IntegerAttr(33))}, 44 attrs(attrStorage) {} 45 46 // Verify that `op` has the given set of result types, operands, and 47 // attributes. 48 template <typename OpTy> 49 void verifyOp(OpTy &&concreteOp, std::vector<Type> resultTypes, 50 std::vector<Value> operands, 51 std::vector<NamedAttribute> attrs) { 52 ASSERT_NE(concreteOp, nullptr); 53 Operation *op = concreteOp.getOperation(); 54 55 EXPECT_EQ(op->getNumResults(), resultTypes.size()); 56 for (unsigned idx : llvm::seq(0U, op->getNumResults())) 57 EXPECT_EQ(op->getResult(idx).getType(), resultTypes[idx]); 58 59 EXPECT_EQ(op->getNumOperands(), operands.size()); 60 for (unsigned idx : llvm::seq(0U, op->getNumOperands())) 61 EXPECT_EQ(op->getOperand(idx), operands[idx]); 62 63 EXPECT_EQ(op->getAttrs().size(), attrs.size()); 64 for (unsigned idx : llvm::seq<unsigned>(0U, attrs.size())) 65 EXPECT_EQ(op->getAttr(attrs[idx].getName().strref()), 66 attrs[idx].getValue()); 67 68 concreteOp.erase(); 69 } 70 71 // Helper method to test ops with inferred result types and single variadic 72 // input. 73 template <typename OpTy> 74 void testSingleVariadicInputInferredType() { 75 // Test separate arg, separate param build method. 76 auto op = builder.create<OpTy>(loc, i32Ty, ValueRange{*cstI32, *cstI32}); 77 verifyOp(std::move(op), {i32Ty}, {*cstI32, *cstI32}, noAttrs); 78 79 // Test collective params build method. 80 op = 81 builder.create<OpTy>(loc, TypeRange{i32Ty}, ValueRange{*cstI32, *cstI32}); 82 verifyOp(std::move(op), {i32Ty}, {*cstI32, *cstI32}, noAttrs); 83 84 // Test build method with no result types, default value of attributes. 85 op = builder.create<OpTy>(loc, ValueRange{*cstI32, *cstI32}); 86 verifyOp(std::move(op), {i32Ty}, {*cstI32, *cstI32}, noAttrs); 87 88 // Test build method with no result types and supplied attributes. 89 op = builder.create<OpTy>(loc, ValueRange{*cstI32, *cstI32}, attrs); 90 verifyOp(std::move(op), {i32Ty}, {*cstI32, *cstI32}, attrs); 91 } 92 93 protected: 94 MLIRContext &ctx; 95 OpBuilder builder; 96 Location loc; 97 Type i32Ty; 98 Type f32Ty; 99 OwningOpRef<test::TableGenConstant> cstI32; 100 OwningOpRef<test::TableGenConstant> cstF32; 101 102 ArrayRef<NamedAttribute> noAttrs; 103 std::vector<NamedAttribute> attrStorage; 104 ArrayRef<NamedAttribute> attrs; 105 }; 106 107 /// Test basic build methods. 108 TEST_F(OpBuildGenTest, BasicBuildMethods) { 109 // Test separate args, separate results build method. 110 auto op = builder.create<test::TableGenBuildOp0>(loc, i32Ty, *cstI32); 111 verifyOp(op, {i32Ty}, {*cstI32}, noAttrs); 112 113 // Test separate args, collective results build method. 114 op = builder.create<test::TableGenBuildOp0>(loc, TypeRange{i32Ty}, *cstI32); 115 verifyOp(op, {i32Ty}, {*cstI32}, noAttrs); 116 117 // Test collective args, collective params build method. 118 op = builder.create<test::TableGenBuildOp0>(loc, TypeRange{i32Ty}, 119 ValueRange{*cstI32}); 120 verifyOp(op, {i32Ty}, {*cstI32}, noAttrs); 121 122 // Test collective args, collective results, non-empty attributes 123 op = builder.create<test::TableGenBuildOp0>(loc, TypeRange{i32Ty}, 124 ValueRange{*cstI32}, attrs); 125 verifyOp(op, {i32Ty}, {*cstI32}, attrs); 126 } 127 128 /// The following 3 tests exercise build methods generated for operations 129 /// with a combination of: 130 /// 131 /// single variadic arg x 132 /// {single variadic result, non-variadic result, multiple variadic results} 133 /// 134 /// Specifically to test that that ODS framework does not generate ambiguous 135 /// build() methods that fail to compile. 136 137 /// Test build methods for an Op with a single varadic arg and a single 138 /// variadic result. 139 TEST_F(OpBuildGenTest, BuildMethodsSingleVariadicArgAndResult) { 140 // Test collective args, collective results method, building a unary op. 141 auto op = builder.create<test::TableGenBuildOp1>(loc, TypeRange{i32Ty}, 142 ValueRange{*cstI32}); 143 verifyOp(op, {i32Ty}, {*cstI32}, noAttrs); 144 145 // Test collective args, collective results method, building a unary op with 146 // named attributes. 147 op = builder.create<test::TableGenBuildOp1>(loc, TypeRange{i32Ty}, 148 ValueRange{*cstI32}, attrs); 149 verifyOp(op, {i32Ty}, {*cstI32}, attrs); 150 151 // Test collective args, collective results method, building a binary op. 152 op = builder.create<test::TableGenBuildOp1>(loc, TypeRange{i32Ty, f32Ty}, 153 ValueRange{*cstI32, *cstF32}); 154 verifyOp(op, {i32Ty, f32Ty}, {*cstI32, *cstF32}, noAttrs); 155 156 // Test collective args, collective results method, building a binary op with 157 // named attributes. 158 op = builder.create<test::TableGenBuildOp1>( 159 loc, TypeRange{i32Ty, f32Ty}, ValueRange{*cstI32, *cstF32}, attrs); 160 verifyOp(op, {i32Ty, f32Ty}, {*cstI32, *cstF32}, attrs); 161 } 162 163 /// Test build methods for an Op with a single varadic arg and a non-variadic 164 /// result. 165 TEST_F(OpBuildGenTest, BuildMethodsSingleVariadicArgNonVariadicResults) { 166 // Test separate arg, separate param build method. 167 auto op = 168 builder.create<test::TableGenBuildOp1>(loc, i32Ty, ValueRange{*cstI32}); 169 verifyOp(op, {i32Ty}, {*cstI32}, noAttrs); 170 171 // Test collective params build method, no attributes. 172 op = builder.create<test::TableGenBuildOp1>(loc, TypeRange{i32Ty}, 173 ValueRange{*cstI32}); 174 verifyOp(op, {i32Ty}, {*cstI32}, noAttrs); 175 176 // Test collective params build method no attributes, 2 inputs. 177 op = builder.create<test::TableGenBuildOp1>(loc, TypeRange{i32Ty}, 178 ValueRange{*cstI32, *cstF32}); 179 verifyOp(op, {i32Ty}, {*cstI32, *cstF32}, noAttrs); 180 181 // Test collective params build method, non-empty attributes. 182 op = builder.create<test::TableGenBuildOp1>( 183 loc, TypeRange{i32Ty}, ValueRange{*cstI32, *cstF32}, attrs); 184 verifyOp(op, {i32Ty}, {*cstI32, *cstF32}, attrs); 185 } 186 187 /// Test build methods for an Op with a single varadic arg and multiple variadic 188 /// result. 189 TEST_F(OpBuildGenTest, 190 BuildMethodsSingleVariadicArgAndMultipleVariadicResults) { 191 // Test separate arg, separate param build method. 192 auto op = builder.create<test::TableGenBuildOp3>( 193 loc, TypeRange{i32Ty}, TypeRange{f32Ty}, ValueRange{*cstI32}); 194 verifyOp(op, {i32Ty, f32Ty}, {*cstI32}, noAttrs); 195 196 // Test collective params build method, no attributes. 197 op = builder.create<test::TableGenBuildOp3>(loc, TypeRange{i32Ty, f32Ty}, 198 ValueRange{*cstI32}); 199 verifyOp(op, {i32Ty, f32Ty}, {*cstI32}, noAttrs); 200 201 // Test collective params build method, with attributes. 202 op = builder.create<test::TableGenBuildOp3>(loc, TypeRange{i32Ty, f32Ty}, 203 ValueRange{*cstI32}, attrs); 204 verifyOp(op, {i32Ty, f32Ty}, {*cstI32}, attrs); 205 } 206 207 // The next test checks supression of ambiguous build methods for ops that 208 // have a single variadic input, and single non-variadic result, and which 209 // support the SameOperandsAndResultType trait and and optionally the 210 // InferOpTypeInterface interface. For such ops, the ODS framework generates 211 // build methods with no result types as they are inferred from the input types. 212 TEST_F(OpBuildGenTest, BuildMethodsSameOperandsAndResultTypeSuppression) { 213 testSingleVariadicInputInferredType<test::TableGenBuildOp4>(); 214 } 215 216 TEST_F(OpBuildGenTest, BuildMethodsRegionsAndInferredType) { 217 auto op = builder.create<test::TableGenBuildOp5>( 218 loc, ValueRange{*cstI32, *cstF32}, /*attributes=*/noAttrs); 219 ASSERT_EQ(op->getNumRegions(), 1u); 220 verifyOp(op, {i32Ty}, {*cstI32, *cstF32}, noAttrs); 221 } 222 223 } // namespace mlir 224