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].first.strref()), attrs[idx].second); 66 67 concreteOp.erase(); 68 } 69 70 // Helper method to test ops with inferred result types and single variadic 71 // input. 72 template <typename OpTy> 73 void testSingleVariadicInputInferredType() { 74 // Test separate arg, separate param build method. 75 auto op = builder.create<OpTy>(loc, i32Ty, ValueRange{*cstI32, *cstI32}); 76 verifyOp(std::move(op), {i32Ty}, {*cstI32, *cstI32}, noAttrs); 77 78 // Test collective params build method. 79 op = 80 builder.create<OpTy>(loc, TypeRange{i32Ty}, ValueRange{*cstI32, *cstI32}); 81 verifyOp(std::move(op), {i32Ty}, {*cstI32, *cstI32}, noAttrs); 82 83 // Test build method with no result types, default value of attributes. 84 op = builder.create<OpTy>(loc, ValueRange{*cstI32, *cstI32}); 85 verifyOp(std::move(op), {i32Ty}, {*cstI32, *cstI32}, noAttrs); 86 87 // Test build method with no result types and supplied attributes. 88 op = builder.create<OpTy>(loc, ValueRange{*cstI32, *cstI32}, attrs); 89 verifyOp(std::move(op), {i32Ty}, {*cstI32, *cstI32}, attrs); 90 } 91 92 protected: 93 MLIRContext &ctx; 94 OpBuilder builder; 95 Location loc; 96 Type i32Ty; 97 Type f32Ty; 98 OwningOpRef<test::TableGenConstant> cstI32; 99 OwningOpRef<test::TableGenConstant> cstF32; 100 101 ArrayRef<NamedAttribute> noAttrs; 102 std::vector<NamedAttribute> attrStorage; 103 ArrayRef<NamedAttribute> attrs; 104 }; 105 106 /// Test basic build methods. 107 TEST_F(OpBuildGenTest, BasicBuildMethods) { 108 // Test separate args, separate results build method. 109 auto op = builder.create<test::TableGenBuildOp0>(loc, i32Ty, *cstI32); 110 verifyOp(op, {i32Ty}, {*cstI32}, noAttrs); 111 112 // Test separate args, collective results build method. 113 op = builder.create<test::TableGenBuildOp0>(loc, TypeRange{i32Ty}, *cstI32); 114 verifyOp(op, {i32Ty}, {*cstI32}, noAttrs); 115 116 // Test collective args, collective params build method. 117 op = builder.create<test::TableGenBuildOp0>(loc, TypeRange{i32Ty}, 118 ValueRange{*cstI32}); 119 verifyOp(op, {i32Ty}, {*cstI32}, noAttrs); 120 121 // Test collective args, collective results, non-empty attributes 122 op = builder.create<test::TableGenBuildOp0>(loc, TypeRange{i32Ty}, 123 ValueRange{*cstI32}, attrs); 124 verifyOp(op, {i32Ty}, {*cstI32}, attrs); 125 } 126 127 /// The following 3 tests exercise build methods generated for operations 128 /// with a combination of: 129 /// 130 /// single variadic arg x 131 /// {single variadic result, non-variadic result, multiple variadic results} 132 /// 133 /// Specifically to test that that ODS framework does not generate ambiguous 134 /// build() methods that fail to compile. 135 136 /// Test build methods for an Op with a single varadic arg and a single 137 /// variadic result. 138 TEST_F(OpBuildGenTest, BuildMethodsSingleVariadicArgAndResult) { 139 // Test collective args, collective results method, building a unary op. 140 auto op = builder.create<test::TableGenBuildOp1>(loc, TypeRange{i32Ty}, 141 ValueRange{*cstI32}); 142 verifyOp(std::move(op), {i32Ty}, {*cstI32}, noAttrs); 143 144 // Test collective args, collective results method, building a unary op with 145 // named attributes. 146 op = builder.create<test::TableGenBuildOp1>(loc, TypeRange{i32Ty}, 147 ValueRange{*cstI32}, attrs); 148 verifyOp(std::move(op), {i32Ty}, {*cstI32}, attrs); 149 150 // Test collective args, collective results method, building a binary op. 151 op = builder.create<test::TableGenBuildOp1>(loc, TypeRange{i32Ty, f32Ty}, 152 ValueRange{*cstI32, *cstF32}); 153 verifyOp(std::move(op), {i32Ty, f32Ty}, {*cstI32, *cstF32}, noAttrs); 154 155 // Test collective args, collective results method, building a binary op with 156 // named attributes. 157 op = builder.create<test::TableGenBuildOp1>( 158 loc, TypeRange{i32Ty, f32Ty}, ValueRange{*cstI32, *cstF32}, attrs); 159 verifyOp(std::move(op), {i32Ty, f32Ty}, {*cstI32, *cstF32}, attrs); 160 } 161 162 /// Test build methods for an Op with a single varadic arg and a non-variadic 163 /// result. 164 TEST_F(OpBuildGenTest, BuildMethodsSingleVariadicArgNonVariadicResults) { 165 // Test separate arg, separate param build method. 166 auto op = 167 builder.create<test::TableGenBuildOp1>(loc, i32Ty, ValueRange{*cstI32}); 168 verifyOp(std::move(op), {i32Ty}, {*cstI32}, noAttrs); 169 170 // Test collective params build method, no attributes. 171 op = builder.create<test::TableGenBuildOp1>(loc, TypeRange{i32Ty}, 172 ValueRange{*cstI32}); 173 verifyOp(std::move(op), {i32Ty}, {*cstI32}, noAttrs); 174 175 // Test collective params build method no attributes, 2 inputs. 176 op = builder.create<test::TableGenBuildOp1>(loc, TypeRange{i32Ty}, 177 ValueRange{*cstI32, *cstF32}); 178 verifyOp(std::move(op), {i32Ty}, {*cstI32, *cstF32}, noAttrs); 179 180 // Test collective params build method, non-empty attributes. 181 op = builder.create<test::TableGenBuildOp1>( 182 loc, TypeRange{i32Ty}, ValueRange{*cstI32, *cstF32}, attrs); 183 verifyOp(std::move(op), {i32Ty}, {*cstI32, *cstF32}, attrs); 184 } 185 186 /// Test build methods for an Op with a single varadic arg and multiple variadic 187 /// result. 188 TEST_F(OpBuildGenTest, 189 BuildMethodsSingleVariadicArgAndMultipleVariadicResults) { 190 // Test separate arg, separate param build method. 191 auto op = builder.create<test::TableGenBuildOp3>( 192 loc, TypeRange{i32Ty}, TypeRange{f32Ty}, ValueRange{*cstI32}); 193 verifyOp(std::move(op), {i32Ty, f32Ty}, {*cstI32}, noAttrs); 194 195 // Test collective params build method, no attributes. 196 op = builder.create<test::TableGenBuildOp3>(loc, TypeRange{i32Ty, f32Ty}, 197 ValueRange{*cstI32}); 198 verifyOp(std::move(op), {i32Ty, f32Ty}, {*cstI32}, noAttrs); 199 200 // Test collective params build method, with attributes. 201 op = builder.create<test::TableGenBuildOp3>(loc, TypeRange{i32Ty, f32Ty}, 202 ValueRange{*cstI32}, attrs); 203 verifyOp(std::move(op), {i32Ty, f32Ty}, {*cstI32}, attrs); 204 } 205 206 // The next 2 tests test supression of ambiguous build methods for ops that 207 // have a single variadic input, and single non-variadic result, and which 208 // support the SameOperandsAndResultType trait and and optionally the 209 // InferOpTypeInterface interface. For such ops, the ODS framework generates 210 // build methods with no result types as they are inferred from the input types. 211 TEST_F(OpBuildGenTest, BuildMethodsSameOperandsAndResultTypeSuppression) { 212 testSingleVariadicInputInferredType<test::TableGenBuildOp4>(); 213 } 214 215 TEST_F( 216 OpBuildGenTest, 217 BuildMethodsSameOperandsAndResultTypeAndInferOpTypeInterfaceSuppression) { 218 testSingleVariadicInputInferredType<test::TableGenBuildOp5>(); 219 } 220 221 } // namespace mlir 222