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