Skip to content

[mlir][openacc] Restore unit tests for device_type functions #77122

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jan 9, 2024

Conversation

clementval
Copy link
Contributor

These tests were initially pushed together with #75864 but they were triggering some buildbot failure (sanitizers). They now make use of the OwningOpRef so all the resources are correctly destroyed at the end of each tests.
They will be extended to includes all the extra getter functions added with device_type support.

@llvmbot
Copy link
Member

llvmbot commented Jan 5, 2024

@llvm/pr-subscribers-mlir-openacc
@llvm/pr-subscribers-openacc

@llvm/pr-subscribers-mlir

Author: Valentin Clement (バレンタイン クレメン) (clementval)

Changes

These tests were initially pushed together with #75864 but they were triggering some buildbot failure (sanitizers). They now make use of the OwningOpRef so all the resources are correctly destroyed at the end of each tests.
They will be extended to includes all the extra getter functions added with device_type support.


Full diff: https://github.com/llvm/llvm-project/pull/77122.diff

3 Files Affected:

  • (modified) mlir/unittests/Dialect/CMakeLists.txt (+1)
  • (added) mlir/unittests/Dialect/OpenACC/CMakeLists.txt (+8)
  • (added) mlir/unittests/Dialect/OpenACC/OpenACCOpsTest.cpp (+349)
diff --git a/mlir/unittests/Dialect/CMakeLists.txt b/mlir/unittests/Dialect/CMakeLists.txt
index 2dec4ba3c001e8..13393569f36fe7 100644
--- a/mlir/unittests/Dialect/CMakeLists.txt
+++ b/mlir/unittests/Dialect/CMakeLists.txt
@@ -10,6 +10,7 @@ add_subdirectory(ArmSME)
 add_subdirectory(Index)
 add_subdirectory(LLVMIR)
 add_subdirectory(MemRef)
+add_subdirectory(OpenACC)
 add_subdirectory(SCF)
 add_subdirectory(SparseTensor)
 add_subdirectory(SPIRV)
diff --git a/mlir/unittests/Dialect/OpenACC/CMakeLists.txt b/mlir/unittests/Dialect/OpenACC/CMakeLists.txt
new file mode 100644
index 00000000000000..5133d7fc38296c
--- /dev/null
+++ b/mlir/unittests/Dialect/OpenACC/CMakeLists.txt
@@ -0,0 +1,8 @@
+add_mlir_unittest(MLIROpenACCTests
+  OpenACCOpsTest.cpp
+)
+target_link_libraries(MLIROpenACCTests
+  PRIVATE
+  MLIRIR
+  MLIROpenACCDialect
+)
diff --git a/mlir/unittests/Dialect/OpenACC/OpenACCOpsTest.cpp b/mlir/unittests/Dialect/OpenACC/OpenACCOpsTest.cpp
new file mode 100644
index 00000000000000..d78d7b0fdf6769
--- /dev/null
+++ b/mlir/unittests/Dialect/OpenACC/OpenACCOpsTest.cpp
@@ -0,0 +1,349 @@
+//===- OpenACCOpsTest.cpp - OpenACC ops extra functiosn Tests -------------===//
+//
+// 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/OpenACC/OpenACC.h"
+#include "mlir/IR/Diagnostics.h"
+#include "mlir/IR/MLIRContext.h"
+#include "mlir/IR/OwningOpRef.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>();
+  }
+
+  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 = b.create<Op>(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 testAsyncValue(OpBuilder &b, MLIRContext &context, Location loc,
+                    llvm::SmallVector<DeviceType> &dtypes) {
+  OwningOpRef<Op> op = b.create<Op>(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 =
+      b.create<arith::ConstantIndexOp>(loc, 1);
+  auto dtypeNvidia = DeviceTypeAttr::get(&context, DeviceType::Nvidia);
+  op->setAsyncDeviceTypeAttr(b.getArrayAttr({dtypeNvidia}));
+  op->getAsyncMutable().assign(val->getResult());
+  EXPECT_EQ(op->getAsyncValue(), empty);
+  EXPECT_EQ(op->getAsyncValue(DeviceType::Nvidia), val->getResult());
+
+  op->getAsyncMutable().clear();
+  op->removeAsyncDeviceTypeAttr();
+}
+
+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 testNumGangsValues(OpBuilder &b, MLIRContext &context, Location loc,
+                        llvm::SmallVector<DeviceType> &dtypes,
+                        llvm::SmallVector<DeviceType> &dtypesWithoutNone) {
+  OwningOpRef<Op> op = b.create<Op>(loc, TypeRange{}, ValueRange{});
+  EXPECT_EQ(op->getNumGangsValues().begin(), op->getNumGangsValues().end());
+
+  OwningOpRef<arith::ConstantIndexOp> val1 =
+      b.create<arith::ConstantIndexOp>(loc, 1);
+  OwningOpRef<arith::ConstantIndexOp> val2 =
+      b.create<arith::ConstantIndexOp>(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 = b.create<Op>(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 =
+      b.create<arith::ConstantIndexOp>(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 = b.create<Op>(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);
+}
+
+template <typename Op>
+void testWaitValues(OpBuilder &b, MLIRContext &context, Location loc,
+                    llvm::SmallVector<DeviceType> &dtypes,
+                    llvm::SmallVector<DeviceType> &dtypesWithoutNone) {
+  OwningOpRef<Op> op = b.create<Op>(loc, TypeRange{}, ValueRange{});
+  EXPECT_EQ(op->getWaitValues().begin(), op->getWaitValues().end());
+
+  OwningOpRef<arith::ConstantIndexOp> val1 =
+      b.create<arith::ConstantIndexOp>(loc, 1);
+  OwningOpRef<arith::ConstantIndexOp> val2 =
+      b.create<arith::ConstantIndexOp>(loc, 4);
+  auto dtypeNone = DeviceTypeAttr::get(&context, DeviceType::None);
+  op->getWaitOperandsMutable().assign(val1->getResult());
+  op->setWaitOperandsDeviceTypeAttr(b.getArrayAttr({dtypeNone}));
+  op->setWaitOperandsSegments(b.getDenseI32ArrayAttr({1}));
+  EXPECT_EQ(op->getWaitValues().front(), val1->getResult());
+  for (auto d : dtypesWithoutNone)
+    EXPECT_EQ(op->getWaitValues(d).begin(), op->getWaitValues(d).end());
+
+  op->getWaitOperandsMutable().clear();
+  op->removeWaitOperandsDeviceTypeAttr();
+  op->removeWaitOperandsSegmentsAttr();
+  for (auto d : dtypes)
+    EXPECT_EQ(op->getWaitValues(d).begin(), op->getWaitValues(d).end());
+
+  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}));
+  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();
+  for (auto d : dtypes)
+    EXPECT_EQ(op->getWaitValues(d).begin(), op->getWaitValues(d).end());
+
+  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}));
+  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();
+}
+
+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 = b.create<LoopOp>(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();
+}

Copy link
Contributor

@razvanlupusoru razvanlupusoru left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great! Thank you!

@clementval clementval merged commit 02fa434 into llvm:main Jan 9, 2024
@clementval clementval deleted the acc_device_type_ut branch January 9, 2024 17:51
justinfargnoli pushed a commit to justinfargnoli/llvm-project that referenced this pull request Jan 28, 2024
)

These tests were initially pushed together with
llvm#75864 but they were triggering
some buildbot failure (sanitizers). They now make use of the
`OwningOpRef` so all the resources are correctly destroyed at the end of
each tests.
They will be extended to includes all the extra getter functions added
with device_type support.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants