[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@gmail.com>
This commit is contained in:
1 parent
acbc7e571c
commit
0661f6636a
5 files changed
+485
No files matched your search
@@ -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_
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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()));
|
||||
}
|
||||
Reference in new issue
Block a user