xref: /llvm-project/mlir/unittests/Dialect/OpenACC/OpenACCOpsTest.cpp (revision f4aec22e4776218d2d94f5357e19897bc2e726d4)
1 //===- OpenACCOpsTest.cpp - Unit tests for OpenACC ops --------------------===//
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/MemRef/IR/MemRef.h"
11 #include "mlir/Dialect/OpenACC/OpenACC.h"
12 #include "mlir/IR/BuiltinTypes.h"
13 #include "mlir/IR/Diagnostics.h"
14 #include "mlir/IR/MLIRContext.h"
15 #include "mlir/IR/OwningOpRef.h"
16 #include "mlir/IR/Value.h"
17 #include "gtest/gtest.h"
18 
19 using namespace mlir;
20 using namespace mlir::acc;
21 
22 //===----------------------------------------------------------------------===//
23 // Test Fixture
24 //===----------------------------------------------------------------------===//
25 
26 class OpenACCOpsTest : public ::testing::Test {
27 protected:
28   OpenACCOpsTest() : b(&context), loc(UnknownLoc::get(&context)) {
29     context.loadDialect<acc::OpenACCDialect, arith::ArithDialect,
30                         memref::MemRefDialect>();
31   }
32 
33   MLIRContext context;
34   OpBuilder b;
35   Location loc;
36   llvm::SmallVector<DeviceType> dtypes = {
37       DeviceType::None,    DeviceType::Star, DeviceType::Multicore,
38       DeviceType::Default, DeviceType::Host, DeviceType::Nvidia,
39       DeviceType::Radeon};
40   llvm::SmallVector<DeviceType> dtypesWithoutNone = {
41       DeviceType::Star, DeviceType::Multicore, DeviceType::Default,
42       DeviceType::Host, DeviceType::Nvidia,    DeviceType::Radeon};
43 };
44 
45 template <typename Op>
46 void testAsyncOnly(OpBuilder &b, MLIRContext &context, Location loc,
47                    llvm::SmallVector<DeviceType> &dtypes) {
48   OwningOpRef<Op> op = b.create<Op>(loc, TypeRange{}, ValueRange{});
49   EXPECT_FALSE(op->hasAsyncOnly());
50   for (auto d : dtypes)
51     EXPECT_FALSE(op->hasAsyncOnly(d));
52 
53   auto dtypeNone = DeviceTypeAttr::get(&context, DeviceType::None);
54   op->setAsyncOnlyAttr(b.getArrayAttr({dtypeNone}));
55   EXPECT_TRUE(op->hasAsyncOnly());
56   EXPECT_TRUE(op->hasAsyncOnly(DeviceType::None));
57   op->removeAsyncOnlyAttr();
58 
59   auto dtypeHost = DeviceTypeAttr::get(&context, DeviceType::Host);
60   op->setAsyncOnlyAttr(b.getArrayAttr({dtypeHost}));
61   EXPECT_TRUE(op->hasAsyncOnly(DeviceType::Host));
62   EXPECT_FALSE(op->hasAsyncOnly());
63   op->removeAsyncOnlyAttr();
64 
65   auto dtypeStar = DeviceTypeAttr::get(&context, DeviceType::Star);
66   op->setAsyncOnlyAttr(b.getArrayAttr({dtypeHost, dtypeStar}));
67   EXPECT_TRUE(op->hasAsyncOnly(DeviceType::Star));
68   EXPECT_TRUE(op->hasAsyncOnly(DeviceType::Host));
69   EXPECT_FALSE(op->hasAsyncOnly());
70 
71   op->removeAsyncOnlyAttr();
72 }
73 
74 TEST_F(OpenACCOpsTest, asyncOnlyTest) {
75   testAsyncOnly<ParallelOp>(b, context, loc, dtypes);
76   testAsyncOnly<KernelsOp>(b, context, loc, dtypes);
77   testAsyncOnly<SerialOp>(b, context, loc, dtypes);
78 }
79 
80 template <typename Op>
81 void testAsyncOnlyDataEntry(OpBuilder &b, MLIRContext &context, Location loc,
82                             llvm::SmallVector<DeviceType> &dtypes) {
83   auto memrefTy = MemRefType::get({}, b.getI32Type());
84   OwningOpRef<memref::AllocaOp> varPtrOp =
85       b.create<memref::AllocaOp>(loc, memrefTy);
86 
87   TypedValue<PointerLikeType> varPtr =
88       cast<TypedValue<PointerLikeType>>(varPtrOp->getResult());
89   OwningOpRef<Op> op = b.create<Op>(loc, varPtr,
90                                     /*structured=*/true, /*implicit=*/true);
91 
92   EXPECT_FALSE(op->hasAsyncOnly());
93   for (auto d : dtypes)
94     EXPECT_FALSE(op->hasAsyncOnly(d));
95 
96   auto dtypeNone = DeviceTypeAttr::get(&context, DeviceType::None);
97   op->setAsyncOnlyAttr(b.getArrayAttr({dtypeNone}));
98   EXPECT_TRUE(op->hasAsyncOnly());
99   EXPECT_TRUE(op->hasAsyncOnly(DeviceType::None));
100   op->removeAsyncOnlyAttr();
101 
102   auto dtypeHost = DeviceTypeAttr::get(&context, DeviceType::Host);
103   op->setAsyncOnlyAttr(b.getArrayAttr({dtypeHost}));
104   EXPECT_TRUE(op->hasAsyncOnly(DeviceType::Host));
105   EXPECT_FALSE(op->hasAsyncOnly());
106   op->removeAsyncOnlyAttr();
107 
108   auto dtypeStar = DeviceTypeAttr::get(&context, DeviceType::Star);
109   op->setAsyncOnlyAttr(b.getArrayAttr({dtypeHost, dtypeStar}));
110   EXPECT_TRUE(op->hasAsyncOnly(DeviceType::Star));
111   EXPECT_TRUE(op->hasAsyncOnly(DeviceType::Host));
112   EXPECT_FALSE(op->hasAsyncOnly());
113 
114   op->removeAsyncOnlyAttr();
115 }
116 
117 TEST_F(OpenACCOpsTest, asyncOnlyTestDataEntry) {
118   testAsyncOnlyDataEntry<DevicePtrOp>(b, context, loc, dtypes);
119   testAsyncOnlyDataEntry<PresentOp>(b, context, loc, dtypes);
120   testAsyncOnlyDataEntry<CopyinOp>(b, context, loc, dtypes);
121   testAsyncOnlyDataEntry<CreateOp>(b, context, loc, dtypes);
122   testAsyncOnlyDataEntry<NoCreateOp>(b, context, loc, dtypes);
123   testAsyncOnlyDataEntry<AttachOp>(b, context, loc, dtypes);
124   testAsyncOnlyDataEntry<UpdateDeviceOp>(b, context, loc, dtypes);
125   testAsyncOnlyDataEntry<UseDeviceOp>(b, context, loc, dtypes);
126 }
127 
128 template <typename Op>
129 void testAsyncValue(OpBuilder &b, MLIRContext &context, Location loc,
130                     llvm::SmallVector<DeviceType> &dtypes) {
131   OwningOpRef<Op> op = b.create<Op>(loc, TypeRange{}, ValueRange{});
132 
133   mlir::Value empty;
134   EXPECT_EQ(op->getAsyncValue(), empty);
135   for (auto d : dtypes)
136     EXPECT_EQ(op->getAsyncValue(d), empty);
137 
138   OwningOpRef<arith::ConstantIndexOp> val =
139       b.create<arith::ConstantIndexOp>(loc, 1);
140   auto dtypeNvidia = DeviceTypeAttr::get(&context, DeviceType::Nvidia);
141   op->setAsyncOperandsDeviceTypeAttr(b.getArrayAttr({dtypeNvidia}));
142   op->getAsyncOperandsMutable().assign(val->getResult());
143   EXPECT_EQ(op->getAsyncValue(), empty);
144   EXPECT_EQ(op->getAsyncValue(DeviceType::Nvidia), val->getResult());
145 
146   op->getAsyncOperandsMutable().clear();
147   op->removeAsyncOperandsDeviceTypeAttr();
148 }
149 
150 TEST_F(OpenACCOpsTest, asyncValueTest) {
151   testAsyncValue<ParallelOp>(b, context, loc, dtypes);
152   testAsyncValue<KernelsOp>(b, context, loc, dtypes);
153   testAsyncValue<SerialOp>(b, context, loc, dtypes);
154 }
155 
156 template <typename Op>
157 void testAsyncValueDataEntry(OpBuilder &b, MLIRContext &context, Location loc,
158                              llvm::SmallVector<DeviceType> &dtypes) {
159   auto memrefTy = MemRefType::get({}, b.getI32Type());
160   OwningOpRef<memref::AllocaOp> varPtrOp =
161       b.create<memref::AllocaOp>(loc, memrefTy);
162 
163   TypedValue<PointerLikeType> varPtr =
164       cast<TypedValue<PointerLikeType>>(varPtrOp->getResult());
165   OwningOpRef<Op> op = b.create<Op>(loc, varPtr,
166                                     /*structured=*/true, /*implicit=*/true);
167 
168   mlir::Value empty;
169   EXPECT_EQ(op->getAsyncValue(), empty);
170   for (auto d : dtypes)
171     EXPECT_EQ(op->getAsyncValue(d), empty);
172 
173   OwningOpRef<arith::ConstantIndexOp> val =
174       b.create<arith::ConstantIndexOp>(loc, 1);
175   auto dtypeNvidia = DeviceTypeAttr::get(&context, DeviceType::Nvidia);
176   op->setAsyncOperandsDeviceTypeAttr(b.getArrayAttr({dtypeNvidia}));
177   op->getAsyncOperandsMutable().assign(val->getResult());
178   EXPECT_EQ(op->getAsyncValue(), empty);
179   EXPECT_EQ(op->getAsyncValue(DeviceType::Nvidia), val->getResult());
180 
181   op->getAsyncOperandsMutable().clear();
182   op->removeAsyncOperandsDeviceTypeAttr();
183 }
184 
185 TEST_F(OpenACCOpsTest, asyncValueTestDataEntry) {
186   testAsyncValueDataEntry<DevicePtrOp>(b, context, loc, dtypes);
187   testAsyncValueDataEntry<PresentOp>(b, context, loc, dtypes);
188   testAsyncValueDataEntry<CopyinOp>(b, context, loc, dtypes);
189   testAsyncValueDataEntry<CreateOp>(b, context, loc, dtypes);
190   testAsyncValueDataEntry<NoCreateOp>(b, context, loc, dtypes);
191   testAsyncValueDataEntry<AttachOp>(b, context, loc, dtypes);
192   testAsyncValueDataEntry<UpdateDeviceOp>(b, context, loc, dtypes);
193   testAsyncValueDataEntry<UseDeviceOp>(b, context, loc, dtypes);
194 }
195 
196 template <typename Op>
197 void testNumGangsValues(OpBuilder &b, MLIRContext &context, Location loc,
198                         llvm::SmallVector<DeviceType> &dtypes,
199                         llvm::SmallVector<DeviceType> &dtypesWithoutNone) {
200   OwningOpRef<Op> op = b.create<Op>(loc, TypeRange{}, ValueRange{});
201   EXPECT_EQ(op->getNumGangsValues().begin(), op->getNumGangsValues().end());
202 
203   OwningOpRef<arith::ConstantIndexOp> val1 =
204       b.create<arith::ConstantIndexOp>(loc, 1);
205   OwningOpRef<arith::ConstantIndexOp> val2 =
206       b.create<arith::ConstantIndexOp>(loc, 4);
207   auto dtypeNone = DeviceTypeAttr::get(&context, DeviceType::None);
208   op->getNumGangsMutable().assign(val1->getResult());
209   op->setNumGangsDeviceTypeAttr(b.getArrayAttr({dtypeNone}));
210   op->setNumGangsSegments(b.getDenseI32ArrayAttr({1}));
211   EXPECT_EQ(op->getNumGangsValues().front(), val1->getResult());
212   for (auto d : dtypesWithoutNone)
213     EXPECT_EQ(op->getNumGangsValues(d).begin(), op->getNumGangsValues(d).end());
214 
215   op->getNumGangsMutable().clear();
216   op->removeNumGangsDeviceTypeAttr();
217   op->removeNumGangsSegmentsAttr();
218   for (auto d : dtypes)
219     EXPECT_EQ(op->getNumGangsValues(d).begin(), op->getNumGangsValues(d).end());
220 
221   op->getNumGangsMutable().append(val1->getResult());
222   op->getNumGangsMutable().append(val2->getResult());
223   op->setNumGangsDeviceTypeAttr(
224       b.getArrayAttr({DeviceTypeAttr::get(&context, DeviceType::Host),
225                       DeviceTypeAttr::get(&context, DeviceType::Star)}));
226   op->setNumGangsSegments(b.getDenseI32ArrayAttr({1, 1}));
227   EXPECT_EQ(op->getNumGangsValues(DeviceType::None).begin(),
228             op->getNumGangsValues(DeviceType::None).end());
229   EXPECT_EQ(op->getNumGangsValues(DeviceType::Host).front(), val1->getResult());
230   EXPECT_EQ(op->getNumGangsValues(DeviceType::Star).front(), val2->getResult());
231 
232   op->getNumGangsMutable().clear();
233   op->removeNumGangsDeviceTypeAttr();
234   op->removeNumGangsSegmentsAttr();
235   for (auto d : dtypes)
236     EXPECT_EQ(op->getNumGangsValues(d).begin(), op->getNumGangsValues(d).end());
237 
238   op->getNumGangsMutable().append(val1->getResult());
239   op->getNumGangsMutable().append(val2->getResult());
240   op->getNumGangsMutable().append(val1->getResult());
241   op->setNumGangsDeviceTypeAttr(
242       b.getArrayAttr({DeviceTypeAttr::get(&context, DeviceType::Default),
243                       DeviceTypeAttr::get(&context, DeviceType::Multicore)}));
244   op->setNumGangsSegments(b.getDenseI32ArrayAttr({2, 1}));
245   EXPECT_EQ(op->getNumGangsValues(DeviceType::None).begin(),
246             op->getNumGangsValues(DeviceType::None).end());
247   EXPECT_EQ(op->getNumGangsValues(DeviceType::Default).front(),
248             val1->getResult());
249   EXPECT_EQ(op->getNumGangsValues(DeviceType::Default).drop_front().front(),
250             val2->getResult());
251   EXPECT_EQ(op->getNumGangsValues(DeviceType::Multicore).front(),
252             val1->getResult());
253 
254   op->getNumGangsMutable().clear();
255   op->removeNumGangsDeviceTypeAttr();
256   op->removeNumGangsSegmentsAttr();
257 }
258 
259 TEST_F(OpenACCOpsTest, numGangsValuesTest) {
260   testNumGangsValues<ParallelOp>(b, context, loc, dtypes, dtypesWithoutNone);
261   testNumGangsValues<KernelsOp>(b, context, loc, dtypes, dtypesWithoutNone);
262 }
263 
264 template <typename Op>
265 void testVectorLength(OpBuilder &b, MLIRContext &context, Location loc,
266                       llvm::SmallVector<DeviceType> &dtypes) {
267   OwningOpRef<Op> op = b.create<Op>(loc, TypeRange{}, ValueRange{});
268 
269   mlir::Value empty;
270   EXPECT_EQ(op->getVectorLengthValue(), empty);
271   for (auto d : dtypes)
272     EXPECT_EQ(op->getVectorLengthValue(d), empty);
273 
274   OwningOpRef<arith::ConstantIndexOp> val =
275       b.create<arith::ConstantIndexOp>(loc, 1);
276   auto dtypeNvidia = DeviceTypeAttr::get(&context, DeviceType::Nvidia);
277   op->setVectorLengthDeviceTypeAttr(b.getArrayAttr({dtypeNvidia}));
278   op->getVectorLengthMutable().assign(val->getResult());
279   EXPECT_EQ(op->getVectorLengthValue(), empty);
280   EXPECT_EQ(op->getVectorLengthValue(DeviceType::Nvidia), val->getResult());
281 
282   op->getVectorLengthMutable().clear();
283   op->removeVectorLengthDeviceTypeAttr();
284 }
285 
286 TEST_F(OpenACCOpsTest, vectorLengthTest) {
287   testVectorLength<ParallelOp>(b, context, loc, dtypes);
288   testVectorLength<KernelsOp>(b, context, loc, dtypes);
289 }
290 
291 template <typename Op>
292 void testWaitOnly(OpBuilder &b, MLIRContext &context, Location loc,
293                   llvm::SmallVector<DeviceType> &dtypes,
294                   llvm::SmallVector<DeviceType> &dtypesWithoutNone) {
295   OwningOpRef<Op> op = b.create<Op>(loc, TypeRange{}, ValueRange{});
296   EXPECT_FALSE(op->hasWaitOnly());
297   for (auto d : dtypes)
298     EXPECT_FALSE(op->hasWaitOnly(d));
299 
300   auto dtypeNone = DeviceTypeAttr::get(&context, DeviceType::None);
301   op->setWaitOnlyAttr(b.getArrayAttr({dtypeNone}));
302   EXPECT_TRUE(op->hasWaitOnly());
303   EXPECT_TRUE(op->hasWaitOnly(DeviceType::None));
304   for (auto d : dtypesWithoutNone)
305     EXPECT_FALSE(op->hasWaitOnly(d));
306   op->removeWaitOnlyAttr();
307 
308   auto dtypeHost = DeviceTypeAttr::get(&context, DeviceType::Host);
309   op->setWaitOnlyAttr(b.getArrayAttr({dtypeHost}));
310   EXPECT_TRUE(op->hasWaitOnly(DeviceType::Host));
311   EXPECT_FALSE(op->hasWaitOnly());
312   op->removeWaitOnlyAttr();
313 
314   auto dtypeStar = DeviceTypeAttr::get(&context, DeviceType::Star);
315   op->setWaitOnlyAttr(b.getArrayAttr({dtypeHost, dtypeStar}));
316   EXPECT_TRUE(op->hasWaitOnly(DeviceType::Star));
317   EXPECT_TRUE(op->hasWaitOnly(DeviceType::Host));
318   EXPECT_FALSE(op->hasWaitOnly());
319 
320   op->removeWaitOnlyAttr();
321 }
322 
323 TEST_F(OpenACCOpsTest, waitOnlyTest) {
324   testWaitOnly<ParallelOp>(b, context, loc, dtypes, dtypesWithoutNone);
325   testWaitOnly<KernelsOp>(b, context, loc, dtypes, dtypesWithoutNone);
326   testWaitOnly<SerialOp>(b, context, loc, dtypes, dtypesWithoutNone);
327   testWaitOnly<UpdateOp>(b, context, loc, dtypes, dtypesWithoutNone);
328   testWaitOnly<DataOp>(b, context, loc, dtypes, dtypesWithoutNone);
329 }
330 
331 template <typename Op>
332 void testWaitValues(OpBuilder &b, MLIRContext &context, Location loc,
333                     llvm::SmallVector<DeviceType> &dtypes,
334                     llvm::SmallVector<DeviceType> &dtypesWithoutNone) {
335   OwningOpRef<Op> op = b.create<Op>(loc, TypeRange{}, ValueRange{});
336   EXPECT_EQ(op->getWaitValues().begin(), op->getWaitValues().end());
337 
338   OwningOpRef<arith::ConstantIndexOp> val1 =
339       b.create<arith::ConstantIndexOp>(loc, 1);
340   OwningOpRef<arith::ConstantIndexOp> val2 =
341       b.create<arith::ConstantIndexOp>(loc, 4);
342   OwningOpRef<arith::ConstantIndexOp> val3 =
343       b.create<arith::ConstantIndexOp>(loc, 5);
344   auto dtypeNone = DeviceTypeAttr::get(&context, DeviceType::None);
345   op->getWaitOperandsMutable().assign(val1->getResult());
346   op->setWaitOperandsDeviceTypeAttr(b.getArrayAttr({dtypeNone}));
347   op->setWaitOperandsSegments(b.getDenseI32ArrayAttr({1}));
348   op->setHasWaitDevnumAttr(b.getBoolArrayAttr({false}));
349   EXPECT_EQ(op->getWaitValues().front(), val1->getResult());
350   for (auto d : dtypesWithoutNone)
351     EXPECT_TRUE(op->getWaitValues(d).empty());
352 
353   op->getWaitOperandsMutable().clear();
354   op->removeWaitOperandsDeviceTypeAttr();
355   op->removeWaitOperandsSegmentsAttr();
356   op->removeHasWaitDevnumAttr();
357   for (auto d : dtypes)
358     EXPECT_TRUE(op->getWaitValues(d).empty());
359 
360   op->getWaitOperandsMutable().append(val1->getResult());
361   op->getWaitOperandsMutable().append(val2->getResult());
362   op->setWaitOperandsDeviceTypeAttr(
363       b.getArrayAttr({DeviceTypeAttr::get(&context, DeviceType::Host),
364                       DeviceTypeAttr::get(&context, DeviceType::Star)}));
365   op->setWaitOperandsSegments(b.getDenseI32ArrayAttr({1, 1}));
366   op->setHasWaitDevnumAttr(b.getBoolArrayAttr({false, false}));
367   EXPECT_EQ(op->getWaitValues(DeviceType::None).begin(),
368             op->getWaitValues(DeviceType::None).end());
369   EXPECT_EQ(op->getWaitValues(DeviceType::Host).front(), val1->getResult());
370   EXPECT_EQ(op->getWaitValues(DeviceType::Star).front(), val2->getResult());
371 
372   op->getWaitOperandsMutable().clear();
373   op->removeWaitOperandsDeviceTypeAttr();
374   op->removeWaitOperandsSegmentsAttr();
375   op->removeHasWaitDevnumAttr();
376   for (auto d : dtypes)
377     EXPECT_TRUE(op->getWaitValues(d).empty());
378 
379   op->getWaitOperandsMutable().append(val1->getResult());
380   op->getWaitOperandsMutable().append(val2->getResult());
381   op->getWaitOperandsMutable().append(val1->getResult());
382   op->setWaitOperandsDeviceTypeAttr(
383       b.getArrayAttr({DeviceTypeAttr::get(&context, DeviceType::Default),
384                       DeviceTypeAttr::get(&context, DeviceType::Multicore)}));
385   op->setWaitOperandsSegments(b.getDenseI32ArrayAttr({2, 1}));
386   op->setHasWaitDevnumAttr(b.getBoolArrayAttr({false, false}));
387   EXPECT_EQ(op->getWaitValues(DeviceType::None).begin(),
388             op->getWaitValues(DeviceType::None).end());
389   EXPECT_EQ(op->getWaitValues(DeviceType::Default).front(), val1->getResult());
390   EXPECT_EQ(op->getWaitValues(DeviceType::Default).drop_front().front(),
391             val2->getResult());
392   EXPECT_EQ(op->getWaitValues(DeviceType::Multicore).front(),
393             val1->getResult());
394 
395   op->getWaitOperandsMutable().clear();
396   op->removeWaitOperandsDeviceTypeAttr();
397   op->removeWaitOperandsSegmentsAttr();
398 
399   op->getWaitOperandsMutable().append(val3->getResult());
400   op->getWaitOperandsMutable().append(val2->getResult());
401   op->getWaitOperandsMutable().append(val1->getResult());
402   op->setWaitOperandsDeviceTypeAttr(
403       b.getArrayAttr({DeviceTypeAttr::get(&context, DeviceType::Multicore)}));
404   op->setHasWaitDevnumAttr(b.getBoolArrayAttr({true}));
405   op->setWaitOperandsSegments(b.getDenseI32ArrayAttr({3}));
406   EXPECT_EQ(op->getWaitValues(DeviceType::None).begin(),
407             op->getWaitValues(DeviceType::None).end());
408   EXPECT_FALSE(op->getWaitDevnum());
409 
410   EXPECT_EQ(op->getWaitDevnum(DeviceType::Multicore), val3->getResult());
411   EXPECT_EQ(op->getWaitValues(DeviceType::Multicore).front(),
412             val2->getResult());
413   EXPECT_EQ(op->getWaitValues(DeviceType::Multicore).drop_front().front(),
414             val1->getResult());
415 
416   op->getWaitOperandsMutable().clear();
417   op->removeWaitOperandsDeviceTypeAttr();
418   op->removeWaitOperandsSegmentsAttr();
419   op->removeHasWaitDevnumAttr();
420 }
421 
422 TEST_F(OpenACCOpsTest, waitValuesTest) {
423   testWaitValues<KernelsOp>(b, context, loc, dtypes, dtypesWithoutNone);
424   testWaitValues<ParallelOp>(b, context, loc, dtypes, dtypesWithoutNone);
425   testWaitValues<SerialOp>(b, context, loc, dtypes, dtypesWithoutNone);
426 }
427 
428 TEST_F(OpenACCOpsTest, loopOpGangVectorWorkerTest) {
429   OwningOpRef<LoopOp> op = b.create<LoopOp>(loc, TypeRange{}, ValueRange{});
430   EXPECT_FALSE(op->hasGang());
431   EXPECT_FALSE(op->hasVector());
432   EXPECT_FALSE(op->hasWorker());
433   for (auto d : dtypes) {
434     EXPECT_FALSE(op->hasGang(d));
435     EXPECT_FALSE(op->hasVector(d));
436     EXPECT_FALSE(op->hasWorker(d));
437   }
438 
439   auto dtypeNone = DeviceTypeAttr::get(&context, DeviceType::None);
440   op->setGangAttr(b.getArrayAttr({dtypeNone}));
441   EXPECT_TRUE(op->hasGang());
442   EXPECT_TRUE(op->hasGang(DeviceType::None));
443   for (auto d : dtypesWithoutNone)
444     EXPECT_FALSE(op->hasGang(d));
445   for (auto d : dtypes) {
446     EXPECT_FALSE(op->hasVector(d));
447     EXPECT_FALSE(op->hasWorker(d));
448   }
449   op->removeGangAttr();
450 
451   op->setWorkerAttr(b.getArrayAttr({dtypeNone}));
452   EXPECT_TRUE(op->hasWorker());
453   EXPECT_TRUE(op->hasWorker(DeviceType::None));
454   for (auto d : dtypesWithoutNone)
455     EXPECT_FALSE(op->hasWorker(d));
456   for (auto d : dtypes) {
457     EXPECT_FALSE(op->hasGang(d));
458     EXPECT_FALSE(op->hasVector(d));
459   }
460   op->removeWorkerAttr();
461 
462   op->setVectorAttr(b.getArrayAttr({dtypeNone}));
463   EXPECT_TRUE(op->hasVector());
464   EXPECT_TRUE(op->hasVector(DeviceType::None));
465   for (auto d : dtypesWithoutNone)
466     EXPECT_FALSE(op->hasVector(d));
467   for (auto d : dtypes) {
468     EXPECT_FALSE(op->hasGang(d));
469     EXPECT_FALSE(op->hasWorker(d));
470   }
471   op->removeVectorAttr();
472 }
473 
474 TEST_F(OpenACCOpsTest, routineOpTest) {
475   OwningOpRef<RoutineOp> op =
476       b.create<RoutineOp>(loc, TypeRange{}, ValueRange{});
477 
478   EXPECT_FALSE(op->hasSeq());
479   EXPECT_FALSE(op->hasVector());
480   EXPECT_FALSE(op->hasWorker());
481 
482   for (auto d : dtypes) {
483     EXPECT_FALSE(op->hasSeq(d));
484     EXPECT_FALSE(op->hasVector(d));
485     EXPECT_FALSE(op->hasWorker(d));
486   }
487 
488   auto dtypeNone = DeviceTypeAttr::get(&context, DeviceType::None);
489   op->setSeqAttr(b.getArrayAttr({dtypeNone}));
490   EXPECT_TRUE(op->hasSeq());
491   for (auto d : dtypesWithoutNone)
492     EXPECT_FALSE(op->hasSeq(d));
493   op->removeSeqAttr();
494 
495   op->setVectorAttr(b.getArrayAttr({dtypeNone}));
496   EXPECT_TRUE(op->hasVector());
497   for (auto d : dtypesWithoutNone)
498     EXPECT_FALSE(op->hasVector(d));
499   op->removeVectorAttr();
500 
501   op->setWorkerAttr(b.getArrayAttr({dtypeNone}));
502   EXPECT_TRUE(op->hasWorker());
503   for (auto d : dtypesWithoutNone)
504     EXPECT_FALSE(op->hasWorker(d));
505   op->removeWorkerAttr();
506 
507   op->setGangAttr(b.getArrayAttr({dtypeNone}));
508   EXPECT_TRUE(op->hasGang());
509   for (auto d : dtypesWithoutNone)
510     EXPECT_FALSE(op->hasGang(d));
511   op->removeGangAttr();
512 
513   op->setGangDimDeviceTypeAttr(b.getArrayAttr({dtypeNone}));
514   op->setGangDimAttr(b.getArrayAttr({b.getIntegerAttr(b.getI64Type(), 8)}));
515   EXPECT_TRUE(op->getGangDimValue().has_value());
516   EXPECT_EQ(op->getGangDimValue().value(), 8);
517   for (auto d : dtypesWithoutNone)
518     EXPECT_FALSE(op->getGangDimValue(d).has_value());
519   op->removeGangDimDeviceTypeAttr();
520   op->removeGangDimAttr();
521 
522   op->setBindNameDeviceTypeAttr(b.getArrayAttr({dtypeNone}));
523   op->setBindNameAttr(b.getArrayAttr({b.getStringAttr("fname")}));
524   EXPECT_TRUE(op->getBindNameValue().has_value());
525   EXPECT_EQ(op->getBindNameValue().value(), "fname");
526   for (auto d : dtypesWithoutNone)
527     EXPECT_FALSE(op->getBindNameValue(d).has_value());
528   op->removeBindNameDeviceTypeAttr();
529   op->removeBindNameAttr();
530 }
531 
532 template <typename Op>
533 void testShortDataEntryOpBuilders(OpBuilder &b, MLIRContext &context,
534                                   Location loc, DataClause dataClause) {
535   auto memrefTy = MemRefType::get({}, b.getI32Type());
536   OwningOpRef<memref::AllocaOp> varPtrOp =
537       b.create<memref::AllocaOp>(loc, memrefTy);
538 
539   TypedValue<PointerLikeType> varPtr =
540       cast<TypedValue<PointerLikeType>>(varPtrOp->getResult());
541   OwningOpRef<Op> op = b.create<Op>(loc, varPtr,
542                                     /*structured=*/true, /*implicit=*/true);
543 
544   EXPECT_EQ(op->getVarPtr(), varPtr);
545   EXPECT_EQ(op->getType(), memrefTy);
546   EXPECT_EQ(op->getDataClause(), dataClause);
547   EXPECT_TRUE(op->getImplicit());
548   EXPECT_TRUE(op->getStructured());
549   EXPECT_TRUE(op->getBounds().empty());
550   EXPECT_FALSE(op->getVarPtrPtr());
551 
552   OwningOpRef<Op> op2 = b.create<Op>(loc, varPtr,
553                                      /*structured=*/false, /*implicit=*/false);
554   EXPECT_FALSE(op2->getImplicit());
555   EXPECT_FALSE(op2->getStructured());
556 
557   OwningOpRef<arith::ConstantIndexOp> extent =
558       b.create<arith::ConstantIndexOp>(loc, 1);
559   OwningOpRef<DataBoundsOp> bounds =
560       b.create<DataBoundsOp>(loc, extent->getResult());
561   OwningOpRef<Op> opWithBounds =
562       b.create<Op>(loc, varPtr,
563                    /*structured=*/true, /*implicit=*/true, bounds->getResult());
564   EXPECT_FALSE(opWithBounds->getBounds().empty());
565   EXPECT_EQ(opWithBounds->getBounds().back(), bounds->getResult());
566 
567   OwningOpRef<Op> opWithName =
568       b.create<Op>(loc, varPtr,
569                    /*structured=*/true, /*implicit=*/true, "varName");
570   EXPECT_EQ(opWithName->getNameAttr().str(), "varName");
571 }
572 
573 TEST_F(OpenACCOpsTest, shortDataEntryOpBuilder) {
574   testShortDataEntryOpBuilders<PrivateOp>(b, context, loc,
575                                           DataClause::acc_private);
576   testShortDataEntryOpBuilders<FirstprivateOp>(b, context, loc,
577                                                DataClause::acc_firstprivate);
578   testShortDataEntryOpBuilders<ReductionOp>(b, context, loc,
579                                             DataClause::acc_reduction);
580   testShortDataEntryOpBuilders<DevicePtrOp>(b, context, loc,
581                                             DataClause::acc_deviceptr);
582   testShortDataEntryOpBuilders<PresentOp>(b, context, loc,
583                                           DataClause::acc_present);
584   testShortDataEntryOpBuilders<CopyinOp>(b, context, loc,
585                                          DataClause::acc_copyin);
586   testShortDataEntryOpBuilders<CreateOp>(b, context, loc,
587                                          DataClause::acc_create);
588   testShortDataEntryOpBuilders<NoCreateOp>(b, context, loc,
589                                            DataClause::acc_no_create);
590   testShortDataEntryOpBuilders<AttachOp>(b, context, loc,
591                                          DataClause::acc_attach);
592   testShortDataEntryOpBuilders<GetDevicePtrOp>(b, context, loc,
593                                                DataClause::acc_getdeviceptr);
594   testShortDataEntryOpBuilders<UpdateDeviceOp>(b, context, loc,
595                                                DataClause::acc_update_device);
596   testShortDataEntryOpBuilders<UseDeviceOp>(b, context, loc,
597                                             DataClause::acc_use_device);
598   testShortDataEntryOpBuilders<DeclareDeviceResidentOp>(
599       b, context, loc, DataClause::acc_declare_device_resident);
600   testShortDataEntryOpBuilders<DeclareLinkOp>(b, context, loc,
601                                               DataClause::acc_declare_link);
602   testShortDataEntryOpBuilders<CacheOp>(b, context, loc, DataClause::acc_cache);
603 }
604 
605 template <typename Op>
606 void testShortDataExitOpBuilders(OpBuilder &b, MLIRContext &context,
607                                  Location loc, DataClause dataClause) {
608   auto memrefTy = MemRefType::get({}, b.getI32Type());
609   OwningOpRef<memref::AllocaOp> varPtrOp =
610       b.create<memref::AllocaOp>(loc, memrefTy);
611   TypedValue<PointerLikeType> varPtr =
612       cast<TypedValue<PointerLikeType>>(varPtrOp->getResult());
613 
614   OwningOpRef<GetDevicePtrOp> accPtrOp = b.create<GetDevicePtrOp>(
615       loc, varPtr, /*structured=*/true, /*implicit=*/true);
616   TypedValue<PointerLikeType> accPtr =
617       cast<TypedValue<PointerLikeType>>(accPtrOp->getResult());
618 
619   OwningOpRef<Op> op = b.create<Op>(loc, accPtr, varPtr,
620                                     /*structured=*/true, /*implicit=*/true);
621 
622   EXPECT_EQ(op->getVarPtr(), varPtr);
623   EXPECT_EQ(op->getAccPtr(), accPtr);
624   EXPECT_EQ(op->getDataClause(), dataClause);
625   EXPECT_TRUE(op->getImplicit());
626   EXPECT_TRUE(op->getStructured());
627   EXPECT_TRUE(op->getBounds().empty());
628 
629   OwningOpRef<Op> op2 = b.create<Op>(loc, accPtr, varPtr,
630                                      /*structured=*/false, /*implicit=*/false);
631   EXPECT_FALSE(op2->getImplicit());
632   EXPECT_FALSE(op2->getStructured());
633 
634   OwningOpRef<arith::ConstantIndexOp> extent =
635       b.create<arith::ConstantIndexOp>(loc, 1);
636   OwningOpRef<DataBoundsOp> bounds =
637       b.create<DataBoundsOp>(loc, extent->getResult());
638   OwningOpRef<Op> opWithBounds =
639       b.create<Op>(loc, accPtr, varPtr,
640                    /*structured=*/true, /*implicit=*/true, bounds->getResult());
641   EXPECT_FALSE(opWithBounds->getBounds().empty());
642   EXPECT_EQ(opWithBounds->getBounds().back(), bounds->getResult());
643 
644   OwningOpRef<Op> opWithName =
645       b.create<Op>(loc, accPtr, varPtr,
646                    /*structured=*/true, /*implicit=*/true, "varName");
647   EXPECT_EQ(opWithName->getNameAttr().str(), "varName");
648 }
649 
650 TEST_F(OpenACCOpsTest, shortDataExitOpBuilder) {
651   testShortDataExitOpBuilders<CopyoutOp>(b, context, loc,
652                                          DataClause::acc_copyout);
653   testShortDataExitOpBuilders<UpdateHostOp>(b, context, loc,
654                                             DataClause::acc_update_host);
655 }
656 
657 template <typename Op>
658 void testShortDataExitNoVarPtrOpBuilders(OpBuilder &b, MLIRContext &context,
659                                          Location loc, DataClause dataClause) {
660   auto memrefTy = MemRefType::get({}, b.getI32Type());
661   OwningOpRef<memref::AllocaOp> varPtrOp =
662       b.create<memref::AllocaOp>(loc, memrefTy);
663   TypedValue<PointerLikeType> varPtr =
664       cast<TypedValue<PointerLikeType>>(varPtrOp->getResult());
665 
666   OwningOpRef<GetDevicePtrOp> accPtrOp = b.create<GetDevicePtrOp>(
667       loc, varPtr, /*structured=*/true, /*implicit=*/true);
668   TypedValue<PointerLikeType> accPtr =
669       cast<TypedValue<PointerLikeType>>(accPtrOp->getResult());
670 
671   OwningOpRef<Op> op = b.create<Op>(loc, accPtr,
672                                     /*structured=*/true, /*implicit=*/true);
673 
674   EXPECT_EQ(op->getAccPtr(), accPtr);
675   EXPECT_EQ(op->getDataClause(), dataClause);
676   EXPECT_TRUE(op->getImplicit());
677   EXPECT_TRUE(op->getStructured());
678   EXPECT_TRUE(op->getBounds().empty());
679 
680   OwningOpRef<Op> op2 = b.create<Op>(loc, accPtr,
681                                      /*structured=*/false, /*implicit=*/false);
682   EXPECT_FALSE(op2->getImplicit());
683   EXPECT_FALSE(op2->getStructured());
684 
685   OwningOpRef<arith::ConstantIndexOp> extent =
686       b.create<arith::ConstantIndexOp>(loc, 1);
687   OwningOpRef<DataBoundsOp> bounds =
688       b.create<DataBoundsOp>(loc, extent->getResult());
689   OwningOpRef<Op> opWithBounds =
690       b.create<Op>(loc, accPtr,
691                    /*structured=*/true, /*implicit=*/true, bounds->getResult());
692   EXPECT_FALSE(opWithBounds->getBounds().empty());
693   EXPECT_EQ(opWithBounds->getBounds().back(), bounds->getResult());
694 
695   OwningOpRef<Op> opWithName =
696       b.create<Op>(loc, accPtr,
697                    /*structured=*/true, /*implicit=*/true, "varName");
698   EXPECT_EQ(opWithName->getNameAttr().str(), "varName");
699 }
700 
701 TEST_F(OpenACCOpsTest, shortDataExitOpNoVarPtrBuilder) {
702   testShortDataExitNoVarPtrOpBuilders<DeleteOp>(b, context, loc,
703                                                 DataClause::acc_delete);
704   testShortDataExitNoVarPtrOpBuilders<DetachOp>(b, context, loc,
705                                                 DataClause::acc_detach);
706 }
707 
708 template <typename Op>
709 void testShortDataEntryOpBuildersMappableVar(OpBuilder &b, MLIRContext &context,
710                                              Location loc,
711                                              DataClause dataClause) {
712   auto int64Ty = b.getI64Type();
713   auto memrefTy = MemRefType::get({}, int64Ty);
714   OwningOpRef<memref::AllocaOp> varPtrOp =
715       b.create<memref::AllocaOp>(loc, memrefTy);
716   SmallVector<Value> indices;
717   OwningOpRef<memref::LoadOp> loadVarOp =
718       b.create<memref::LoadOp>(loc, int64Ty, varPtrOp->getResult(), indices);
719 
720   EXPECT_TRUE(isMappableType(loadVarOp->getResult().getType()));
721   TypedValue<MappableType> var =
722       cast<TypedValue<MappableType>>(loadVarOp->getResult());
723   OwningOpRef<Op> op = b.create<Op>(loc, var,
724                                     /*structured=*/true, /*implicit=*/true);
725 
726   EXPECT_EQ(op->getVar(), var);
727   EXPECT_EQ(op->getVarPtr(), nullptr);
728   EXPECT_EQ(op->getType(), int64Ty);
729   EXPECT_EQ(op->getVarType(), int64Ty);
730   EXPECT_EQ(op->getDataClause(), dataClause);
731   EXPECT_TRUE(op->getImplicit());
732   EXPECT_TRUE(op->getStructured());
733   EXPECT_TRUE(op->getBounds().empty());
734   EXPECT_FALSE(op->getVarPtrPtr());
735 }
736 
737 struct IntegerOpenACCMappableModel
738     : public mlir::acc::MappableType::ExternalModel<IntegerOpenACCMappableModel,
739                                                     IntegerType> {};
740 
741 TEST_F(OpenACCOpsTest, mappableTypeBuilderDataEntry) {
742   // First, set up the test by attaching MappableInterface to IntegerType.
743   IntegerType i64ty = IntegerType::get(&context, 8);
744   ASSERT_FALSE(isMappableType(i64ty));
745   IntegerType::attachInterface<IntegerOpenACCMappableModel>(context);
746   ASSERT_TRUE(isMappableType(i64ty));
747 
748   testShortDataEntryOpBuildersMappableVar<PrivateOp>(b, context, loc,
749                                                      DataClause::acc_private);
750   testShortDataEntryOpBuildersMappableVar<FirstprivateOp>(
751       b, context, loc, DataClause::acc_firstprivate);
752   testShortDataEntryOpBuildersMappableVar<ReductionOp>(
753       b, context, loc, DataClause::acc_reduction);
754   testShortDataEntryOpBuildersMappableVar<DevicePtrOp>(
755       b, context, loc, DataClause::acc_deviceptr);
756   testShortDataEntryOpBuildersMappableVar<PresentOp>(b, context, loc,
757                                                      DataClause::acc_present);
758   testShortDataEntryOpBuildersMappableVar<CopyinOp>(b, context, loc,
759                                                     DataClause::acc_copyin);
760   testShortDataEntryOpBuildersMappableVar<CreateOp>(b, context, loc,
761                                                     DataClause::acc_create);
762   testShortDataEntryOpBuildersMappableVar<NoCreateOp>(
763       b, context, loc, DataClause::acc_no_create);
764   testShortDataEntryOpBuildersMappableVar<AttachOp>(b, context, loc,
765                                                     DataClause::acc_attach);
766   testShortDataEntryOpBuildersMappableVar<GetDevicePtrOp>(
767       b, context, loc, DataClause::acc_getdeviceptr);
768   testShortDataEntryOpBuildersMappableVar<UpdateDeviceOp>(
769       b, context, loc, DataClause::acc_update_device);
770   testShortDataEntryOpBuildersMappableVar<UseDeviceOp>(
771       b, context, loc, DataClause::acc_use_device);
772   testShortDataEntryOpBuildersMappableVar<DeclareDeviceResidentOp>(
773       b, context, loc, DataClause::acc_declare_device_resident);
774   testShortDataEntryOpBuildersMappableVar<DeclareLinkOp>(
775       b, context, loc, DataClause::acc_declare_link);
776   testShortDataEntryOpBuildersMappableVar<CacheOp>(b, context, loc,
777                                                    DataClause::acc_cache);
778 }
779