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