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(value: {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(value: {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(value: {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(value: {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(value: {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(value: {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>(location: loc, args: 1); |
140 | auto dtypeNvidia = DeviceTypeAttr::get(&context, DeviceType::Nvidia); |
141 | op->setAsyncOperandsDeviceTypeAttr(b.getArrayAttr(value: {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>(location: loc, args: 1); |
175 | auto dtypeNvidia = DeviceTypeAttr::get(&context, DeviceType::Nvidia); |
176 | op->setAsyncOperandsDeviceTypeAttr(b.getArrayAttr(value: {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>(location: loc, args: 1); |
205 | OwningOpRef<arith::ConstantIndexOp> val2 = |
206 | b.create<arith::ConstantIndexOp>(location: loc, args: 4); |
207 | auto dtypeNone = DeviceTypeAttr::get(&context, DeviceType::None); |
208 | op->getNumGangsMutable().assign(val1->getResult()); |
209 | op->setNumGangsDeviceTypeAttr(b.getArrayAttr(value: {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>(location: loc, args: 1); |
276 | auto dtypeNvidia = DeviceTypeAttr::get(&context, DeviceType::Nvidia); |
277 | op->setVectorLengthDeviceTypeAttr(b.getArrayAttr(value: {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(value: {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(value: {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(value: {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>(location: loc, args: 1); |
340 | OwningOpRef<arith::ConstantIndexOp> val2 = |
341 | b.create<arith::ConstantIndexOp>(location: loc, args: 4); |
342 | OwningOpRef<arith::ConstantIndexOp> val3 = |
343 | b.create<arith::ConstantIndexOp>(location: loc, args: 5); |
344 | auto dtypeNone = DeviceTypeAttr::get(&context, DeviceType::None); |
345 | op->getWaitOperandsMutable().assign(val1->getResult()); |
346 | op->setWaitOperandsDeviceTypeAttr(b.getArrayAttr(value: {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(value: {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(value: {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(value: {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(value: {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(value: {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(value: {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(value: {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(value: {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(value: {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>(location: loc, args: 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>(location: loc, args: 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>(location: loc, args: 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 | |