809 lines
34 KiB
C++
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);
|
|
}
|