1 //===- OpBuildGen.cpp - TableGen OpBuildGen Tests -------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 // Test TableGen generated build() methods on Operations.
11 //===----------------------------------------------------------------------===//
13 #include "TestDialect.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"
24 //===----------------------------------------------------------------------===//
26 //===----------------------------------------------------------------------===//
28 static MLIRContext
&getContext() {
29 static MLIRContext ctx
;
30 ctx
.getOrLoadDialect
<test::TestDialect
>();
33 /// Test fixture for providing basic utilities for testing.
34 class OpBuildGenTest
: public ::testing::Test
{
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)),
44 "attr1", builder
.getI32IntegerAttr(33))},
47 // Verify that `op` has the given set of result types, operands, and
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();
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
]);
60 EXPECT_EQ(op
->getNumOperands(), operands
.size());
61 for (unsigned idx
: llvm::seq(0U, op
->getNumOperands()))
62 EXPECT_EQ(op
->getOperand(idx
), operands
[idx
]);
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());
69 EXPECT_TRUE(mlir::succeeded(concreteOp
.verify()));
73 template <typename OpTy
>
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();
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
]);
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
]);
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";
96 llvm::errs() << "Expected attrs:\n";
98 llvm::errs() << "\t" << it
.getName() << " = " << it
.getValue() << "\n";
100 for (unsigned idx
: llvm::seq
<unsigned>(0U, attrs
.size()))
101 EXPECT_EQ(op
->getAttr(attrs
[idx
].getName().strref()),
102 attrs
[idx
].getValue());
105 EXPECT_TRUE(mlir::succeeded(concreteOp
.verify()));
115 OwningOpRef
<test::TableGenConstant
> cstI32
;
116 OwningOpRef
<test::TableGenConstant
> cstF32
;
118 ArrayRef
<NamedAttribute
> noAttrs
;
119 std::vector
<NamedAttribute
> attrStorage
;
120 ArrayRef
<NamedAttribute
> attrs
;
123 /// Test basic build methods.
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
);
129 // Test separate args, collective results build method.
130 op
= builder
.create
<test::TableGenBuildOp0
>(loc
, TypeRange
{i32Ty
}, *cstI32
);
131 verifyOp(op
, {i32Ty
}, {*cstI32
}, noAttrs
);
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
);
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
);
144 /// The following 3 tests exercise build methods generated for operations
145 /// with a combination of:
147 /// single variadic arg x
148 /// {single variadic result, non-variadic result, multiple variadic results}
150 /// Specifically to test that ODS framework does not generate ambiguous
151 /// build() methods that fail to compile.
153 /// Test build methods for an Op with a single varadic arg and a single
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
);
161 // Test collective args, collective results method, building a unary op with
163 op
= builder
.create
<test::TableGenBuildOp1
>(loc
, TypeRange
{i32Ty
},
164 ValueRange
{*cstI32
}, attrs
);
165 verifyOp(op
, {i32Ty
}, {*cstI32
}, attrs
);
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
);
172 // Test collective args, collective results method, building a binary op with
174 op
= builder
.create
<test::TableGenBuildOp1
>(
175 loc
, TypeRange
{i32Ty
, f32Ty
}, ValueRange
{*cstI32
, *cstF32
}, attrs
);
176 verifyOp(op
, {i32Ty
, f32Ty
}, {*cstI32
, *cstF32
}, attrs
);
179 /// Test build methods for an Op with a single varadic arg and a non-variadic
181 TEST_F(OpBuildGenTest
, BuildMethodsSingleVariadicArgNonVariadicResults
) {
182 // Test separate arg, separate param build method.
184 builder
.create
<test::TableGenBuildOp1
>(loc
, i32Ty
, ValueRange
{*cstI32
});
185 verifyOp(op
, {i32Ty
}, {*cstI32
}, noAttrs
);
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
);
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
);
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
);
203 /// Test build methods for an Op with a single varadic arg and multiple variadic
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
);
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
);
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
);
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.
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
);
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
);
239 // Test build method with no result types, default value of attributes.
241 builder
.create
<test::TableGenBuildOp4
>(loc
, ValueRange
{*cstI32
, *cstI32
});
242 verifyOp(std::move(op
), {i32Ty
}, {*cstI32
, *cstI32
}, noAttrs
);
244 // Test build method with no result types and supplied attributes.
245 op
= builder
.create
<test::TableGenBuildOp4
>(loc
, ValueRange
{*cstI32
, *cstI32
},
247 verifyOp(std::move(op
), {i32Ty
}, {*cstI32
, *cstI32
}, attrs
);
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
);
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
);
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
);
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
);
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
);
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
);
288 // Test build method with no result types and supplied attributes.
289 op
= builder
.create
<test::TableGenBuildOp6
>(loc
, ValueRange
{*cstI32
, *cstI32
},
291 verifyOp(std::move(op
), {f32Ty
}, {*cstI32
}, {*cstI32
}, attrs
);