1//===- OpenACCOpsTest.cpp - OpenACC ops extra functiosn 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#include "mlir/Dialect/Arith/IR/Arith.h"
10#include "mlir/Dialect/OpenACC/OpenACC.h"
11#include "mlir/IR/Diagnostics.h"
12#include "mlir/IR/MLIRContext.h"
13#include "mlir/IR/OwningOpRef.h"
14#include "gtest/gtest.h"
15
16using namespace mlir;
17using namespace mlir::acc;
18
19//===----------------------------------------------------------------------===//
20// Test Fixture
21//===----------------------------------------------------------------------===//
22
23class OpenACCOpsTest : public ::testing::Test {
24protected:
25 OpenACCOpsTest() : b(&context), loc(UnknownLoc::get(&context)) {
26 context.loadDialect<acc::OpenACCDialect, arith::ArithDialect>();
27 }
28
29 MLIRContext context;
30 OpBuilder b;
31 Location loc;
32 llvm::SmallVector<DeviceType> dtypes = {
33 DeviceType::None, DeviceType::Star, DeviceType::Multicore,
34 DeviceType::Default, DeviceType::Host, DeviceType::Nvidia,
35 DeviceType::Radeon};
36 llvm::SmallVector<DeviceType> dtypesWithoutNone = {
37 DeviceType::Star, DeviceType::Multicore, DeviceType::Default,
38 DeviceType::Host, DeviceType::Nvidia, DeviceType::Radeon};
39};
40
41template <typename Op>
42void testAsyncOnly(OpBuilder &b, MLIRContext &context, Location loc,
43 llvm::SmallVector<DeviceType> &dtypes) {
44 OwningOpRef<Op> op = b.create<Op>(loc, TypeRange{}, ValueRange{});
45 EXPECT_FALSE(op->hasAsyncOnly());
46 for (auto d : dtypes)
47 EXPECT_FALSE(op->hasAsyncOnly(d));
48
49 auto dtypeNone = DeviceTypeAttr::get(&context, DeviceType::None);
50 op->setAsyncOnlyAttr(b.getArrayAttr(value: {dtypeNone}));
51 EXPECT_TRUE(op->hasAsyncOnly());
52 EXPECT_TRUE(op->hasAsyncOnly(DeviceType::None));
53 op->removeAsyncOnlyAttr();
54
55 auto dtypeHost = DeviceTypeAttr::get(&context, DeviceType::Host);
56 op->setAsyncOnlyAttr(b.getArrayAttr(value: {dtypeHost}));
57 EXPECT_TRUE(op->hasAsyncOnly(DeviceType::Host));
58 EXPECT_FALSE(op->hasAsyncOnly());
59 op->removeAsyncOnlyAttr();
60
61 auto dtypeStar = DeviceTypeAttr::get(&context, DeviceType::Star);
62 op->setAsyncOnlyAttr(b.getArrayAttr(value: {dtypeHost, dtypeStar}));
63 EXPECT_TRUE(op->hasAsyncOnly(DeviceType::Star));
64 EXPECT_TRUE(op->hasAsyncOnly(DeviceType::Host));
65 EXPECT_FALSE(op->hasAsyncOnly());
66
67 op->removeAsyncOnlyAttr();
68}
69
70TEST_F(OpenACCOpsTest, asyncOnlyTest) {
71 testAsyncOnly<ParallelOp>(b, context, loc, dtypes);
72 testAsyncOnly<KernelsOp>(b, context, loc, dtypes);
73 testAsyncOnly<SerialOp>(b, context, loc, dtypes);
74}
75
76template <typename Op>
77void testAsyncValue(OpBuilder &b, MLIRContext &context, Location loc,
78 llvm::SmallVector<DeviceType> &dtypes) {
79 OwningOpRef<Op> op = b.create<Op>(loc, TypeRange{}, ValueRange{});
80
81 mlir::Value empty;
82 EXPECT_EQ(op->getAsyncValue(), empty);
83 for (auto d : dtypes)
84 EXPECT_EQ(op->getAsyncValue(d), empty);
85
86 OwningOpRef<arith::ConstantIndexOp> val =
87 b.create<arith::ConstantIndexOp>(location: loc, args: 1);
88 auto dtypeNvidia = DeviceTypeAttr::get(&context, DeviceType::Nvidia);
89 op->setAsyncOperandsDeviceTypeAttr(b.getArrayAttr(value: {dtypeNvidia}));
90 op->getAsyncOperandsMutable().assign(val->getResult());
91 EXPECT_EQ(op->getAsyncValue(), empty);
92 EXPECT_EQ(op->getAsyncValue(DeviceType::Nvidia), val->getResult());
93
94 op->getAsyncOperandsMutable().clear();
95 op->removeAsyncOperandsDeviceTypeAttr();
96}
97
98TEST_F(OpenACCOpsTest, asyncValueTest) {
99 testAsyncValue<ParallelOp>(b, context, loc, dtypes);
100 testAsyncValue<KernelsOp>(b, context, loc, dtypes);
101 testAsyncValue<SerialOp>(b, context, loc, dtypes);
102}
103
104template <typename Op>
105void testNumGangsValues(OpBuilder &b, MLIRContext &context, Location loc,
106 llvm::SmallVector<DeviceType> &dtypes,
107 llvm::SmallVector<DeviceType> &dtypesWithoutNone) {
108 OwningOpRef<Op> op = b.create<Op>(loc, TypeRange{}, ValueRange{});
109 EXPECT_EQ(op->getNumGangsValues().begin(), op->getNumGangsValues().end());
110
111 OwningOpRef<arith::ConstantIndexOp> val1 =
112 b.create<arith::ConstantIndexOp>(location: loc, args: 1);
113 OwningOpRef<arith::ConstantIndexOp> val2 =
114 b.create<arith::ConstantIndexOp>(location: loc, args: 4);
115 auto dtypeNone = DeviceTypeAttr::get(&context, DeviceType::None);
116 op->getNumGangsMutable().assign(val1->getResult());
117 op->setNumGangsDeviceTypeAttr(b.getArrayAttr(value: {dtypeNone}));
118 op->setNumGangsSegments(b.getDenseI32ArrayAttr({1}));
119 EXPECT_EQ(op->getNumGangsValues().front(), val1->getResult());
120 for (auto d : dtypesWithoutNone)
121 EXPECT_EQ(op->getNumGangsValues(d).begin(), op->getNumGangsValues(d).end());
122
123 op->getNumGangsMutable().clear();
124 op->removeNumGangsDeviceTypeAttr();
125 op->removeNumGangsSegmentsAttr();
126 for (auto d : dtypes)
127 EXPECT_EQ(op->getNumGangsValues(d).begin(), op->getNumGangsValues(d).end());
128
129 op->getNumGangsMutable().append(val1->getResult());
130 op->getNumGangsMutable().append(val2->getResult());
131 op->setNumGangsDeviceTypeAttr(
132 b.getArrayAttr({DeviceTypeAttr::get(&context, DeviceType::Host),
133 DeviceTypeAttr::get(&context, DeviceType::Star)}));
134 op->setNumGangsSegments(b.getDenseI32ArrayAttr({1, 1}));
135 EXPECT_EQ(op->getNumGangsValues(DeviceType::None).begin(),
136 op->getNumGangsValues(DeviceType::None).end());
137 EXPECT_EQ(op->getNumGangsValues(DeviceType::Host).front(), val1->getResult());
138 EXPECT_EQ(op->getNumGangsValues(DeviceType::Star).front(), val2->getResult());
139
140 op->getNumGangsMutable().clear();
141 op->removeNumGangsDeviceTypeAttr();
142 op->removeNumGangsSegmentsAttr();
143 for (auto d : dtypes)
144 EXPECT_EQ(op->getNumGangsValues(d).begin(), op->getNumGangsValues(d).end());
145
146 op->getNumGangsMutable().append(val1->getResult());
147 op->getNumGangsMutable().append(val2->getResult());
148 op->getNumGangsMutable().append(val1->getResult());
149 op->setNumGangsDeviceTypeAttr(
150 b.getArrayAttr({DeviceTypeAttr::get(&context, DeviceType::Default),
151 DeviceTypeAttr::get(&context, DeviceType::Multicore)}));
152 op->setNumGangsSegments(b.getDenseI32ArrayAttr({2, 1}));
153 EXPECT_EQ(op->getNumGangsValues(DeviceType::None).begin(),
154 op->getNumGangsValues(DeviceType::None).end());
155 EXPECT_EQ(op->getNumGangsValues(DeviceType::Default).front(),
156 val1->getResult());
157 EXPECT_EQ(op->getNumGangsValues(DeviceType::Default).drop_front().front(),
158 val2->getResult());
159 EXPECT_EQ(op->getNumGangsValues(DeviceType::Multicore).front(),
160 val1->getResult());
161
162 op->getNumGangsMutable().clear();
163 op->removeNumGangsDeviceTypeAttr();
164 op->removeNumGangsSegmentsAttr();
165}
166
167TEST_F(OpenACCOpsTest, numGangsValuesTest) {
168 testNumGangsValues<ParallelOp>(b, context, loc, dtypes, dtypesWithoutNone);
169 testNumGangsValues<KernelsOp>(b, context, loc, dtypes, dtypesWithoutNone);
170}
171
172template <typename Op>
173void testVectorLength(OpBuilder &b, MLIRContext &context, Location loc,
174 llvm::SmallVector<DeviceType> &dtypes) {
175 OwningOpRef<Op> op = b.create<Op>(loc, TypeRange{}, ValueRange{});
176
177 mlir::Value empty;
178 EXPECT_EQ(op->getVectorLengthValue(), empty);
179 for (auto d : dtypes)
180 EXPECT_EQ(op->getVectorLengthValue(d), empty);
181
182 OwningOpRef<arith::ConstantIndexOp> val =
183 b.create<arith::ConstantIndexOp>(location: loc, args: 1);
184 auto dtypeNvidia = DeviceTypeAttr::get(&context, DeviceType::Nvidia);
185 op->setVectorLengthDeviceTypeAttr(b.getArrayAttr(value: {dtypeNvidia}));
186 op->getVectorLengthMutable().assign(val->getResult());
187 EXPECT_EQ(op->getVectorLengthValue(), empty);
188 EXPECT_EQ(op->getVectorLengthValue(DeviceType::Nvidia), val->getResult());
189
190 op->getVectorLengthMutable().clear();
191 op->removeVectorLengthDeviceTypeAttr();
192}
193
194TEST_F(OpenACCOpsTest, vectorLengthTest) {
195 testVectorLength<ParallelOp>(b, context, loc, dtypes);
196 testVectorLength<KernelsOp>(b, context, loc, dtypes);
197}
198
199template <typename Op>
200void testWaitOnly(OpBuilder &b, MLIRContext &context, Location loc,
201 llvm::SmallVector<DeviceType> &dtypes,
202 llvm::SmallVector<DeviceType> &dtypesWithoutNone) {
203 OwningOpRef<Op> op = b.create<Op>(loc, TypeRange{}, ValueRange{});
204 EXPECT_FALSE(op->hasWaitOnly());
205 for (auto d : dtypes)
206 EXPECT_FALSE(op->hasWaitOnly(d));
207
208 auto dtypeNone = DeviceTypeAttr::get(&context, DeviceType::None);
209 op->setWaitOnlyAttr(b.getArrayAttr(value: {dtypeNone}));
210 EXPECT_TRUE(op->hasWaitOnly());
211 EXPECT_TRUE(op->hasWaitOnly(DeviceType::None));
212 for (auto d : dtypesWithoutNone)
213 EXPECT_FALSE(op->hasWaitOnly(d));
214 op->removeWaitOnlyAttr();
215
216 auto dtypeHost = DeviceTypeAttr::get(&context, DeviceType::Host);
217 op->setWaitOnlyAttr(b.getArrayAttr(value: {dtypeHost}));
218 EXPECT_TRUE(op->hasWaitOnly(DeviceType::Host));
219 EXPECT_FALSE(op->hasWaitOnly());
220 op->removeWaitOnlyAttr();
221
222 auto dtypeStar = DeviceTypeAttr::get(&context, DeviceType::Star);
223 op->setWaitOnlyAttr(b.getArrayAttr(value: {dtypeHost, dtypeStar}));
224 EXPECT_TRUE(op->hasWaitOnly(DeviceType::Star));
225 EXPECT_TRUE(op->hasWaitOnly(DeviceType::Host));
226 EXPECT_FALSE(op->hasWaitOnly());
227
228 op->removeWaitOnlyAttr();
229}
230
231TEST_F(OpenACCOpsTest, waitOnlyTest) {
232 testWaitOnly<ParallelOp>(b, context, loc, dtypes, dtypesWithoutNone);
233 testWaitOnly<KernelsOp>(b, context, loc, dtypes, dtypesWithoutNone);
234 testWaitOnly<SerialOp>(b, context, loc, dtypes, dtypesWithoutNone);
235 testWaitOnly<UpdateOp>(b, context, loc, dtypes, dtypesWithoutNone);
236 testWaitOnly<DataOp>(b, context, loc, dtypes, dtypesWithoutNone);
237}
238
239template <typename Op>
240void testWaitValues(OpBuilder &b, MLIRContext &context, Location loc,
241 llvm::SmallVector<DeviceType> &dtypes,
242 llvm::SmallVector<DeviceType> &dtypesWithoutNone) {
243 OwningOpRef<Op> op = b.create<Op>(loc, TypeRange{}, ValueRange{});
244 EXPECT_EQ(op->getWaitValues().begin(), op->getWaitValues().end());
245
246 OwningOpRef<arith::ConstantIndexOp> val1 =
247 b.create<arith::ConstantIndexOp>(location: loc, args: 1);
248 OwningOpRef<arith::ConstantIndexOp> val2 =
249 b.create<arith::ConstantIndexOp>(location: loc, args: 4);
250 OwningOpRef<arith::ConstantIndexOp> val3 =
251 b.create<arith::ConstantIndexOp>(location: loc, args: 5);
252 auto dtypeNone = DeviceTypeAttr::get(&context, DeviceType::None);
253 op->getWaitOperandsMutable().assign(val1->getResult());
254 op->setWaitOperandsDeviceTypeAttr(b.getArrayAttr(value: {dtypeNone}));
255 op->setWaitOperandsSegments(b.getDenseI32ArrayAttr({1}));
256 op->setHasWaitDevnumAttr(b.getBoolArrayAttr({false}));
257 EXPECT_EQ(op->getWaitValues().front(), val1->getResult());
258 for (auto d : dtypesWithoutNone)
259 EXPECT_TRUE(op->getWaitValues(d).empty());
260
261 op->getWaitOperandsMutable().clear();
262 op->removeWaitOperandsDeviceTypeAttr();
263 op->removeWaitOperandsSegmentsAttr();
264 op->removeHasWaitDevnumAttr();
265 for (auto d : dtypes)
266 EXPECT_TRUE(op->getWaitValues(d).empty());
267
268 op->getWaitOperandsMutable().append(val1->getResult());
269 op->getWaitOperandsMutable().append(val2->getResult());
270 op->setWaitOperandsDeviceTypeAttr(
271 b.getArrayAttr({DeviceTypeAttr::get(&context, DeviceType::Host),
272 DeviceTypeAttr::get(&context, DeviceType::Star)}));
273 op->setWaitOperandsSegments(b.getDenseI32ArrayAttr({1, 1}));
274 op->setHasWaitDevnumAttr(b.getBoolArrayAttr({false, false}));
275 EXPECT_EQ(op->getWaitValues(DeviceType::None).begin(),
276 op->getWaitValues(DeviceType::None).end());
277 EXPECT_EQ(op->getWaitValues(DeviceType::Host).front(), val1->getResult());
278 EXPECT_EQ(op->getWaitValues(DeviceType::Star).front(), val2->getResult());
279
280 op->getWaitOperandsMutable().clear();
281 op->removeWaitOperandsDeviceTypeAttr();
282 op->removeWaitOperandsSegmentsAttr();
283 op->removeHasWaitDevnumAttr();
284 for (auto d : dtypes)
285 EXPECT_TRUE(op->getWaitValues(d).empty());
286
287 op->getWaitOperandsMutable().append(val1->getResult());
288 op->getWaitOperandsMutable().append(val2->getResult());
289 op->getWaitOperandsMutable().append(val1->getResult());
290 op->setWaitOperandsDeviceTypeAttr(
291 b.getArrayAttr({DeviceTypeAttr::get(&context, DeviceType::Default),
292 DeviceTypeAttr::get(&context, DeviceType::Multicore)}));
293 op->setWaitOperandsSegments(b.getDenseI32ArrayAttr({2, 1}));
294 op->setHasWaitDevnumAttr(b.getBoolArrayAttr({false, false}));
295 EXPECT_EQ(op->getWaitValues(DeviceType::None).begin(),
296 op->getWaitValues(DeviceType::None).end());
297 EXPECT_EQ(op->getWaitValues(DeviceType::Default).front(), val1->getResult());
298 EXPECT_EQ(op->getWaitValues(DeviceType::Default).drop_front().front(),
299 val2->getResult());
300 EXPECT_EQ(op->getWaitValues(DeviceType::Multicore).front(),
301 val1->getResult());
302
303 op->getWaitOperandsMutable().clear();
304 op->removeWaitOperandsDeviceTypeAttr();
305 op->removeWaitOperandsSegmentsAttr();
306
307 op->getWaitOperandsMutable().append(val3->getResult());
308 op->getWaitOperandsMutable().append(val2->getResult());
309 op->getWaitOperandsMutable().append(val1->getResult());
310 op->setWaitOperandsDeviceTypeAttr(
311 b.getArrayAttr({DeviceTypeAttr::get(&context, DeviceType::Multicore)}));
312 op->setHasWaitDevnumAttr(b.getBoolArrayAttr({true}));
313 op->setWaitOperandsSegments(b.getDenseI32ArrayAttr({3}));
314 EXPECT_EQ(op->getWaitValues(DeviceType::None).begin(),
315 op->getWaitValues(DeviceType::None).end());
316 EXPECT_FALSE(op->getWaitDevnum());
317
318 EXPECT_EQ(op->getWaitDevnum(DeviceType::Multicore), val3->getResult());
319 EXPECT_EQ(op->getWaitValues(DeviceType::Multicore).front(),
320 val2->getResult());
321 EXPECT_EQ(op->getWaitValues(DeviceType::Multicore).drop_front().front(),
322 val1->getResult());
323
324 op->getWaitOperandsMutable().clear();
325 op->removeWaitOperandsDeviceTypeAttr();
326 op->removeWaitOperandsSegmentsAttr();
327 op->removeHasWaitDevnumAttr();
328}
329
330TEST_F(OpenACCOpsTest, waitValuesTest) {
331 testWaitValues<KernelsOp>(b, context, loc, dtypes, dtypesWithoutNone);
332 testWaitValues<ParallelOp>(b, context, loc, dtypes, dtypesWithoutNone);
333 testWaitValues<SerialOp>(b, context, loc, dtypes, dtypesWithoutNone);
334}
335
336TEST_F(OpenACCOpsTest, loopOpGangVectorWorkerTest) {
337 OwningOpRef<LoopOp> op = b.create<LoopOp>(loc, TypeRange{}, ValueRange{});
338 EXPECT_FALSE(op->hasGang());
339 EXPECT_FALSE(op->hasVector());
340 EXPECT_FALSE(op->hasWorker());
341 for (auto d : dtypes) {
342 EXPECT_FALSE(op->hasGang(d));
343 EXPECT_FALSE(op->hasVector(d));
344 EXPECT_FALSE(op->hasWorker(d));
345 }
346
347 auto dtypeNone = DeviceTypeAttr::get(&context, DeviceType::None);
348 op->setGangAttr(b.getArrayAttr(value: {dtypeNone}));
349 EXPECT_TRUE(op->hasGang());
350 EXPECT_TRUE(op->hasGang(DeviceType::None));
351 for (auto d : dtypesWithoutNone)
352 EXPECT_FALSE(op->hasGang(d));
353 for (auto d : dtypes) {
354 EXPECT_FALSE(op->hasVector(d));
355 EXPECT_FALSE(op->hasWorker(d));
356 }
357 op->removeGangAttr();
358
359 op->setWorkerAttr(b.getArrayAttr(value: {dtypeNone}));
360 EXPECT_TRUE(op->hasWorker());
361 EXPECT_TRUE(op->hasWorker(DeviceType::None));
362 for (auto d : dtypesWithoutNone)
363 EXPECT_FALSE(op->hasWorker(d));
364 for (auto d : dtypes) {
365 EXPECT_FALSE(op->hasGang(d));
366 EXPECT_FALSE(op->hasVector(d));
367 }
368 op->removeWorkerAttr();
369
370 op->setVectorAttr(b.getArrayAttr(value: {dtypeNone}));
371 EXPECT_TRUE(op->hasVector());
372 EXPECT_TRUE(op->hasVector(DeviceType::None));
373 for (auto d : dtypesWithoutNone)
374 EXPECT_FALSE(op->hasVector(d));
375 for (auto d : dtypes) {
376 EXPECT_FALSE(op->hasGang(d));
377 EXPECT_FALSE(op->hasWorker(d));
378 }
379 op->removeVectorAttr();
380}
381
382TEST_F(OpenACCOpsTest, routineOpTest) {
383 OwningOpRef<RoutineOp> op =
384 b.create<RoutineOp>(loc, TypeRange{}, ValueRange{});
385
386 EXPECT_FALSE(op->hasSeq());
387 EXPECT_FALSE(op->hasVector());
388 EXPECT_FALSE(op->hasWorker());
389
390 for (auto d : dtypes) {
391 EXPECT_FALSE(op->hasSeq(d));
392 EXPECT_FALSE(op->hasVector(d));
393 EXPECT_FALSE(op->hasWorker(d));
394 }
395
396 auto dtypeNone = DeviceTypeAttr::get(&context, DeviceType::None);
397 op->setSeqAttr(b.getArrayAttr(value: {dtypeNone}));
398 EXPECT_TRUE(op->hasSeq());
399 for (auto d : dtypesWithoutNone)
400 EXPECT_FALSE(op->hasSeq(d));
401 op->removeSeqAttr();
402
403 op->setVectorAttr(b.getArrayAttr(value: {dtypeNone}));
404 EXPECT_TRUE(op->hasVector());
405 for (auto d : dtypesWithoutNone)
406 EXPECT_FALSE(op->hasVector(d));
407 op->removeVectorAttr();
408
409 op->setWorkerAttr(b.getArrayAttr(value: {dtypeNone}));
410 EXPECT_TRUE(op->hasWorker());
411 for (auto d : dtypesWithoutNone)
412 EXPECT_FALSE(op->hasWorker(d));
413 op->removeWorkerAttr();
414
415 op->setGangAttr(b.getArrayAttr(value: {dtypeNone}));
416 EXPECT_TRUE(op->hasGang());
417 for (auto d : dtypesWithoutNone)
418 EXPECT_FALSE(op->hasGang(d));
419 op->removeGangAttr();
420
421 op->setGangDimDeviceTypeAttr(b.getArrayAttr(value: {dtypeNone}));
422 op->setGangDimAttr(b.getArrayAttr({b.getIntegerAttr(b.getI64Type(), 8)}));
423 EXPECT_TRUE(op->getGangDimValue().has_value());
424 EXPECT_EQ(op->getGangDimValue().value(), 8);
425 for (auto d : dtypesWithoutNone)
426 EXPECT_FALSE(op->getGangDimValue(d).has_value());
427 op->removeGangDimDeviceTypeAttr();
428 op->removeGangDimAttr();
429
430 op->setBindNameDeviceTypeAttr(b.getArrayAttr(value: {dtypeNone}));
431 op->setBindNameAttr(b.getArrayAttr({b.getStringAttr("fname")}));
432 EXPECT_TRUE(op->getBindNameValue().has_value());
433 EXPECT_EQ(op->getBindNameValue().value(), "fname");
434 for (auto d : dtypesWithoutNone)
435 EXPECT_FALSE(op->getBindNameValue(d).has_value());
436 op->removeBindNameDeviceTypeAttr();
437 op->removeBindNameAttr();
438}
439

source code of mlir/unittests/Dialect/OpenACC/OpenACCOpsTest.cpp