xref: /llvm-project/mlir/unittests/TableGen/OpBuildGen.cpp (revision e67080df999c035d764c42aaa6d85417331ac52c)
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 "TestOps.h"
15 #include "mlir/IR/Attributes.h"
16 #include "mlir/IR/Builders.h"
17 #include "mlir/IR/BuiltinTypes.h"
18 #include "mlir/IR/Dialect.h"
19 #include "gmock/gmock.h"
20 #include <vector>
21 
22 namespace mlir {
23 
24 //===----------------------------------------------------------------------===//
25 // Test Fixture
26 //===----------------------------------------------------------------------===//
27 
getContext()28 static MLIRContext &getContext() {
29   static MLIRContext ctx;
30   ctx.getOrLoadDialect<test::TestDialect>();
31   return ctx;
32 }
33 /// Test fixture for providing basic utilities for testing.
34 class OpBuildGenTest : public ::testing::Test {
35 protected:
OpBuildGenTest()36   OpBuildGenTest()
37       : ctx(getContext()), builder(&ctx), loc(builder.getUnknownLoc()),
38         i32Ty(builder.getI32Type()), f32Ty(builder.getF32Type()),
39         cstI32(builder.create<test::TableGenConstant>(loc, i32Ty)),
40         cstF32(builder.create<test::TableGenConstant>(loc, f32Ty)),
41         noAttrs(), attrStorage{builder.getNamedAttr("attr0",
42                                                     builder.getBoolAttr(true)),
43                                builder.getNamedAttr(
44                                    "attr1", builder.getI32IntegerAttr(33))},
45         attrs(attrStorage) {}
46 
47   // Verify that `op` has the given set of result types, operands, and
48   // attributes.
49   template <typename OpTy>
verifyOp(OpTy && concreteOp,std::vector<Type> resultTypes,std::vector<Value> operands,std::vector<NamedAttribute> attrs)50   void verifyOp(OpTy &&concreteOp, std::vector<Type> resultTypes,
51                 std::vector<Value> operands,
52                 std::vector<NamedAttribute> attrs) {
53     ASSERT_NE(concreteOp, nullptr);
54     Operation *op = concreteOp.getOperation();
55 
56     EXPECT_EQ(op->getNumResults(), resultTypes.size());
57     for (unsigned idx : llvm::seq(0U, op->getNumResults()))
58       EXPECT_EQ(op->getResult(idx).getType(), resultTypes[idx]);
59 
60     EXPECT_EQ(op->getNumOperands(), operands.size());
61     for (unsigned idx : llvm::seq(0U, op->getNumOperands()))
62       EXPECT_EQ(op->getOperand(idx), operands[idx]);
63 
64     EXPECT_EQ(op->getAttrs().size(), attrs.size());
65     for (unsigned idx : llvm::seq<unsigned>(0U, attrs.size()))
66       EXPECT_EQ(op->getAttr(attrs[idx].getName().strref()),
67                 attrs[idx].getValue());
68 
69     EXPECT_TRUE(mlir::succeeded(concreteOp.verify()));
70     concreteOp.erase();
71   }
72 
73   template <typename OpTy>
verifyOp(OpTy && concreteOp,std::vector<Type> resultTypes,std::vector<Value> operands1,std::vector<Value> operands2,std::vector<NamedAttribute> attrs)74   void verifyOp(OpTy &&concreteOp, std::vector<Type> resultTypes,
75                 std::vector<Value> operands1, std::vector<Value> operands2,
76                 std::vector<NamedAttribute> attrs) {
77     ASSERT_NE(concreteOp, nullptr);
78     Operation *op = concreteOp.getOperation();
79 
80     EXPECT_EQ(op->getNumResults(), resultTypes.size());
81     for (unsigned idx : llvm::seq(0U, op->getNumResults()))
82       EXPECT_EQ(op->getResult(idx).getType(), resultTypes[idx]);
83 
84     auto operands = llvm::to_vector(llvm::concat<Value>(operands1, operands2));
85     EXPECT_EQ(op->getNumOperands(), operands.size());
86     for (unsigned idx : llvm::seq(0U, op->getNumOperands()))
87       EXPECT_EQ(op->getOperand(idx), operands[idx]);
88 
89     EXPECT_EQ(op->getAttrs().size(), attrs.size());
90     if (op->getAttrs().size() != attrs.size()) {
91       // Simple export where there is mismatch count.
92       llvm::errs() << "Op attrs:\n";
93       for (auto it : op->getAttrs())
94         llvm::errs() << "\t" << it.getName() << " = " << it.getValue() << "\n";
95 
96       llvm::errs() << "Expected attrs:\n";
97       for (auto it : attrs)
98         llvm::errs() << "\t" << it.getName() << " = " << it.getValue() << "\n";
99     } else {
100       for (unsigned idx : llvm::seq<unsigned>(0U, attrs.size()))
101         EXPECT_EQ(op->getAttr(attrs[idx].getName().strref()),
102                   attrs[idx].getValue());
103     }
104 
105     EXPECT_TRUE(mlir::succeeded(concreteOp.verify()));
106     concreteOp.erase();
107   }
108 
109 protected:
110   MLIRContext &ctx;
111   OpBuilder builder;
112   Location loc;
113   Type i32Ty;
114   Type f32Ty;
115   OwningOpRef<test::TableGenConstant> cstI32;
116   OwningOpRef<test::TableGenConstant> cstF32;
117 
118   ArrayRef<NamedAttribute> noAttrs;
119   std::vector<NamedAttribute> attrStorage;
120   ArrayRef<NamedAttribute> attrs;
121 };
122 
123 /// Test basic build methods.
TEST_F(OpBuildGenTest,BasicBuildMethods)124 TEST_F(OpBuildGenTest, BasicBuildMethods) {
125   // Test separate args, separate results build method.
126   auto op = builder.create<test::TableGenBuildOp0>(loc, i32Ty, *cstI32);
127   verifyOp(op, {i32Ty}, {*cstI32}, noAttrs);
128 
129   // Test separate args, collective results build method.
130   op = builder.create<test::TableGenBuildOp0>(loc, TypeRange{i32Ty}, *cstI32);
131   verifyOp(op, {i32Ty}, {*cstI32}, noAttrs);
132 
133   // Test collective args, collective params build method.
134   op = builder.create<test::TableGenBuildOp0>(loc, TypeRange{i32Ty},
135                                               ValueRange{*cstI32});
136   verifyOp(op, {i32Ty}, {*cstI32}, noAttrs);
137 
138   // Test collective args, collective results, non-empty attributes
139   op = builder.create<test::TableGenBuildOp0>(loc, TypeRange{i32Ty},
140                                               ValueRange{*cstI32}, attrs);
141   verifyOp(op, {i32Ty}, {*cstI32}, attrs);
142 }
143 
144 /// The following 3 tests exercise build methods generated for operations
145 /// with a combination of:
146 ///
147 /// single variadic arg x
148 /// {single variadic result, non-variadic result, multiple variadic results}
149 ///
150 /// Specifically to test that ODS framework does not generate ambiguous
151 /// build() methods that fail to compile.
152 
153 /// Test build methods for an Op with a single varadic arg and a single
154 /// variadic result.
TEST_F(OpBuildGenTest,BuildMethodsSingleVariadicArgAndResult)155 TEST_F(OpBuildGenTest, BuildMethodsSingleVariadicArgAndResult) {
156   // Test collective args, collective results method, building a unary op.
157   auto op = builder.create<test::TableGenBuildOp1>(loc, TypeRange{i32Ty},
158                                                    ValueRange{*cstI32});
159   verifyOp(op, {i32Ty}, {*cstI32}, noAttrs);
160 
161   // Test collective args, collective results method, building a unary op with
162   // named attributes.
163   op = builder.create<test::TableGenBuildOp1>(loc, TypeRange{i32Ty},
164                                               ValueRange{*cstI32}, attrs);
165   verifyOp(op, {i32Ty}, {*cstI32}, attrs);
166 
167   // Test collective args, collective results method, building a binary op.
168   op = builder.create<test::TableGenBuildOp1>(loc, TypeRange{i32Ty, f32Ty},
169                                               ValueRange{*cstI32, *cstF32});
170   verifyOp(op, {i32Ty, f32Ty}, {*cstI32, *cstF32}, noAttrs);
171 
172   // Test collective args, collective results method, building a binary op with
173   // named attributes.
174   op = builder.create<test::TableGenBuildOp1>(
175       loc, TypeRange{i32Ty, f32Ty}, ValueRange{*cstI32, *cstF32}, attrs);
176   verifyOp(op, {i32Ty, f32Ty}, {*cstI32, *cstF32}, attrs);
177 }
178 
179 /// Test build methods for an Op with a single varadic arg and a non-variadic
180 /// result.
TEST_F(OpBuildGenTest,BuildMethodsSingleVariadicArgNonVariadicResults)181 TEST_F(OpBuildGenTest, BuildMethodsSingleVariadicArgNonVariadicResults) {
182   // Test separate arg, separate param build method.
183   auto op =
184       builder.create<test::TableGenBuildOp1>(loc, i32Ty, ValueRange{*cstI32});
185   verifyOp(op, {i32Ty}, {*cstI32}, noAttrs);
186 
187   // Test collective params build method, no attributes.
188   op = builder.create<test::TableGenBuildOp1>(loc, TypeRange{i32Ty},
189                                               ValueRange{*cstI32});
190   verifyOp(op, {i32Ty}, {*cstI32}, noAttrs);
191 
192   // Test collective params build method no attributes, 2 inputs.
193   op = builder.create<test::TableGenBuildOp1>(loc, TypeRange{i32Ty},
194                                               ValueRange{*cstI32, *cstF32});
195   verifyOp(op, {i32Ty}, {*cstI32, *cstF32}, noAttrs);
196 
197   // Test collective params build method, non-empty attributes.
198   op = builder.create<test::TableGenBuildOp1>(
199       loc, TypeRange{i32Ty}, ValueRange{*cstI32, *cstF32}, attrs);
200   verifyOp(op, {i32Ty}, {*cstI32, *cstF32}, attrs);
201 }
202 
203 /// Test build methods for an Op with a single varadic arg and multiple variadic
204 /// result.
TEST_F(OpBuildGenTest,BuildMethodsSingleVariadicArgAndMultipleVariadicResults)205 TEST_F(OpBuildGenTest,
206        BuildMethodsSingleVariadicArgAndMultipleVariadicResults) {
207   // Test separate arg, separate param build method.
208   auto op = builder.create<test::TableGenBuildOp3>(
209       loc, TypeRange{i32Ty}, TypeRange{f32Ty}, ValueRange{*cstI32});
210   verifyOp(op, {i32Ty, f32Ty}, {*cstI32}, noAttrs);
211 
212   // Test collective params build method, no attributes.
213   op = builder.create<test::TableGenBuildOp3>(loc, TypeRange{i32Ty, f32Ty},
214                                               ValueRange{*cstI32});
215   verifyOp(op, {i32Ty, f32Ty}, {*cstI32}, noAttrs);
216 
217   // Test collective params build method, with attributes.
218   op = builder.create<test::TableGenBuildOp3>(loc, TypeRange{i32Ty, f32Ty},
219                                               ValueRange{*cstI32}, attrs);
220   verifyOp(op, {i32Ty, f32Ty}, {*cstI32}, attrs);
221 }
222 
223 // The next test checks suppression of ambiguous build methods for ops that
224 // have a single variadic input, and single non-variadic result, and which
225 // support the SameOperandsAndResultType trait and optionally the
226 // InferOpTypeInterface interface. For such ops, the ODS framework generates
227 // build methods with no result types as they are inferred from the input types.
TEST_F(OpBuildGenTest,BuildMethodsSameOperandsAndResultTypeSuppression)228 TEST_F(OpBuildGenTest, BuildMethodsSameOperandsAndResultTypeSuppression) {
229   // Test separate arg, separate param build method.
230   auto op = builder.create<test::TableGenBuildOp4>(
231       loc, i32Ty, ValueRange{*cstI32, *cstI32});
232   verifyOp(std::move(op), {i32Ty}, {*cstI32, *cstI32}, noAttrs);
233 
234   // Test collective params build method.
235   op = builder.create<test::TableGenBuildOp4>(loc, TypeRange{i32Ty},
236                                               ValueRange{*cstI32, *cstI32});
237   verifyOp(std::move(op), {i32Ty}, {*cstI32, *cstI32}, noAttrs);
238 
239   // Test build method with no result types, default value of attributes.
240   op =
241       builder.create<test::TableGenBuildOp4>(loc, ValueRange{*cstI32, *cstI32});
242   verifyOp(std::move(op), {i32Ty}, {*cstI32, *cstI32}, noAttrs);
243 
244   // Test build method with no result types and supplied attributes.
245   op = builder.create<test::TableGenBuildOp4>(loc, ValueRange{*cstI32, *cstI32},
246                                               attrs);
247   verifyOp(std::move(op), {i32Ty}, {*cstI32, *cstI32}, attrs);
248 }
249 
TEST_F(OpBuildGenTest,BuildMethodsRegionsAndInferredType)250 TEST_F(OpBuildGenTest, BuildMethodsRegionsAndInferredType) {
251   auto op = builder.create<test::TableGenBuildOp5>(
252       loc, ValueRange{*cstI32, *cstF32}, /*attributes=*/noAttrs);
253   ASSERT_EQ(op->getNumRegions(), 1u);
254   verifyOp(op, {i32Ty}, {*cstI32, *cstF32}, noAttrs);
255 }
256 
TEST_F(OpBuildGenTest,BuildMethodsVariadicProperties)257 TEST_F(OpBuildGenTest, BuildMethodsVariadicProperties) {
258   // Account for conversion as part of getAttrs().
259   std::vector<NamedAttribute> noAttrsStorage;
260   auto segmentSize = builder.getNamedAttr("operandSegmentSizes",
261                                           builder.getDenseI32ArrayAttr({1, 1}));
262   noAttrsStorage.push_back(segmentSize);
263   ArrayRef<NamedAttribute> noAttrs(noAttrsStorage);
264   std::vector<NamedAttribute> attrsStorage = this->attrStorage;
265   attrsStorage.push_back(segmentSize);
266   ArrayRef<NamedAttribute> attrs(attrsStorage);
267 
268   // Test separate arg, separate param build method.
269   auto op = builder.create<test::TableGenBuildOp6>(
270       loc, f32Ty, ValueRange{*cstI32}, ValueRange{*cstI32});
271   verifyOp(std::move(op), {f32Ty}, {*cstI32}, {*cstI32}, noAttrs);
272 
273   // Test build method with no result types, default value of attributes.
274   op = builder.create<test::TableGenBuildOp6>(loc, ValueRange{*cstI32},
275                                               ValueRange{*cstI32});
276   verifyOp(std::move(op), {f32Ty}, {*cstI32}, {*cstI32}, noAttrs);
277 
278   // Test collective params build method.
279   op = builder.create<test::TableGenBuildOp6>(
280       loc, TypeRange{f32Ty}, ValueRange{*cstI32}, ValueRange{*cstI32});
281   verifyOp(std::move(op), {f32Ty}, {*cstI32}, {*cstI32}, noAttrs);
282 
283   // Test build method with result types, supplied attributes.
284   op = builder.create<test::TableGenBuildOp6>(
285       loc, TypeRange{f32Ty}, ValueRange{*cstI32, *cstI32}, attrs);
286   verifyOp(std::move(op), {f32Ty}, {*cstI32}, {*cstI32}, attrs);
287 
288   // Test build method with no result types and supplied attributes.
289   op = builder.create<test::TableGenBuildOp6>(loc, ValueRange{*cstI32, *cstI32},
290                                               attrs);
291   verifyOp(std::move(op), {f32Ty}, {*cstI32}, {*cstI32}, attrs);
292 }
293 
294 } // namespace mlir
295