[Mlir-commits] [mlir] 0661f66 - [mlir][acc] Add reduction utilities for acc to gpu lowering (#209316)

llvmlistbot at llvm.org llvmlistbot at llvm.org
Mon Jul 13 14:55:10 PDT 2026


Author: Razvan Lupusoru
Date: 2026-07-13T21:55:05Z
New Revision: 0661f6636a0a5a79635e99d98a239c2bba4ea2ed

URL: https://github.com/llvm/llvm-project/commit/0661f6636a0a5a79635e99d98a239c2bba4ea2ed
DIFF: https://github.com/llvm/llvm-project/commit/0661f6636a0a5a79635e99d98a239c2bba4ea2ed.diff

LOG: [mlir][acc] Add reduction utilities for acc to gpu lowering (#209316)

In preparation for the pass that converts `acc.compute_region` to GPU
dialect, this PR adds several utilities which are used in that pass
related to reductions. Doing so to simplify review and to ensure that
unit testing is added for the utilities.

---------

Co-authored-by: Scott Manley <rscottmanley at gmail.com>

Added: 
    mlir/include/mlir/Dialect/OpenACC/OpenACCUtilsReduction.h
    mlir/lib/Dialect/OpenACC/Utils/OpenACCUtilsReduction.cpp
    mlir/unittests/Dialect/OpenACC/OpenACCUtilsReductionTest.cpp

Modified: 
    mlir/lib/Dialect/OpenACC/Utils/CMakeLists.txt
    mlir/unittests/Dialect/OpenACC/CMakeLists.txt

Removed: 
    


################################################################################
diff  --git a/mlir/include/mlir/Dialect/OpenACC/OpenACCUtilsReduction.h b/mlir/include/mlir/Dialect/OpenACC/OpenACCUtilsReduction.h
new file mode 100644
index 0000000000000..ba4c09c0aaf5f
--- /dev/null
+++ b/mlir/include/mlir/Dialect/OpenACC/OpenACCUtilsReduction.h
@@ -0,0 +1,66 @@
+//===- OpenACCUtilsReduction.h - OpenACC reduction utilities ----*- C++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines utility functions for OpenACC reductions.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef MLIR_DIALECT_OPENACC_OPENACCUTILSREDUCTION_H_
+#define MLIR_DIALECT_OPENACC_OPENACCUTILSREDUCTION_H_
+
+#include "mlir/Dialect/Arith/IR/Arith.h"
+#include "mlir/Dialect/OpenACC/OpenACC.h"
+#include "mlir/Dialect/OpenACC/OpenACCParMapping.h"
+#include "mlir/IR/Builders.h"
+#include "mlir/IR/Value.h"
+#include "llvm/ADT/SmallVector.h"
+
+#include <optional>
+
+namespace mlir {
+namespace acc {
+
+/// Returns the parallel dimensions that participate in \p op's combine step.
+///
+/// Used when lowering reductions to determine which GPU parallelism levels must
+/// be synchronized before combining partial results.
+SmallVector<GPUParallelDimAttr>
+getReductionCombineParDims(ReductionCombineOp op);
+
+/// Returns the parallel dimensions that participate in \p op's combine step.
+///
+/// Prefers dimensions from an `acc.reduction_accumulate` user of the source
+/// variable; otherwise falls back to \p op's `acc.par_dims` attribute.
+SmallVector<GPUParallelDimAttr>
+getReductionCombineParDims(ReductionCombineRegionOp op);
+
+/// Maps an `arith` atomic RMW kind to the corresponding acc reduction operator.
+ReductionOperator translateAtomicRMWKind(arith::AtomicRMWKind kind);
+
+/// Maps an acc reduction operator to the `arith` atomic RMW kind for \p type.
+///
+/// Returns `std::nullopt` when \p redOp is not supported for \p type.
+std::optional<arith::AtomicRMWKind>
+translateACCReductionOperator(ReductionOperator redOp, Type type);
+
+/// Creates the identity (neutral) value for a reduction of \p type and \p kind.
+///
+/// When \p useOnlyFiniteValue is true, floating-point identities avoid
+/// non-finite sentinel values where applicable.
+Value createIdentityValue(OpBuilder &b, Location loc, Type type,
+                          arith::AtomicRMWKind kind,
+                          bool useOnlyFiniteValue = true);
+
+/// Combines two reduction partial values using the operator for \p kind.
+Value generateReductionOp(OpBuilder &b, Location loc, Value lhs, Value rhs,
+                          arith::AtomicRMWKind kind);
+
+} // namespace acc
+} // namespace mlir
+
+#endif // MLIR_DIALECT_OPENACC_OPENACCUTILSREDUCTION_H_

diff  --git a/mlir/lib/Dialect/OpenACC/Utils/CMakeLists.txt b/mlir/lib/Dialect/OpenACC/Utils/CMakeLists.txt
index 67e1fc269ffa4..fc30625964c43 100644
--- a/mlir/lib/Dialect/OpenACC/Utils/CMakeLists.txt
+++ b/mlir/lib/Dialect/OpenACC/Utils/CMakeLists.txt
@@ -3,6 +3,7 @@ add_mlir_dialect_library(MLIROpenACCUtils
   OpenACCUtilsCG.cpp
   OpenACCUtilsGPU.cpp
   OpenACCUtilsLoop.cpp
+  OpenACCUtilsReduction.cpp
   OpenACCUtilsTiling.cpp
   OpenACCUtilsType.cpp
 
@@ -21,8 +22,10 @@ add_mlir_dialect_library(MLIROpenACCUtils
   LINK_LIBS PUBLIC
   MLIRArithDialect
   MLIRArithUtils
+  MLIRComplexDialect
   MLIRDataLayoutInterfaces
   MLIRGPUDialect
+  MLIRMemRefDialect
   MLIROpenACCDialect
   MLIRIR
   MLIRSCFDialect

diff  --git a/mlir/lib/Dialect/OpenACC/Utils/OpenACCUtilsReduction.cpp b/mlir/lib/Dialect/OpenACC/Utils/OpenACCUtilsReduction.cpp
new file mode 100644
index 0000000000000..df69714344f14
--- /dev/null
+++ b/mlir/lib/Dialect/OpenACC/Utils/OpenACCUtilsReduction.cpp
@@ -0,0 +1,221 @@
+//===- OpenACCUtilsReduction.cpp - OpenACC reduction utilities ------------===//
+//
+// 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/OpenACC/OpenACCUtilsReduction.h"
+#include "mlir/Dialect/Arith/Utils/Utils.h"
+#include "mlir/Dialect/Complex/IR/Complex.h"
+#include "mlir/Dialect/OpenACC/OpenACCUtilsCG.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace mlir;
+
+namespace mlir {
+namespace acc {
+
+static bool isFloatOrComplexType(Type ty) {
+  return isa<FloatType, ComplexType>(ty);
+}
+
+SmallVector<GPUParallelDimAttr>
+getReductionCombineParDims(ReductionCombineOp reductionCombineOp) {
+  if (GPUParallelDimsAttr parDimsAttr = getParDimsAttr(reductionCombineOp))
+    return SmallVector<GPUParallelDimAttr>(parDimsAttr.getArray());
+  llvm_unreachable(
+      "expected parallel dimensions attribute for reduction combine op");
+}
+
+SmallVector<GPUParallelDimAttr>
+getReductionCombineParDims(ReductionCombineRegionOp combineRegionOp) {
+  for (Operation *user : combineRegionOp.getSrcVar().getUsers()) {
+    if (auto accumulateOp = dyn_cast<ReductionAccumulateOp>(user))
+      return SmallVector<GPUParallelDimAttr>(
+          accumulateOp.getParDims().getArray());
+  }
+  if (GPUParallelDimsAttr parDimsAttr = getParDimsAttr(combineRegionOp))
+    return SmallVector<GPUParallelDimAttr>(parDimsAttr.getArray());
+  return {};
+}
+
+ReductionOperator translateAtomicRMWKind(arith::AtomicRMWKind kind) {
+  switch (kind) {
+  case arith::AtomicRMWKind::addf:
+  case arith::AtomicRMWKind::addi:
+    return ReductionOperator::AccAdd;
+  case arith::AtomicRMWKind::mulf:
+  case arith::AtomicRMWKind::muli:
+    return ReductionOperator::AccMul;
+  case arith::AtomicRMWKind::maxs:
+  case arith::AtomicRMWKind::maxu:
+  case arith::AtomicRMWKind::maximumf:
+  case arith::AtomicRMWKind::maxnumf:
+    return ReductionOperator::AccMax;
+  case arith::AtomicRMWKind::minu:
+  case arith::AtomicRMWKind::mins:
+  case arith::AtomicRMWKind::minimumf:
+  case arith::AtomicRMWKind::minnumf:
+    return ReductionOperator::AccMin;
+  case arith::AtomicRMWKind::andi:
+    return ReductionOperator::AccIand;
+  case arith::AtomicRMWKind::ori:
+    return ReductionOperator::AccIor;
+  case arith::AtomicRMWKind::xori:
+    return ReductionOperator::AccXor;
+  case arith::AtomicRMWKind::assign:
+    break;
+  }
+  llvm_unreachable("unsupported atomic kind");
+}
+
+std::optional<arith::AtomicRMWKind>
+translateACCReductionOperator(ReductionOperator redOp, Type type) {
+  if (type.isInteger() && type.isUnsignedInteger())
+    return std::nullopt;
+
+  if (auto reducible = dyn_cast<ReducibleType>(type)) {
+    if (std::optional<arith::AtomicRMWKind> kind =
+            reducible.getAtomicRMWKind(redOp))
+      return kind;
+    return std::nullopt;
+  }
+
+  switch (redOp) {
+  case ReductionOperator::AccAdd:
+    if (type.isInteger())
+      return arith::AtomicRMWKind::addi;
+    if (isFloatOrComplexType(type))
+      return arith::AtomicRMWKind::addf;
+    break;
+  case ReductionOperator::AccMul:
+    if (type.isInteger())
+      return arith::AtomicRMWKind::muli;
+    if (isFloatOrComplexType(type))
+      return arith::AtomicRMWKind::mulf;
+    break;
+  case ReductionOperator::AccMax:
+    if (type.isInteger())
+      return arith::AtomicRMWKind::maxs;
+    if (type.isFloat())
+      return arith::AtomicRMWKind::maxnumf;
+    break;
+  case ReductionOperator::AccMaximumf:
+    return arith::AtomicRMWKind::maximumf;
+  case ReductionOperator::AccMaxnumf:
+    return arith::AtomicRMWKind::maxnumf;
+  case ReductionOperator::AccMin:
+    if (type.isInteger())
+      return arith::AtomicRMWKind::mins;
+    if (type.isFloat())
+      return arith::AtomicRMWKind::minnumf;
+    break;
+  case ReductionOperator::AccMinimumf:
+    return arith::AtomicRMWKind::minimumf;
+  case ReductionOperator::AccMinnumf:
+    return arith::AtomicRMWKind::minnumf;
+  case ReductionOperator::AccIand:
+  case ReductionOperator::AccLand:
+    if (type.isInteger())
+      return arith::AtomicRMWKind::andi;
+    break;
+  case ReductionOperator::AccIor:
+  case ReductionOperator::AccLor:
+    if (type.isInteger())
+      return arith::AtomicRMWKind::ori;
+    break;
+  case ReductionOperator::AccXor:
+  case ReductionOperator::AccNeqv:
+    if (type.isInteger())
+      return arith::AtomicRMWKind::xori;
+    break;
+  case ReductionOperator::AccEqv:
+  case ReductionOperator::AccNone:
+    break;
+  }
+  return std::nullopt;
+}
+
+static TypedAttr getReductionIdentityValueAttr(arith::AtomicRMWKind kind,
+                                               Type type, OpBuilder &builder,
+                                               Location loc,
+                                               bool useOnlyFiniteValue) {
+  if (type.isIntOrIndexOrFloat()) {
+    TypedAttr attr = arith::getIdentityValueAttr(kind, type, builder, loc,
+                                                 useOnlyFiniteValue);
+    if (!attr)
+      emitError(loc) << "reduction identity: operator not supported " << kind;
+    return attr;
+  }
+  if (auto complexTy = dyn_cast<ComplexType>(type)) {
+    auto eltTy = dyn_cast<FloatType>(complexTy.getElementType());
+    if (!eltTy) {
+      emitError(loc) << "reduction identity: complex with non-floating "
+                        "element type";
+      return nullptr;
+    }
+    switch (kind) {
+    case arith::AtomicRMWKind::addf: {
+      TypedAttr scalarAttr = arith::getIdentityValueAttr(
+          kind, eltTy, builder, loc, useOnlyFiniteValue);
+      assert(scalarAttr && "expected scalar identity for complex reduction");
+      double d = cast<FloatAttr>(scalarAttr).getValue().convertToDouble();
+      return complex::NumberAttr::get(complexTy, d, d);
+    }
+    case arith::AtomicRMWKind::mulf: {
+      TypedAttr scalarAttr = arith::getIdentityValueAttr(
+          kind, eltTy, builder, loc, useOnlyFiniteValue);
+      assert(scalarAttr &&
+             "expected scalar identity for complex mulf reduction");
+      auto realPart = cast<FloatAttr>(scalarAttr).getValue();
+      return complex::NumberAttr::get(complexTy, realPart.convertToDouble(),
+                                      0.0);
+    }
+    default:
+      emitError(loc)
+          << "reduction identity: operator not supported for complex " << kind;
+      return nullptr;
+    }
+  }
+  emitError(loc) << "reduction identity: type not supported " << type;
+  return nullptr;
+}
+
+Value createIdentityValue(OpBuilder &b, Location loc, Type type,
+                          arith::AtomicRMWKind kind, bool useOnlyFiniteValue) {
+  TypedAttr typedAttr =
+      getReductionIdentityValueAttr(kind, type, b, loc, useOnlyFiniteValue);
+  assert(typedAttr && "expected identity attribute");
+  if (auto numAttr = dyn_cast<complex::NumberAttr>(typedAttr)) {
+    auto complexTy = cast<ComplexType>(numAttr.getType());
+    auto floatElt = cast<FloatType>(complexTy.getElementType());
+    Value realVal = arith::ConstantOp::create(
+        b, loc, b.getFloatAttr(floatElt, numAttr.getReal()));
+    Value imagVal = arith::ConstantOp::create(
+        b, loc, b.getFloatAttr(floatElt, numAttr.getImag()));
+    return complex::CreateOp::create(b, loc, complexTy, realVal, imagVal);
+  }
+  return arith::ConstantOp::create(b, loc, typedAttr);
+}
+
+Value generateReductionOp(OpBuilder &b, Location loc, Value lhs, Value rhs,
+                          arith::AtomicRMWKind kind) {
+  assert(lhs.getType() == rhs.getType() &&
+         "expected same type for lhs and rhs");
+  if (isa<ComplexType>(lhs.getType())) {
+    switch (kind) {
+    case arith::AtomicRMWKind::addf:
+      return complex::AddOp::create(b, loc, lhs, rhs);
+    case arith::AtomicRMWKind::mulf:
+      return complex::MulOp::create(b, loc, lhs, rhs);
+    default:
+      llvm_unreachable("unsupported complex atomic reduction kind");
+    }
+  }
+  return arith::getReductionOp(kind, b, loc, lhs, rhs);
+}
+
+} // namespace acc
+} // namespace mlir

diff  --git a/mlir/unittests/Dialect/OpenACC/CMakeLists.txt b/mlir/unittests/Dialect/OpenACC/CMakeLists.txt
index 3a14d3e6796cb..c3b56ec877827 100644
--- a/mlir/unittests/Dialect/OpenACC/CMakeLists.txt
+++ b/mlir/unittests/Dialect/OpenACC/CMakeLists.txt
@@ -5,6 +5,7 @@ add_mlir_unittest(MLIROpenACCTests
   OpenACCTypeInterfacesTest.cpp
   OpenACCUtilsCGTest.cpp
   OpenACCUtilsGPUTest.cpp
+  OpenACCUtilsReductionTest.cpp
   OpenACCUtilsTest.cpp
   OpenACCUtilsTypeTest.cpp
   OpenACCUtilsTilingTest.cpp
@@ -14,12 +15,14 @@ mlir_target_link_libraries(MLIROpenACCTests
   PRIVATE
   MLIRIR
   MLIRAffineDialect
+  MLIRComplexDialect
   MLIRDLTIDialect
   MLIRFuncDialect
   MLIRGPUDialect
   MLIRLLVMDialect
   MLIRMemRefDialect
   MLIRArithDialect
+  MLIROpenACCAnalysis
   MLIROpenACCDialect
   MLIROpenACCUtils
   MLIRSCFDialect

diff  --git a/mlir/unittests/Dialect/OpenACC/OpenACCUtilsReductionTest.cpp b/mlir/unittests/Dialect/OpenACC/OpenACCUtilsReductionTest.cpp
new file mode 100644
index 0000000000000..566f905ff24d5
--- /dev/null
+++ b/mlir/unittests/Dialect/OpenACC/OpenACCUtilsReductionTest.cpp
@@ -0,0 +1,192 @@
+//===- OpenACCUtilsReductionTest.cpp - OpenACC reduction utility 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/OpenACC/OpenACCUtilsReduction.h"
+#include "mlir/Dialect/Arith/IR/Arith.h"
+#include "mlir/Dialect/Complex/IR/Complex.h"
+#include "mlir/Dialect/MemRef/IR/MemRef.h"
+#include "mlir/Dialect/OpenACC/OpenACC.h"
+#include "mlir/Dialect/OpenACC/OpenACCUtilsCG.h"
+#include "mlir/IR/BuiltinOps.h"
+#include "mlir/IR/BuiltinTypes.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 OpenACCUtilsReductionTest : public ::testing::Test {
+protected:
+  OpenACCUtilsReductionTest() : b(&context), loc(UnknownLoc::get(&context)) {
+    context.loadDialect<acc::OpenACCDialect, arith::ArithDialect,
+                        complex::ComplexDialect, memref::MemRefDialect>();
+  }
+
+  MLIRContext context;
+  OpBuilder b;
+  Location loc;
+};
+
+//===----------------------------------------------------------------------===//
+// translateAtomicRMWKind / translateACCReductionOperator Tests
+//===----------------------------------------------------------------------===//
+
+TEST_F(OpenACCUtilsReductionTest, translateAtomicRMWKind) {
+  EXPECT_EQ(translateAtomicRMWKind(arith::AtomicRMWKind::addi),
+            ReductionOperator::AccAdd);
+  EXPECT_EQ(translateAtomicRMWKind(arith::AtomicRMWKind::addf),
+            ReductionOperator::AccAdd);
+  EXPECT_EQ(translateAtomicRMWKind(arith::AtomicRMWKind::muli),
+            ReductionOperator::AccMul);
+  EXPECT_EQ(translateAtomicRMWKind(arith::AtomicRMWKind::maxnumf),
+            ReductionOperator::AccMax);
+  EXPECT_EQ(translateAtomicRMWKind(arith::AtomicRMWKind::minnumf),
+            ReductionOperator::AccMin);
+  EXPECT_EQ(translateAtomicRMWKind(arith::AtomicRMWKind::andi),
+            ReductionOperator::AccIand);
+}
+
+TEST_F(OpenACCUtilsReductionTest, translateACCReductionOperator) {
+  EXPECT_EQ(
+      *translateACCReductionOperator(ReductionOperator::AccAdd, b.getI32Type()),
+      arith::AtomicRMWKind::addi);
+  EXPECT_EQ(
+      *translateACCReductionOperator(ReductionOperator::AccAdd, b.getF32Type()),
+      arith::AtomicRMWKind::addf);
+  EXPECT_EQ(
+      *translateACCReductionOperator(ReductionOperator::AccMul, b.getI64Type()),
+      arith::AtomicRMWKind::muli);
+  EXPECT_EQ(
+      *translateACCReductionOperator(ReductionOperator::AccMax, b.getF32Type()),
+      arith::AtomicRMWKind::maxnumf);
+  EXPECT_FALSE(translateACCReductionOperator(ReductionOperator::AccAdd,
+                                             b.getIntegerType(32, false)));
+}
+
+//===----------------------------------------------------------------------===//
+// getReductionCombineParDims Tests
+//===----------------------------------------------------------------------===//
+
+TEST_F(OpenACCUtilsReductionTest, getReductionCombineParDimsFromCombineOp) {
+  MemRefType memTy = MemRefType::get({}, b.getI32Type());
+  auto dest = memref::AllocaOp::create(b, loc, memTy);
+  auto src = memref::AllocaOp::create(b, loc, memTy);
+  auto combine =
+      ReductionCombineOp::create(b, loc, dest, src, ReductionOperator::AccAdd);
+  GPUParallelDimsAttr parDims = GPUParallelDimsAttr::get(
+      &context, {GPUParallelDimAttr::blockXDim(&context),
+                 GPUParallelDimAttr::threadXDim(&context)});
+  setParDimsAttr(combine, parDims);
+
+  SmallVector<GPUParallelDimAttr> result = getReductionCombineParDims(combine);
+  ASSERT_EQ(result.size(), 2u);
+  EXPECT_EQ(result[0], GPUParallelDimAttr::blockXDim(&context));
+  EXPECT_EQ(result[1], GPUParallelDimAttr::threadXDim(&context));
+}
+
+TEST_F(OpenACCUtilsReductionTest,
+       getReductionCombineParDimsFromCombineRegionViaAccumulate) {
+  MemRefType memTy = MemRefType::get({}, b.getI32Type());
+  auto dest = memref::AllocaOp::create(b, loc, memTy);
+  auto src = memref::AllocaOp::create(b, loc, memTy);
+  auto combineRegion = ReductionCombineRegionOp::create(b, loc, dest, src);
+  combineRegion.getRegion().emplaceBlock();
+  b.setInsertionPointToStart(&combineRegion.getRegion().front());
+  YieldOp::create(b, loc);
+
+  GPUParallelDimsAttr accDims = GPUParallelDimsAttr::get(
+      &context, {GPUParallelDimAttr::threadYDim(&context)});
+  Value partial = arith::ConstantIntOp::create(b, loc, b.getI32Type(), 1);
+  ReductionAccumulateOp::create(b, loc, partial, src.getResult(),
+                                ReductionOperator::AccAdd, accDims);
+
+  SmallVector<GPUParallelDimAttr> result =
+      getReductionCombineParDims(combineRegion);
+  ASSERT_EQ(result.size(), 1u);
+  EXPECT_EQ(result[0], GPUParallelDimAttr::threadYDim(&context));
+}
+
+TEST_F(OpenACCUtilsReductionTest,
+       getReductionCombineParDimsFromCombineRegionAttribute) {
+  MemRefType memTy = MemRefType::get({}, b.getI32Type());
+  auto dest = memref::AllocaOp::create(b, loc, memTy);
+  auto src = memref::AllocaOp::create(b, loc, memTy);
+  auto combineRegion = ReductionCombineRegionOp::create(b, loc, dest, src);
+  GPUParallelDimsAttr parDims = GPUParallelDimsAttr::get(
+      &context, {GPUParallelDimAttr::blockZDim(&context)});
+  setParDimsAttr(combineRegion, parDims);
+  combineRegion.getRegion().emplaceBlock();
+  b.setInsertionPointToStart(&combineRegion.getRegion().front());
+  YieldOp::create(b, loc);
+
+  SmallVector<GPUParallelDimAttr> result =
+      getReductionCombineParDims(combineRegion);
+  ASSERT_EQ(result.size(), 1u);
+  EXPECT_EQ(result[0], GPUParallelDimAttr::blockZDim(&context));
+}
+
+//===----------------------------------------------------------------------===//
+// createIdentityValue / generateReductionOp Tests
+//===----------------------------------------------------------------------===//
+
+TEST_F(OpenACCUtilsReductionTest, createIdentityValueIntegerAdd) {
+  Value ident =
+      createIdentityValue(b, loc, b.getI32Type(), arith::AtomicRMWKind::addi);
+  auto cst = ident.getDefiningOp<arith::ConstantOp>();
+  ASSERT_TRUE(cst);
+  EXPECT_EQ(cast<IntegerAttr>(cst.getValue()).getInt(), 0);
+}
+
+TEST_F(OpenACCUtilsReductionTest, createIdentityValueFloatMul) {
+  Value ident =
+      createIdentityValue(b, loc, b.getF32Type(), arith::AtomicRMWKind::mulf);
+  auto cst = ident.getDefiningOp<arith::ConstantOp>();
+  ASSERT_TRUE(cst);
+  EXPECT_EQ(cast<FloatAttr>(cst.getValue()).getValueAsDouble(), 1.0);
+}
+
+TEST_F(OpenACCUtilsReductionTest, createIdentityValueComplexAdd) {
+  auto complexTy = ComplexType::get(b.getF32Type());
+  Value ident =
+      createIdentityValue(b, loc, complexTy, arith::AtomicRMWKind::addf);
+  auto createOp = ident.getDefiningOp<complex::CreateOp>();
+  ASSERT_TRUE(createOp);
+  auto realCst = createOp.getReal().getDefiningOp<arith::ConstantOp>();
+  auto imagCst = createOp.getImaginary().getDefiningOp<arith::ConstantOp>();
+  ASSERT_TRUE(realCst);
+  ASSERT_TRUE(imagCst);
+  EXPECT_EQ(cast<FloatAttr>(realCst.getValue()).getValueAsDouble(), 0.0);
+  EXPECT_EQ(cast<FloatAttr>(imagCst.getValue()).getValueAsDouble(), 0.0);
+}
+
+TEST_F(OpenACCUtilsReductionTest, generateReductionOpIntegerAdd) {
+  Value lhs = arith::ConstantIntOp::create(b, loc, b.getI32Type(), 3);
+  Value rhs = arith::ConstantIntOp::create(b, loc, b.getI32Type(), 5);
+  Value sum = generateReductionOp(b, loc, lhs, rhs, arith::AtomicRMWKind::addi);
+  EXPECT_TRUE(isa<arith::AddIOp>(sum.getDefiningOp()));
+}
+
+TEST_F(OpenACCUtilsReductionTest, generateReductionOpComplexMul) {
+  auto complexTy = ComplexType::get(b.getF32Type());
+  Value lhs = complex::CreateOp::create(
+      b, loc, complexTy,
+      arith::ConstantOp::create(b, loc, b.getF32FloatAttr(2.0)),
+      arith::ConstantOp::create(b, loc, b.getF32FloatAttr(1.0)));
+  Value rhs = complex::CreateOp::create(
+      b, loc, complexTy,
+      arith::ConstantOp::create(b, loc, b.getF32FloatAttr(3.0)),
+      arith::ConstantOp::create(b, loc, b.getF32FloatAttr(0.0)));
+  Value product =
+      generateReductionOp(b, loc, lhs, rhs, arith::AtomicRMWKind::mulf);
+  EXPECT_TRUE(isa<complex::MulOp>(product.getDefiningOp()));
+}


        


More information about the Mlir-commits mailing list