809 lines
34 KiB
C++

//===- OpenACCOpsTest.cpp - Unit tests for OpenACC ops --------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "mlir/Dialect/Arith/IR/Arith.h"
#include "mlir/Dialect/MemRef/IR/MemRef.h"
#include "mlir/Dialect/OpenACC/OpenACC.h"
#include "mlir/IR/BuiltinTypes.h"
#include "mlir/IR/Diagnostics.h"
#include "mlir/IR/MLIRContext.h"
#include "mlir/IR/OwningOpRef.h"
#include "mlir/IR/Value.h"
#include "gtest/gtest.h"
using namespace mlir;
using namespace mlir::acc;
//===----------------------------------------------------------------------===//
// Test Fixture
//===----------------------------------------------------------------------===//
class OpenACCOpsTest : public ::testing::Test {
protected:
OpenACCOpsTest() : b(&context), loc(UnknownLoc::get(&context)) {
context.loadDialect<acc::OpenACCDialect, arith::ArithDialect,
memref::MemRefDialect>();
}
MLIRContext context;
OpBuilder b;
Location loc;
llvm::SmallVector<DeviceType> dtypes = {
DeviceType::None, DeviceType::Star, DeviceType::Multicore,
DeviceType::Default, DeviceType::Host, DeviceType::Nvidia,
DeviceType::Radeon};
llvm::SmallVector<DeviceType> dtypesWithoutNone = {
DeviceType::Star, DeviceType::Multicore, DeviceType::Default,
DeviceType::Host, DeviceType::Nvidia, DeviceType::Radeon};
};
template <typename Op>
void testAsyncOnly(OpBuilder &b, MLIRContext &context, Location loc,
llvm::SmallVector<DeviceType> &dtypes) {
OwningOpRef<Op> op = Op::create(b, loc, TypeRange{}, ValueRange{});
EXPECT_FALSE(op->hasAsyncOnly());
for (auto d : dtypes)
EXPECT_FALSE(op->hasAsyncOnly(d));
auto dtypeNone = DeviceTypeAttr::get(&context, DeviceType::None);
op->setAsyncOnlyAttr(b.getArrayAttr({dtypeNone}));
EXPECT_TRUE(op->hasAsyncOnly());
EXPECT_TRUE(op->hasAsyncOnly(DeviceType::None));
op->removeAsyncOnlyAttr();
auto dtypeHost = DeviceTypeAttr::get(&context, DeviceType::Host);
op->setAsyncOnlyAttr(b.getArrayAttr({dtypeHost}));
EXPECT_TRUE(op->hasAsyncOnly(DeviceType::Host));
EXPECT_FALSE(op->hasAsyncOnly());
op->removeAsyncOnlyAttr();
auto dtypeStar = DeviceTypeAttr::get(&context, DeviceType::Star);
op->setAsyncOnlyAttr(b.getArrayAttr({dtypeHost, dtypeStar}));
EXPECT_TRUE(op->hasAsyncOnly(DeviceType::Star));
EXPECT_TRUE(op->hasAsyncOnly(DeviceType::Host));
EXPECT_FALSE(op->hasAsyncOnly());
op->removeAsyncOnlyAttr();
}
TEST_F(OpenACCOpsTest, asyncOnlyTest) {
testAsyncOnly<ParallelOp>(b, context, loc, dtypes);
testAsyncOnly<KernelsOp>(b, context, loc, dtypes);
testAsyncOnly<SerialOp>(b, context, loc, dtypes);
}
template <typename Op>
void testAsyncOnlyDataEntry(OpBuilder &b, MLIRContext &context, Location loc,
llvm::SmallVector<DeviceType> &dtypes) {
auto memrefTy = MemRefType::get({}, b.getI32Type());
OwningOpRef<memref::AllocaOp> varPtrOp =
memref::AllocaOp::create(b, loc, memrefTy);
TypedValue<PointerLikeType> varPtr =
cast<TypedValue<PointerLikeType>>(varPtrOp->getResult());
OwningOpRef<Op> op = Op::create(b, loc, varPtr,
/*structured=*/true, /*implicit=*/true);
EXPECT_FALSE(op->hasAsyncOnly());
for (auto d : dtypes)
EXPECT_FALSE(op->hasAsyncOnly(d));
auto dtypeNone = DeviceTypeAttr::get(&context, DeviceType::None);
op->setAsyncOnlyAttr(b.getArrayAttr({dtypeNone}));
EXPECT_TRUE(op->hasAsyncOnly());
EXPECT_TRUE(op->hasAsyncOnly(DeviceType::None));
op->removeAsyncOnlyAttr();
auto dtypeHost = DeviceTypeAttr::get(&context, DeviceType::Host);
op->setAsyncOnlyAttr(b.getArrayAttr({dtypeHost}));
EXPECT_TRUE(op->hasAsyncOnly(DeviceType::Host));
EXPECT_FALSE(op->hasAsyncOnly());
op->removeAsyncOnlyAttr();
auto dtypeStar = DeviceTypeAttr::get(&context, DeviceType::Star);
op->setAsyncOnlyAttr(b.getArrayAttr({dtypeHost, dtypeStar}));
EXPECT_TRUE(op->hasAsyncOnly(DeviceType::Star));
EXPECT_TRUE(op->hasAsyncOnly(DeviceType::Host));
EXPECT_FALSE(op->hasAsyncOnly());
op->removeAsyncOnlyAttr();
}
TEST_F(OpenACCOpsTest, asyncOnlyTestDataEntry) {
testAsyncOnlyDataEntry<DevicePtrOp>(b, context, loc, dtypes);
testAsyncOnlyDataEntry<PresentOp>(b, context, loc, dtypes);
testAsyncOnlyDataEntry<CopyinOp>(b, context, loc, dtypes);
testAsyncOnlyDataEntry<CreateOp>(b, context, loc, dtypes);
testAsyncOnlyDataEntry<NoCreateOp>(b, context, loc, dtypes);
testAsyncOnlyDataEntry<AttachOp>(b, context, loc, dtypes);
testAsyncOnlyDataEntry<UpdateDeviceOp>(b, context, loc, dtypes);
testAsyncOnlyDataEntry<UseDeviceOp>(b, context, loc, dtypes);
}
template <typename Op>
void testAsyncValue(OpBuilder &b, MLIRContext &context, Location loc,
llvm::SmallVector<DeviceType> &dtypes) {
OwningOpRef<Op> op = Op::create(b, loc, TypeRange{}, ValueRange{});
mlir::Value empty;
EXPECT_EQ(op->getAsyncValue(), empty);
for (auto d : dtypes)
EXPECT_EQ(op->getAsyncValue(d), empty);
OwningOpRef<arith::ConstantIndexOp> val =
arith::ConstantIndexOp::create(b, loc, 1);
auto dtypeNvidia = DeviceTypeAttr::get(&context, DeviceType::Nvidia);
op->setAsyncOperandsDeviceTypeAttr(b.getArrayAttr({dtypeNvidia}));
op->getAsyncOperandsMutable().assign(val->getResult());
EXPECT_EQ(op->getAsyncValue(), empty);
EXPECT_EQ(op->getAsyncValue(DeviceType::Nvidia), val->getResult());
op->getAsyncOperandsMutable().clear();
op->removeAsyncOperandsDeviceTypeAttr();
}
TEST_F(OpenACCOpsTest, asyncValueTest) {
testAsyncValue<ParallelOp>(b, context, loc, dtypes);
testAsyncValue<KernelsOp>(b, context, loc, dtypes);
testAsyncValue<SerialOp>(b, context, loc, dtypes);
}
template <typename Op>
void testAsyncValueDataEntry(OpBuilder &b, MLIRContext &context, Location loc,
llvm::SmallVector<DeviceType> &dtypes) {
auto memrefTy = MemRefType::get({}, b.getI32Type());
OwningOpRef<memref::AllocaOp> varPtrOp =
memref::AllocaOp::create(b, loc, memrefTy);
TypedValue<PointerLikeType> varPtr =
cast<TypedValue<PointerLikeType>>(varPtrOp->getResult());
OwningOpRef<Op> op = Op::create(b, loc, varPtr,
/*structured=*/true, /*implicit=*/true);
mlir::Value empty;
EXPECT_EQ(op->getAsyncValue(), empty);
for (auto d : dtypes)
EXPECT_EQ(op->getAsyncValue(d), empty);
OwningOpRef<arith::ConstantIndexOp> val =
arith::ConstantIndexOp::create(b, loc, 1);
auto dtypeNvidia = DeviceTypeAttr::get(&context, DeviceType::Nvidia);
op->setAsyncOperandsDeviceTypeAttr(b.getArrayAttr({dtypeNvidia}));
op->getAsyncOperandsMutable().assign(val->getResult());
EXPECT_EQ(op->getAsyncValue(), empty);
EXPECT_EQ(op->getAsyncValue(DeviceType::Nvidia), val->getResult());
op->getAsyncOperandsMutable().clear();
op->removeAsyncOperandsDeviceTypeAttr();
}
TEST_F(OpenACCOpsTest, asyncValueTestDataEntry) {
testAsyncValueDataEntry<DevicePtrOp>(b, context, loc, dtypes);
testAsyncValueDataEntry<PresentOp>(b, context, loc, dtypes);
testAsyncValueDataEntry<CopyinOp>(b, context, loc, dtypes);
testAsyncValueDataEntry<CreateOp>(b, context, loc, dtypes);
testAsyncValueDataEntry<NoCreateOp>(b, context, loc, dtypes);
testAsyncValueDataEntry<AttachOp>(b, context, loc, dtypes);
testAsyncValueDataEntry<UpdateDeviceOp>(b, context, loc, dtypes);
testAsyncValueDataEntry<UseDeviceOp>(b, context, loc, dtypes);
}
template <typename Op>
void testNumGangsValues(OpBuilder &b, MLIRContext &context, Location loc,
llvm::SmallVector<DeviceType> &dtypes,
llvm::SmallVector<DeviceType> &dtypesWithoutNone) {
OwningOpRef<Op> op = Op::create(b, loc, TypeRange{}, ValueRange{});
EXPECT_EQ(op->getNumGangsValues().begin(), op->getNumGangsValues().end());
OwningOpRef<arith::ConstantIndexOp> val1 =
arith::ConstantIndexOp::create(b, loc, 1);
OwningOpRef<arith::ConstantIndexOp> val2 =
arith::ConstantIndexOp::create(b, loc, 4);
auto dtypeNone = DeviceTypeAttr::get(&context, DeviceType::None);
op->getNumGangsMutable().assign(val1->getResult());
op->setNumGangsDeviceTypeAttr(b.getArrayAttr({dtypeNone}));
op->setNumGangsSegments(b.getDenseI32ArrayAttr({1}));
EXPECT_EQ(op->getNumGangsValues().front(), val1->getResult());
for (auto d : dtypesWithoutNone)
EXPECT_EQ(op->getNumGangsValues(d).begin(), op->getNumGangsValues(d).end());
op->getNumGangsMutable().clear();
op->removeNumGangsDeviceTypeAttr();
op->removeNumGangsSegmentsAttr();
for (auto d : dtypes)
EXPECT_EQ(op->getNumGangsValues(d).begin(), op->getNumGangsValues(d).end());
op->getNumGangsMutable().append(val1->getResult());
op->getNumGangsMutable().append(val2->getResult());
op->setNumGangsDeviceTypeAttr(
b.getArrayAttr({DeviceTypeAttr::get(&context, DeviceType::Host),
DeviceTypeAttr::get(&context, DeviceType::Star)}));
op->setNumGangsSegments(b.getDenseI32ArrayAttr({1, 1}));
EXPECT_EQ(op->getNumGangsValues(DeviceType::None).begin(),
op->getNumGangsValues(DeviceType::None).end());
EXPECT_EQ(op->getNumGangsValues(DeviceType::Host).front(), val1->getResult());
EXPECT_EQ(op->getNumGangsValues(DeviceType::Star).front(), val2->getResult());
op->getNumGangsMutable().clear();
op->removeNumGangsDeviceTypeAttr();
op->removeNumGangsSegmentsAttr();
for (auto d : dtypes)
EXPECT_EQ(op->getNumGangsValues(d).begin(), op->getNumGangsValues(d).end());
op->getNumGangsMutable().append(val1->getResult());
op->getNumGangsMutable().append(val2->getResult());
op->getNumGangsMutable().append(val1->getResult());
op->setNumGangsDeviceTypeAttr(
b.getArrayAttr({DeviceTypeAttr::get(&context, DeviceType::Default),
DeviceTypeAttr::get(&context, DeviceType::Multicore)}));
op->setNumGangsSegments(b.getDenseI32ArrayAttr({2, 1}));
EXPECT_EQ(op->getNumGangsValues(DeviceType::None).begin(),
op->getNumGangsValues(DeviceType::None).end());
EXPECT_EQ(op->getNumGangsValues(DeviceType::Default).front(),
val1->getResult());
EXPECT_EQ(op->getNumGangsValues(DeviceType::Default).drop_front().front(),
val2->getResult());
EXPECT_EQ(op->getNumGangsValues(DeviceType::Multicore).front(),
val1->getResult());
op->getNumGangsMutable().clear();
op->removeNumGangsDeviceTypeAttr();
op->removeNumGangsSegmentsAttr();
}
TEST_F(OpenACCOpsTest, numGangsValuesTest) {
testNumGangsValues<ParallelOp>(b, context, loc, dtypes, dtypesWithoutNone);
testNumGangsValues<KernelsOp>(b, context, loc, dtypes, dtypesWithoutNone);
}
template <typename Op>
void testVectorLength(OpBuilder &b, MLIRContext &context, Location loc,
llvm::SmallVector<DeviceType> &dtypes) {
OwningOpRef<Op> op = Op::create(b, loc, TypeRange{}, ValueRange{});
mlir::Value empty;
EXPECT_EQ(op->getVectorLengthValue(), empty);
for (auto d : dtypes)
EXPECT_EQ(op->getVectorLengthValue(d), empty);
OwningOpRef<arith::ConstantIndexOp> val =
arith::ConstantIndexOp::create(b, loc, 1);
auto dtypeNvidia = DeviceTypeAttr::get(&context, DeviceType::Nvidia);
op->setVectorLengthDeviceTypeAttr(b.getArrayAttr({dtypeNvidia}));
op->getVectorLengthMutable().assign(val->getResult());
EXPECT_EQ(op->getVectorLengthValue(), empty);
EXPECT_EQ(op->getVectorLengthValue(DeviceType::Nvidia), val->getResult());
op->getVectorLengthMutable().clear();
op->removeVectorLengthDeviceTypeAttr();
}
TEST_F(OpenACCOpsTest, vectorLengthTest) {
testVectorLength<ParallelOp>(b, context, loc, dtypes);
testVectorLength<KernelsOp>(b, context, loc, dtypes);
}
template <typename Op>
void testWaitOnly(OpBuilder &b, MLIRContext &context, Location loc,
llvm::SmallVector<DeviceType> &dtypes,
llvm::SmallVector<DeviceType> &dtypesWithoutNone) {
OwningOpRef<Op> op = Op::create(b, loc, TypeRange{}, ValueRange{});
EXPECT_FALSE(op->hasWaitOnly());
for (auto d : dtypes)
EXPECT_FALSE(op->hasWaitOnly(d));
auto dtypeNone = DeviceTypeAttr::get(&context, DeviceType::None);
op->setWaitOnlyAttr(b.getArrayAttr({dtypeNone}));
EXPECT_TRUE(op->hasWaitOnly());
EXPECT_TRUE(op->hasWaitOnly(DeviceType::None));
for (auto d : dtypesWithoutNone)
EXPECT_FALSE(op->hasWaitOnly(d));
op->removeWaitOnlyAttr();
auto dtypeHost = DeviceTypeAttr::get(&context, DeviceType::Host);
op->setWaitOnlyAttr(b.getArrayAttr({dtypeHost}));
EXPECT_TRUE(op->hasWaitOnly(DeviceType::Host));
EXPECT_FALSE(op->hasWaitOnly());
op->removeWaitOnlyAttr();
auto dtypeStar = DeviceTypeAttr::get(&context, DeviceType::Star);
op->setWaitOnlyAttr(b.getArrayAttr({dtypeHost, dtypeStar}));
EXPECT_TRUE(op->hasWaitOnly(DeviceType::Star));
EXPECT_TRUE(op->hasWaitOnly(DeviceType::Host));
EXPECT_FALSE(op->hasWaitOnly());
op->removeWaitOnlyAttr();
}
TEST_F(OpenACCOpsTest, waitOnlyTest) {
testWaitOnly<ParallelOp>(b, context, loc, dtypes, dtypesWithoutNone);
testWaitOnly<KernelsOp>(b, context, loc, dtypes, dtypesWithoutNone);
testWaitOnly<SerialOp>(b, context, loc, dtypes, dtypesWithoutNone);
testWaitOnly<UpdateOp>(b, context, loc, dtypes, dtypesWithoutNone);
testWaitOnly<DataOp>(b, context, loc, dtypes, dtypesWithoutNone);
}
template <typename Op>
void testWaitValues(OpBuilder &b, MLIRContext &context, Location loc,
llvm::SmallVector<DeviceType> &dtypes,
llvm::SmallVector<DeviceType> &dtypesWithoutNone) {
OwningOpRef<Op> op = Op::create(b, loc, TypeRange{}, ValueRange{});
EXPECT_EQ(op->getWaitValues().begin(), op->getWaitValues().end());
OwningOpRef<arith::ConstantIndexOp> val1 =
arith::ConstantIndexOp::create(b, loc, 1);
OwningOpRef<arith::ConstantIndexOp> val2 =
arith::ConstantIndexOp::create(b, loc, 4);
OwningOpRef<arith::ConstantIndexOp> val3 =
arith::ConstantIndexOp::create(b, loc, 5);
auto dtypeNone = DeviceTypeAttr::get(&context, DeviceType::None);
op->getWaitOperandsMutable().assign(val1->getResult());
op->setWaitOperandsDeviceTypeAttr(b.getArrayAttr({dtypeNone}));
op->setWaitOperandsSegments(b.getDenseI32ArrayAttr({1}));
op->setHasWaitDevnumAttr(b.getBoolArrayAttr({false}));
EXPECT_EQ(op->getWaitValues().front(), val1->getResult());
for (auto d : dtypesWithoutNone)
EXPECT_TRUE(op->getWaitValues(d).empty());
op->getWaitOperandsMutable().clear();
op->removeWaitOperandsDeviceTypeAttr();
op->removeWaitOperandsSegmentsAttr();
op->removeHasWaitDevnumAttr();
for (auto d : dtypes)
EXPECT_TRUE(op->getWaitValues(d).empty());
op->getWaitOperandsMutable().append(val1->getResult());
op->getWaitOperandsMutable().append(val2->getResult());
op->setWaitOperandsDeviceTypeAttr(
b.getArrayAttr({DeviceTypeAttr::get(&context, DeviceType::Host),
DeviceTypeAttr::get(&context, DeviceType::Star)}));
op->setWaitOperandsSegments(b.getDenseI32ArrayAttr({1, 1}));
op->setHasWaitDevnumAttr(b.getBoolArrayAttr({false, false}));
EXPECT_EQ(op->getWaitValues(DeviceType::None).begin(),
op->getWaitValues(DeviceType::None).end());
EXPECT_EQ(op->getWaitValues(DeviceType::Host).front(), val1->getResult());
EXPECT_EQ(op->getWaitValues(DeviceType::Star).front(), val2->getResult());
op->getWaitOperandsMutable().clear();
op->removeWaitOperandsDeviceTypeAttr();
op->removeWaitOperandsSegmentsAttr();
op->removeHasWaitDevnumAttr();
for (auto d : dtypes)
EXPECT_TRUE(op->getWaitValues(d).empty());
op->getWaitOperandsMutable().append(val1->getResult());
op->getWaitOperandsMutable().append(val2->getResult());
op->getWaitOperandsMutable().append(val1->getResult());
op->setWaitOperandsDeviceTypeAttr(
b.getArrayAttr({DeviceTypeAttr::get(&context, DeviceType::Default),
DeviceTypeAttr::get(&context, DeviceType::Multicore)}));
op->setWaitOperandsSegments(b.getDenseI32ArrayAttr({2, 1}));
op->setHasWaitDevnumAttr(b.getBoolArrayAttr({false, false}));
EXPECT_EQ(op->getWaitValues(DeviceType::None).begin(),
op->getWaitValues(DeviceType::None).end());
EXPECT_EQ(op->getWaitValues(DeviceType::Default).front(), val1->getResult());
EXPECT_EQ(op->getWaitValues(DeviceType::Default).drop_front().front(),
val2->getResult());
EXPECT_EQ(op->getWaitValues(DeviceType::Multicore).front(),
val1->getResult());
op->getWaitOperandsMutable().clear();
op->removeWaitOperandsDeviceTypeAttr();
op->removeWaitOperandsSegmentsAttr();
op->getWaitOperandsMutable().append(val3->getResult());
op->getWaitOperandsMutable().append(val2->getResult());
op->getWaitOperandsMutable().append(val1->getResult());
op->setWaitOperandsDeviceTypeAttr(
b.getArrayAttr({DeviceTypeAttr::get(&context, DeviceType::Multicore)}));
op->setHasWaitDevnumAttr(b.getBoolArrayAttr({true}));
op->setWaitOperandsSegments(b.getDenseI32ArrayAttr({3}));
EXPECT_EQ(op->getWaitValues(DeviceType::None).begin(),
op->getWaitValues(DeviceType::None).end());
EXPECT_FALSE(op->getWaitDevnum());
EXPECT_EQ(op->getWaitDevnum(DeviceType::Multicore), val3->getResult());
EXPECT_EQ(op->getWaitValues(DeviceType::Multicore).front(),
val2->getResult());
EXPECT_EQ(op->getWaitValues(DeviceType::Multicore).drop_front().front(),
val1->getResult());
op->getWaitOperandsMutable().clear();
op->removeWaitOperandsDeviceTypeAttr();
op->removeWaitOperandsSegmentsAttr();
op->removeHasWaitDevnumAttr();
}
TEST_F(OpenACCOpsTest, waitValuesTest) {
testWaitValues<KernelsOp>(b, context, loc, dtypes, dtypesWithoutNone);
testWaitValues<ParallelOp>(b, context, loc, dtypes, dtypesWithoutNone);
testWaitValues<SerialOp>(b, context, loc, dtypes, dtypesWithoutNone);
}
TEST_F(OpenACCOpsTest, loopOpGangVectorWorkerTest) {
OwningOpRef<LoopOp> op = LoopOp::create(b, loc, TypeRange{}, ValueRange{});
EXPECT_FALSE(op->hasGang());
EXPECT_FALSE(op->hasVector());
EXPECT_FALSE(op->hasWorker());
for (auto d : dtypes) {
EXPECT_FALSE(op->hasGang(d));
EXPECT_FALSE(op->hasVector(d));
EXPECT_FALSE(op->hasWorker(d));
}
auto dtypeNone = DeviceTypeAttr::get(&context, DeviceType::None);
op->setGangAttr(b.getArrayAttr({dtypeNone}));
EXPECT_TRUE(op->hasGang());
EXPECT_TRUE(op->hasGang(DeviceType::None));
for (auto d : dtypesWithoutNone)
EXPECT_FALSE(op->hasGang(d));
for (auto d : dtypes) {
EXPECT_FALSE(op->hasVector(d));
EXPECT_FALSE(op->hasWorker(d));
}
op->removeGangAttr();
op->setWorkerAttr(b.getArrayAttr({dtypeNone}));
EXPECT_TRUE(op->hasWorker());
EXPECT_TRUE(op->hasWorker(DeviceType::None));
for (auto d : dtypesWithoutNone)
EXPECT_FALSE(op->hasWorker(d));
for (auto d : dtypes) {
EXPECT_FALSE(op->hasGang(d));
EXPECT_FALSE(op->hasVector(d));
}
op->removeWorkerAttr();
op->setVectorAttr(b.getArrayAttr({dtypeNone}));
EXPECT_TRUE(op->hasVector());
EXPECT_TRUE(op->hasVector(DeviceType::None));
for (auto d : dtypesWithoutNone)
EXPECT_FALSE(op->hasVector(d));
for (auto d : dtypes) {
EXPECT_FALSE(op->hasGang(d));
EXPECT_FALSE(op->hasWorker(d));
}
op->removeVectorAttr();
}
TEST_F(OpenACCOpsTest, routineOpTest) {
OwningOpRef<RoutineOp> op =
RoutineOp::create(b, loc, TypeRange{}, ValueRange{});
EXPECT_FALSE(op->hasSeq());
EXPECT_FALSE(op->hasVector());
EXPECT_FALSE(op->hasWorker());
for (auto d : dtypes) {
EXPECT_FALSE(op->hasSeq(d));
EXPECT_FALSE(op->hasVector(d));
EXPECT_FALSE(op->hasWorker(d));
}
auto dtypeNone = DeviceTypeAttr::get(&context, DeviceType::None);
op->setSeqAttr(b.getArrayAttr({dtypeNone}));
EXPECT_TRUE(op->hasSeq());
for (auto d : dtypesWithoutNone)
EXPECT_FALSE(op->hasSeq(d));
op->removeSeqAttr();
op->setVectorAttr(b.getArrayAttr({dtypeNone}));
EXPECT_TRUE(op->hasVector());
for (auto d : dtypesWithoutNone)
EXPECT_FALSE(op->hasVector(d));
op->removeVectorAttr();
op->setWorkerAttr(b.getArrayAttr({dtypeNone}));
EXPECT_TRUE(op->hasWorker());
for (auto d : dtypesWithoutNone)
EXPECT_FALSE(op->hasWorker(d));
op->removeWorkerAttr();
op->setGangAttr(b.getArrayAttr({dtypeNone}));
EXPECT_TRUE(op->hasGang());
for (auto d : dtypesWithoutNone)
EXPECT_FALSE(op->hasGang(d));
op->removeGangAttr();
op->setGangDimDeviceTypeAttr(b.getArrayAttr({dtypeNone}));
op->setGangDimAttr(b.getArrayAttr({b.getIntegerAttr(b.getI64Type(), 8)}));
EXPECT_TRUE(op->getGangDimValue().has_value());
EXPECT_EQ(op->getGangDimValue().value(), 8);
for (auto d : dtypesWithoutNone)
EXPECT_FALSE(op->getGangDimValue(d).has_value());
op->removeGangDimDeviceTypeAttr();
op->removeGangDimAttr();
op->setBindIdNameDeviceTypeAttr(
b.getArrayAttr({DeviceTypeAttr::get(&context, DeviceType::Host)}));
op->setBindStrNameDeviceTypeAttr(b.getArrayAttr({dtypeNone}));
op->setBindIdNameAttr(
b.getArrayAttr({SymbolRefAttr::get(&context, "test_symbol")}));
op->setBindStrNameAttr(b.getArrayAttr({b.getStringAttr("fname")}));
EXPECT_TRUE(op->getBindNameValue().has_value());
EXPECT_TRUE(op->getBindNameValue(DeviceType::Host).has_value());
EXPECT_EQ(std::visit(
[](const auto &attr) -> std::string {
if constexpr (std::is_same_v<std::decay_t<decltype(attr)>,
mlir::StringAttr>) {
return attr.str();
} else {
return attr.getLeafReference().str();
}
},
op->getBindNameValue().value()),
"fname");
EXPECT_EQ(std::visit(
[](const auto &attr) -> std::string {
if constexpr (std::is_same_v<std::decay_t<decltype(attr)>,
mlir::StringAttr>) {
return attr.str();
} else {
return attr.getLeafReference().str();
}
},
op->getBindNameValue(DeviceType::Host).value()),
"test_symbol");
for (auto d : dtypesWithoutNone) {
if (d != DeviceType::Host)
EXPECT_FALSE(op->getBindNameValue(d).has_value());
}
op->removeBindIdNameDeviceTypeAttr();
op->removeBindStrNameDeviceTypeAttr();
op->removeBindIdNameAttr();
op->removeBindStrNameAttr();
}
template <typename Op>
void testShortDataEntryOpBuilders(OpBuilder &b, MLIRContext &context,
Location loc, DataClause dataClause) {
auto memrefTy = MemRefType::get({}, b.getI32Type());
OwningOpRef<memref::AllocaOp> varPtrOp =
memref::AllocaOp::create(b, loc, memrefTy);
TypedValue<PointerLikeType> varPtr =
cast<TypedValue<PointerLikeType>>(varPtrOp->getResult());
OwningOpRef<Op> op = Op::create(b, loc, varPtr,
/*structured=*/true, /*implicit=*/true);
EXPECT_EQ(op->getVarPtr(), varPtr);
EXPECT_EQ(op->getType(), memrefTy);
EXPECT_EQ(op->getDataClause(), dataClause);
EXPECT_TRUE(op->getImplicit());
EXPECT_TRUE(op->getStructured());
EXPECT_TRUE(op->getBounds().empty());
EXPECT_FALSE(op->getVarPtrPtr());
OwningOpRef<Op> op2 = Op::create(b, loc, varPtr,
/*structured=*/false, /*implicit=*/false);
EXPECT_FALSE(op2->getImplicit());
EXPECT_FALSE(op2->getStructured());
OwningOpRef<arith::ConstantIndexOp> extent =
arith::ConstantIndexOp::create(b, loc, 1);
OwningOpRef<DataBoundsOp> bounds =
DataBoundsOp::create(b, loc, extent->getResult());
OwningOpRef<Op> opWithBounds =
Op::create(b, loc, varPtr,
/*structured=*/true, /*implicit=*/true, bounds->getResult());
EXPECT_FALSE(opWithBounds->getBounds().empty());
EXPECT_EQ(opWithBounds->getBounds().back(), bounds->getResult());
OwningOpRef<Op> opWithName =
Op::create(b, loc, varPtr,
/*structured=*/true, /*implicit=*/true, "varName");
EXPECT_EQ(opWithName->getNameAttr().str(), "varName");
}
TEST_F(OpenACCOpsTest, shortDataEntryOpBuilder) {
testShortDataEntryOpBuilders<PrivateOp>(b, context, loc,
DataClause::acc_private);
testShortDataEntryOpBuilders<FirstprivateOp>(b, context, loc,
DataClause::acc_firstprivate);
testShortDataEntryOpBuilders<ReductionOp>(b, context, loc,
DataClause::acc_reduction);
testShortDataEntryOpBuilders<DevicePtrOp>(b, context, loc,
DataClause::acc_deviceptr);
testShortDataEntryOpBuilders<PresentOp>(b, context, loc,
DataClause::acc_present);
testShortDataEntryOpBuilders<CopyinOp>(b, context, loc,
DataClause::acc_copyin);
testShortDataEntryOpBuilders<CreateOp>(b, context, loc,
DataClause::acc_create);
testShortDataEntryOpBuilders<NoCreateOp>(b, context, loc,
DataClause::acc_no_create);
testShortDataEntryOpBuilders<AttachOp>(b, context, loc,
DataClause::acc_attach);
testShortDataEntryOpBuilders<GetDevicePtrOp>(b, context, loc,
DataClause::acc_getdeviceptr);
testShortDataEntryOpBuilders<UpdateDeviceOp>(b, context, loc,
DataClause::acc_update_device);
testShortDataEntryOpBuilders<UseDeviceOp>(b, context, loc,
DataClause::acc_use_device);
testShortDataEntryOpBuilders<DeclareDeviceResidentOp>(
b, context, loc, DataClause::acc_declare_device_resident);
testShortDataEntryOpBuilders<DeclareLinkOp>(b, context, loc,
DataClause::acc_declare_link);
testShortDataEntryOpBuilders<CacheOp>(b, context, loc, DataClause::acc_cache);
}
template <typename Op>
void testShortDataExitOpBuilders(OpBuilder &b, MLIRContext &context,
Location loc, DataClause dataClause) {
auto memrefTy = MemRefType::get({}, b.getI32Type());
OwningOpRef<memref::AllocaOp> varPtrOp =
memref::AllocaOp::create(b, loc, memrefTy);
TypedValue<PointerLikeType> varPtr =
cast<TypedValue<PointerLikeType>>(varPtrOp->getResult());
OwningOpRef<GetDevicePtrOp> accPtrOp = GetDevicePtrOp::create(
b, loc, varPtr, /*structured=*/true, /*implicit=*/true);
TypedValue<PointerLikeType> accPtr =
cast<TypedValue<PointerLikeType>>(accPtrOp->getResult());
OwningOpRef<Op> op = Op::create(b, loc, accPtr, varPtr,
/*structured=*/true, /*implicit=*/true);
EXPECT_EQ(op->getVarPtr(), varPtr);
EXPECT_EQ(op->getAccPtr(), accPtr);
EXPECT_EQ(op->getDataClause(), dataClause);
EXPECT_TRUE(op->getImplicit());
EXPECT_TRUE(op->getStructured());
EXPECT_TRUE(op->getBounds().empty());
OwningOpRef<Op> op2 = Op::create(b, loc, accPtr, varPtr,
/*structured=*/false, /*implicit=*/false);
EXPECT_FALSE(op2->getImplicit());
EXPECT_FALSE(op2->getStructured());
OwningOpRef<arith::ConstantIndexOp> extent =
arith::ConstantIndexOp::create(b, loc, 1);
OwningOpRef<DataBoundsOp> bounds =
DataBoundsOp::create(b, loc, extent->getResult());
OwningOpRef<Op> opWithBounds =
Op::create(b, loc, accPtr, varPtr,
/*structured=*/true, /*implicit=*/true, bounds->getResult());
EXPECT_FALSE(opWithBounds->getBounds().empty());
EXPECT_EQ(opWithBounds->getBounds().back(), bounds->getResult());
OwningOpRef<Op> opWithName =
Op::create(b, loc, accPtr, varPtr,
/*structured=*/true, /*implicit=*/true, "varName");
EXPECT_EQ(opWithName->getNameAttr().str(), "varName");
}
TEST_F(OpenACCOpsTest, shortDataExitOpBuilder) {
testShortDataExitOpBuilders<CopyoutOp>(b, context, loc,
DataClause::acc_copyout);
testShortDataExitOpBuilders<UpdateHostOp>(b, context, loc,
DataClause::acc_update_host);
}
template <typename Op>
void testShortDataExitNoVarPtrOpBuilders(OpBuilder &b, MLIRContext &context,
Location loc, DataClause dataClause) {
auto memrefTy = MemRefType::get({}, b.getI32Type());
OwningOpRef<memref::AllocaOp> varPtrOp =
memref::AllocaOp::create(b, loc, memrefTy);
TypedValue<PointerLikeType> varPtr =
cast<TypedValue<PointerLikeType>>(varPtrOp->getResult());
OwningOpRef<GetDevicePtrOp> accPtrOp = GetDevicePtrOp::create(
b, loc, varPtr, /*structured=*/true, /*implicit=*/true);
TypedValue<PointerLikeType> accPtr =
cast<TypedValue<PointerLikeType>>(accPtrOp->getResult());
OwningOpRef<Op> op = Op::create(b, loc, accPtr,
/*structured=*/true, /*implicit=*/true);
EXPECT_EQ(op->getAccPtr(), accPtr);
EXPECT_EQ(op->getDataClause(), dataClause);
EXPECT_TRUE(op->getImplicit());
EXPECT_TRUE(op->getStructured());
EXPECT_TRUE(op->getBounds().empty());
OwningOpRef<Op> op2 = Op::create(b, loc, accPtr,
/*structured=*/false, /*implicit=*/false);
EXPECT_FALSE(op2->getImplicit());
EXPECT_FALSE(op2->getStructured());
OwningOpRef<arith::ConstantIndexOp> extent =
arith::ConstantIndexOp::create(b, loc, 1);
OwningOpRef<DataBoundsOp> bounds =
DataBoundsOp::create(b, loc, extent->getResult());
OwningOpRef<Op> opWithBounds =
Op::create(b, loc, accPtr,
/*structured=*/true, /*implicit=*/true, bounds->getResult());
EXPECT_FALSE(opWithBounds->getBounds().empty());
EXPECT_EQ(opWithBounds->getBounds().back(), bounds->getResult());
OwningOpRef<Op> opWithName =
Op::create(b, loc, accPtr,
/*structured=*/true, /*implicit=*/true, "varName");
EXPECT_EQ(opWithName->getNameAttr().str(), "varName");
}
TEST_F(OpenACCOpsTest, shortDataExitOpNoVarPtrBuilder) {
testShortDataExitNoVarPtrOpBuilders<DeleteOp>(b, context, loc,
DataClause::acc_delete);
testShortDataExitNoVarPtrOpBuilders<DetachOp>(b, context, loc,
DataClause::acc_detach);
}
template <typename Op>
void testShortDataEntryOpBuildersMappableVar(OpBuilder &b, MLIRContext &context,
Location loc,
DataClause dataClause) {
auto int64Ty = b.getI64Type();
auto memrefTy = MemRefType::get({}, int64Ty);
OwningOpRef<memref::AllocaOp> varPtrOp =
memref::AllocaOp::create(b, loc, memrefTy);
SmallVector<Value> indices;
OwningOpRef<memref::LoadOp> loadVarOp =
memref::LoadOp::create(b, loc, int64Ty, varPtrOp->getResult(), indices);
EXPECT_TRUE(isMappableType(loadVarOp->getResult().getType()));
TypedValue<MappableType> var =
cast<TypedValue<MappableType>>(loadVarOp->getResult());
OwningOpRef<Op> op = Op::create(b, loc, var,
/*structured=*/true, /*implicit=*/true);
EXPECT_EQ(op->getVar(), var);
EXPECT_EQ(op->getVarPtr(), nullptr);
EXPECT_EQ(op->getType(), int64Ty);
EXPECT_EQ(op->getVarType(), int64Ty);
EXPECT_EQ(op->getDataClause(), dataClause);
EXPECT_TRUE(op->getImplicit());
EXPECT_TRUE(op->getStructured());
EXPECT_TRUE(op->getBounds().empty());
EXPECT_FALSE(op->getVarPtrPtr());
}
struct IntegerOpenACCMappableModel
: public mlir::acc::MappableType::ExternalModel<IntegerOpenACCMappableModel,
IntegerType> {};
TEST_F(OpenACCOpsTest, mappableTypeBuilderDataEntry) {
// First, set up the test by attaching MappableInterface to IntegerType.
IntegerType i64ty = IntegerType::get(&context, 8);
ASSERT_FALSE(isMappableType(i64ty));
IntegerType::attachInterface<IntegerOpenACCMappableModel>(context);
ASSERT_TRUE(isMappableType(i64ty));
testShortDataEntryOpBuildersMappableVar<PrivateOp>(b, context, loc,
DataClause::acc_private);
testShortDataEntryOpBuildersMappableVar<FirstprivateOp>(
b, context, loc, DataClause::acc_firstprivate);
testShortDataEntryOpBuildersMappableVar<ReductionOp>(
b, context, loc, DataClause::acc_reduction);
testShortDataEntryOpBuildersMappableVar<DevicePtrOp>(
b, context, loc, DataClause::acc_deviceptr);
testShortDataEntryOpBuildersMappableVar<PresentOp>(b, context, loc,
DataClause::acc_present);
testShortDataEntryOpBuildersMappableVar<CopyinOp>(b, context, loc,
DataClause::acc_copyin);
testShortDataEntryOpBuildersMappableVar<CreateOp>(b, context, loc,
DataClause::acc_create);
testShortDataEntryOpBuildersMappableVar<NoCreateOp>(
b, context, loc, DataClause::acc_no_create);
testShortDataEntryOpBuildersMappableVar<AttachOp>(b, context, loc,
DataClause::acc_attach);
testShortDataEntryOpBuildersMappableVar<GetDevicePtrOp>(
b, context, loc, DataClause::acc_getdeviceptr);
testShortDataEntryOpBuildersMappableVar<UpdateDeviceOp>(
b, context, loc, DataClause::acc_update_device);
testShortDataEntryOpBuildersMappableVar<UseDeviceOp>(
b, context, loc, DataClause::acc_use_device);
testShortDataEntryOpBuildersMappableVar<DeclareDeviceResidentOp>(
b, context, loc, DataClause::acc_declare_device_resident);
testShortDataEntryOpBuildersMappableVar<DeclareLinkOp>(
b, context, loc, DataClause::acc_declare_link);
testShortDataEntryOpBuildersMappableVar<CacheOp>(b, context, loc,
DataClause::acc_cache);
}