[Mlir-commits] [mlir] 56164c3 - [Flang][MLIR][OpenMP] Add support for logical eqv in worksharing-loop
Kiran Chandramohan
llvmlistbot at llvm.org
Thu Mar 9 06:04:47 PST 2023
Author: Dylan Fleming
Date: 2023-03-09T13:58:23Z
New Revision: 56164c3eb450c1de2d7326a545e4c7bbc57e91b5
URL: https://github.com/llvm/llvm-project/commit/56164c3eb450c1de2d7326a545e4c7bbc57e91b5
DIFF: https://github.com/llvm/llvm-project/commit/56164c3eb450c1de2d7326a545e4c7bbc57e91b5.diff
LOG: [Flang][MLIR][OpenMP] Add support for logical eqv in worksharing-loop
The patch adds the lowering from Flang parse-tree to FIR+OpenMP. The
conversion code is also added in MLIR.
Reviewed By: kiranchandramohan
Differential Revision: https://reviews.llvm.org/D133442
Co-authored-by: Kiran Chandramohan <kiran.chandramohan at arm.com>
Added:
flang/test/Lower/OpenMP/wsloop-reduction-logical-eqv.f90
Modified:
flang/lib/Lower/OpenMP.cpp
flang/test/Fir/convert-to-llvm-openmp-and-fir.fir
flang/test/Lower/OpenMP/wsloop-reduction-logical-and.f90
mlir/lib/Conversion/OpenMPToLLVM/OpenMPToLLVM.cpp
mlir/test/Conversion/OpenMPToLLVM/convert-to-llvmir.mlir
Removed:
flang/test/Lower/OpenMP/Todo/reduction-eqv.f90
################################################################################
diff --git a/flang/lib/Lower/OpenMP.cpp b/flang/lib/Lower/OpenMP.cpp
index 8fcf0ba226a5..b4a426898385 100644
--- a/flang/lib/Lower/OpenMP.cpp
+++ b/flang/lib/Lower/OpenMP.cpp
@@ -1112,7 +1112,7 @@ static int getOperationIdentity(llvm::StringRef reductionOpName,
mlir::Location loc) {
if (reductionOpName.contains("add"))
return 0;
- if (reductionOpName.contains("multiply") || reductionOpName.contains("and"))
+ if (reductionOpName.contains("multiply") || reductionOpName.contains("and") || reductionOpName.contains("eqv"))
return 1;
TODO(loc, "Reduction of some intrinsic operators is not supported");
}
@@ -1120,14 +1120,19 @@ static int getOperationIdentity(llvm::StringRef reductionOpName,
static Value getReductionInitValue(mlir::Location loc, mlir::Type type,
llvm::StringRef reductionOpName,
fir::FirOpBuilder &builder) {
- assert(type.isIntOrIndexOrFloat() &&
- "only integer and float types are currently supported");
if (type.isa<FloatType>())
return builder.create<mlir::arith::ConstantOp>(
loc, type,
builder.getFloatAttr(
type, (double)getOperationIdentity(reductionOpName, loc)));
+ if (type.isa<fir::LogicalType>()) {
+ Value intConst = builder.create<mlir::arith::ConstantOp>(
+ loc, builder.getI1Type(),
+ builder.getIntegerAttr(builder.getI1Type(),
+ getOperationIdentity(reductionOpName, loc)));
+ return builder.createConvert(loc, type, intConst);
+ }
return builder.create<mlir::arith::ConstantOp>(
loc, type,
builder.getIntegerAttr(type, getOperationIdentity(reductionOpName, loc)));
@@ -1187,9 +1192,25 @@ static omp::ReductionDeclareOp createReductionDecl(
getReductionOperation<mlir::arith::MulFOp, mlir::arith::MulIOp>(
builder, type, loc, op1, op2);
break;
- case Fortran::parser::DefinedOperator::IntrinsicOperator::AND:
- reductionOp = builder.create<mlir::arith::AndIOp>(loc, op1, op2);
+ case Fortran::parser::DefinedOperator::IntrinsicOperator::AND: {
+ Value op1_i1 = builder.createConvert(loc, builder.getI1Type(), op1);
+ Value op2_i1 = builder.createConvert(loc, builder.getI1Type(), op2);
+
+ Value andiOp = builder.create<mlir::arith::AndIOp>(loc, op1_i1, op2_i1);
+
+ reductionOp = builder.createConvert(loc, type, andiOp);
+ break;
+ }
+ case Fortran::parser::DefinedOperator::IntrinsicOperator::EQV: {
+ Value op1_i1 = builder.createConvert(loc, builder.getI1Type(), op1);
+ Value op2_i1 = builder.createConvert(loc, builder.getI1Type(), op2);
+
+ Value cmpiOp = builder.create<mlir::arith::CmpIOp>(
+ loc, arith::CmpIPredicate::eq, op1_i1, op2_i1);
+
+ reductionOp = builder.createConvert(loc, type, cmpiOp);
break;
+ }
default:
TODO(loc, "Reduction of some intrinsic operators is not supported");
}
@@ -1276,6 +1297,8 @@ static std::string getReductionName(
break;
case Fortran::parser::DefinedOperator::IntrinsicOperator::AND:
return "and_reduction";
+ case Fortran::parser::DefinedOperator::IntrinsicOperator::EQV:
+ return "eqv_reduction";
default:
reductionName = "other_reduction";
break;
@@ -1385,6 +1408,7 @@ static void genOMP(Fortran::lower::AbstractConverter &converter,
case Fortran::parser::DefinedOperator::IntrinsicOperator::Add:
case Fortran::parser::DefinedOperator::IntrinsicOperator::Multiply:
case Fortran::parser::DefinedOperator::IntrinsicOperator::AND:
+ case Fortran::parser::DefinedOperator::IntrinsicOperator::EQV:
break;
default:
@@ -1401,8 +1425,11 @@ static void genOMP(Fortran::lower::AbstractConverter &converter,
symVal.getType().cast<fir::ReferenceType>().getEleTy();
reductionVars.push_back(symVal);
if (redType.isa<fir::LogicalType>())
- redType = firOpBuilder.getI1Type();
- if (redType.isIntOrIndexOrFloat()) {
+ decl = createReductionDecl(
+ firOpBuilder,
+ getReductionName(intrinsicOp, firOpBuilder.getI1Type()),
+ intrinsicOp, redType, currentLocation);
+ else if (redType.isIntOrIndexOrFloat()) {
decl = createReductionDecl(
firOpBuilder, getReductionName(intrinsicOp, redType),
intrinsicOp, redType, currentLocation);
@@ -2105,6 +2132,7 @@ void Fortran::lower::genOpenMPReduction(
case Fortran::parser::DefinedOperator::IntrinsicOperator::Add:
case Fortran::parser::DefinedOperator::IntrinsicOperator::Multiply:
case Fortran::parser::DefinedOperator::IntrinsicOperator::AND:
+ case Fortran::parser::DefinedOperator::IntrinsicOperator::EQV:
break;
default:
continue;
@@ -2116,9 +2144,7 @@ void Fortran::lower::genOpenMPReduction(
mlir::Value reductionVal = converter.getSymbolAddress(*symbol);
mlir::Type reductionType =
reductionVal.getType().cast<fir::ReferenceType>().getEleTy();
-
- if (intrinsicOp !=
- Fortran::parser::DefinedOperator::IntrinsicOperator::AND) {
+ if (!reductionType.isa<fir::LogicalType>()) {
if (!reductionType.isIntOrIndexOrFloat())
continue;
}
@@ -2126,8 +2152,7 @@ void Fortran::lower::genOpenMPReduction(
if (auto loadOp = mlir::dyn_cast<fir::LoadOp>(
reductionValUse.getOwner())) {
mlir::Value loadVal = loadOp.getRes();
- if (intrinsicOp == Fortran::parser::DefinedOperator::
- IntrinsicOperator::AND) {
+ if (reductionType.isa<fir::LogicalType>()) {
mlir::Operation *reductionOp = findReductionChain(loadVal);
fir::ConvertOp convertOp =
getConvertFromReductionOp(reductionOp, loadVal);
diff --git a/flang/test/Fir/convert-to-llvm-openmp-and-fir.fir b/flang/test/Fir/convert-to-llvm-openmp-and-fir.fir
index 3a848d121396..ee94ac19accd 100644
--- a/flang/test/Fir/convert-to-llvm-openmp-and-fir.fir
+++ b/flang/test/Fir/convert-to-llvm-openmp-and-fir.fir
@@ -485,3 +485,72 @@ func.func @_QPsb() {
// CHECK: }
// CHECK: llvm.return
// CHECK: }
+
+// -----
+
+// CHECK: omp.reduction.declare @[[EQV_REDUCTION:.*]] : i32 init {
+// CHECK: ^bb0(%{{.*}}: i32):
+// CHECK: %[[TRUE:.*]] = llvm.mlir.constant(true) : i1
+// CHECK: %[[TRUE_EXT:.*]] = llvm.zext %[[TRUE]] : i1 to i32
+// CHECK: omp.yield(%[[TRUE_EXT]] : i32)
+// CHECK: } combiner {
+// CHECK: ^bb0(%[[ARG_1:.*]]: i32, %[[ARG_2:.*]]: i32):
+// CHECK: %[[ZERO_1:.*]] = llvm.mlir.constant(0 : i64) : i32
+// CHECK: %[[ARGVAL_1:.*]] = llvm.icmp "ne" %[[ARG_1]], %[[ZERO_1]] : i32
+// CHECK: %[[ZERO_2:.*]] = llvm.mlir.constant(0 : i64) : i32
+// CHECK: %[[ARGVAL_2:.*]] = llvm.icmp "ne" %[[ARG_2]], %[[ZERO_2]] : i32
+// CHECK: %[[RES:.*]] = llvm.icmp "eq" %[[ARGVAL_1]], %[[ARGVAL_2]] : i1
+// CHECK: %[[RES_EXT:.*]] = llvm.zext %[[RES]] : i1 to i32
+// CHECK: omp.yield(%[[RES_EXT]] : i32)
+// CHECK: }
+// CHECK-LABEL: @_QPsimple_reduction
+// CHECK-SAME: %[[ARRAY_REF:.*]]: !llvm.ptr<array<100 x i32>>
+// CHECK: %[[RED_ACCUMULATOR:.*]] = llvm.alloca %2 x i32 {bindc_name = "x", in_type = !fir.logical<4>, operand_segment_sizes = array<i32: 0, 0>, uniq_name = "_QFsimple_reductionEx"} : (i64) -> !llvm.ptr<i32>
+// CHECK: omp.parallel {
+// CHECK: omp.wsloop reduction(@[[EQV_REDUCTION]] -> %[[RED_ACCUMULATOR]] : !llvm.ptr<i32>) for
+// CHECK: %[[ARRAY_ELEM_REF:.*]] = llvm.getelementptr %[[ARRAY_REF]][0, %{{.*}}] : (!llvm.ptr<array<100 x i32>>, i64) -> !llvm.ptr<i32>
+// CHECK: %[[ARRAY_ELEM:.*]] = llvm.load %[[ARRAY_ELEM_REF]] : !llvm.ptr<i32>
+// CHECK: omp.reduction %[[ARRAY_ELEM]], %[[RED_ACCUMULATOR]] : i32, !llvm.ptr<i32>
+// CHECK: omp.yield
+// CHECK: omp.terminator
+// CHECK: llvm.return
+
+omp.reduction.declare @eqv_reduction : !fir.logical<4> init {
+^bb0(%arg0: !fir.logical<4>):
+ %true = arith.constant true
+ %0 = fir.convert %true : (i1) -> !fir.logical<4>
+ omp.yield(%0 : !fir.logical<4>)
+} combiner {
+^bb0(%arg0: !fir.logical<4>, %arg1: !fir.logical<4>):
+ %0 = fir.convert %arg0 : (!fir.logical<4>) -> i1
+ %1 = fir.convert %arg1 : (!fir.logical<4>) -> i1
+ %2 = arith.cmpi eq, %0, %1 : i1
+ %3 = fir.convert %2 : (i1) -> !fir.logical<4>
+ omp.yield(%3 : !fir.logical<4>)
+}
+func.func @_QPsimple_reduction(%arg0: !fir.ref<!fir.array<100x!fir.logical<4>>> {fir.bindc_name = "y"}) {
+ %0 = fir.alloca i32 {bindc_name = "i", uniq_name = "_QFsimple_reductionEi"}
+ %1 = fir.alloca !fir.logical<4> {bindc_name = "x", uniq_name = "_QFsimple_reductionEx"}
+ %true = arith.constant true
+ %2 = fir.convert %true : (i1) -> !fir.logical<4>
+ fir.store %2 to %1 : !fir.ref<!fir.logical<4>>
+ omp.parallel {
+ %3 = fir.alloca i32 {adapt.valuebyref, pinned}
+ %c1_i32 = arith.constant 1 : i32
+ %c100_i32 = arith.constant 100 : i32
+ %c1_i32_0 = arith.constant 1 : i32
+ omp.wsloop reduction(@eqv_reduction -> %1 : !fir.ref<!fir.logical<4>>) for (%arg1) : i32 = (%c1_i32) to (%c100_i32) inclusive step (%c1_i32_0) {
+ fir.store %arg1 to %3 : !fir.ref<i32>
+ %4 = fir.load %3 : !fir.ref<i32>
+ %5 = fir.convert %4 : (i32) -> i64
+ %c1_i64 = arith.constant 1 : i64
+ %6 = arith.subi %5, %c1_i64 : i64
+ %7 = fir.coordinate_of %arg0, %6 : (!fir.ref<!fir.array<100x!fir.logical<4>>>, i64) -> !fir.ref<!fir.logical<4>>
+ %8 = fir.load %7 : !fir.ref<!fir.logical<4>>
+ omp.reduction %8, %1 : !fir.logical<4>, !fir.ref<!fir.logical<4>>
+ omp.yield
+ }
+ omp.terminator
+ }
+ return
+}
diff --git a/flang/test/Lower/OpenMP/Todo/reduction-eqv.f90 b/flang/test/Lower/OpenMP/Todo/reduction-eqv.f90
deleted file mode 100644
index 36322e9156c6..000000000000
--- a/flang/test/Lower/OpenMP/Todo/reduction-eqv.f90
+++ /dev/null
@@ -1,15 +0,0 @@
-! RUN: %not_todo_cmd bbc -emit-fir -fopenmp -o - %s 2>&1 | FileCheck %s
-! RUN: %not_todo_cmd %flang_fc1 -emit-fir -fopenmp -o - %s 2>&1 | FileCheck %s
-
-! CHECK: not yet implemented: Reduction of some intrinsic operators is not supported
-subroutine reduction_eqv(y)
- logical :: x, y(100)
- !$omp parallel
- !$omp do reduction(.eqv.:x)
- do i=1, 100
- x = x .eqv. y(i)
- end do
- !$omp end do
- !$omp end parallel
- print *, x
-end subroutine
diff --git a/flang/test/Lower/OpenMP/wsloop-reduction-logical-and.f90 b/flang/test/Lower/OpenMP/wsloop-reduction-logical-and.f90
index 206d63d79f45..425d37398c57 100644
--- a/flang/test/Lower/OpenMP/wsloop-reduction-logical-and.f90
+++ b/flang/test/Lower/OpenMP/wsloop-reduction-logical-and.f90
@@ -2,14 +2,18 @@
! RUN: %flang_fc1 -emit-fir -fopenmp %s -o - | FileCheck %s
!CHECK-LABEL: omp.reduction.declare
-!CHECK-SAME: @[[RED_NAME:.*]] : i1 init {
-!CHECK: ^bb0(%{{.*}}: i1):
+!CHECK-SAME: @[[RED_NAME:.*]] : !fir.logical<4> init {
+!CHECK: ^bb0(%{{.*}}: !fir.logical<4>):
!CHECK: %true = arith.constant true
-!CHECK: omp.yield(%true : i1)
+!CHECK: %[[true_fir:.*]] = fir.convert %true : (i1) -> !fir.logical<4>
+!CHECK: omp.yield(%[[true_fir]] : !fir.logical<4>)
!CHECK: } combiner {
-!CHECK: ^bb0(%[[ARG0:.*]]: i1, %[[ARG1:.*]]: i1):
-!CHECK: %[[RES:.*]] = arith.andi %[[ARG0]], %[[ARG1]] : i1
-!CHECK: omp.yield(%[[RES]] : i1)
+!CHECK: ^bb0(%[[ARG0:.*]]: !fir.logical<4>, %[[ARG1:.*]]: !fir.logical<4>):
+!CHECK: %[[arg0_i1:.*]] = fir.convert %[[ARG0]] : (!fir.logical<4>) -> i1
+!CHECK: %[[arg1_i1:.*]] = fir.convert %[[ARG1]] : (!fir.logical<4>) -> i1
+!CHECK: %[[RES:.*]] = arith.andi %[[arg0_i1]], %[[arg1_i1]] : i1
+!CHECK: %[[RES_logical:.*]] = fir.convert %[[RES]] : (i1) -> !fir.logical<4>
+!CHECK: omp.yield(%[[RES_logical]] : !fir.logical<4>)
!CHECK: }
!CHECK-LABEL: func.func @_QPsimple_reduction(
diff --git a/flang/test/Lower/OpenMP/wsloop-reduction-logical-eqv.f90 b/flang/test/Lower/OpenMP/wsloop-reduction-logical-eqv.f90
new file mode 100644
index 000000000000..e8cf46f8261c
--- /dev/null
+++ b/flang/test/Lower/OpenMP/wsloop-reduction-logical-eqv.f90
@@ -0,0 +1,136 @@
+! RUN: bbc -emit-fir -fopenmp %s -o - | FileCheck %s
+! RUN: %flang_fc1 -emit-fir -fopenmp %s -o - | FileCheck %s
+
+!CHECK-LABEL: omp.reduction.declare
+!CHECK-SAME: @[[RED_NAME:.*]] : !fir.logical<4> init {
+!CHECK: ^bb0(%{{.*}}: !fir.logical<4>):
+!CHECK: %true = arith.constant true
+!CHECK: %[[true_fir:.*]] = fir.convert %true : (i1) -> !fir.logical<4>
+!CHECK: omp.yield(%[[true_fir]] : !fir.logical<4>)
+!CHECK: } combiner {
+!CHECK: ^bb0(%[[ARG0:.*]]: !fir.logical<4>, %[[ARG1:.*]]: !fir.logical<4>):
+!CHECK: %[[arg0_i1:.*]] = fir.convert %[[ARG0]] : (!fir.logical<4>) -> i1
+!CHECK: %[[arg1_i1:.*]] = fir.convert %[[ARG1]] : (!fir.logical<4>) -> i1
+!CHECK: %[[RES:.*]] = arith.cmpi eq, %[[arg0_i1]], %[[arg1_i1]] : i1
+!CHECK: %[[RES_logical:.*]] = fir.convert %[[RES]] : (i1) -> !fir.logical<4>
+!CHECK: omp.yield(%[[RES_logical]] : !fir.logical<4>)
+!CHECK: }
+
+!CHECK-LABEL: func.func @_QPsimple_reduction(
+!CHECK-SAME: %[[ARRAY:.*]]: !fir.ref<!fir.array<100x!fir.logical<4>>> {fir.bindc_name = "y"}) {
+!CHECK: %[[IREF:.*]] = fir.alloca i32 {bindc_name = "i", uniq_name = "_QFsimple_reductionEi"}
+!CHECK: %[[XREF:.*]] = fir.alloca !fir.logical<4> {bindc_name = "x", uniq_name = "_QFsimple_reductionEx"}
+!CHECK: omp.parallel
+!CHECK: %[[I_PVT_REF:.*]] = fir.alloca i32 {adapt.valuebyref, pinned}
+!CHECK: %[[C1_1:.*]] = arith.constant 1 : i32
+!CHECK: %[[C100:.*]] = arith.constant 100 : i32
+!CHECK: %[[C1_2:.*]] = arith.constant 1 : i32
+!CHECK: omp.wsloop reduction(@[[RED_NAME]] -> %[[XREF]] : !fir.ref<!fir.logical<4>>) for (%[[IVAL:.*]]) : i32 = (%[[C1_1]]) to (%[[C100]]) inclusive step (%[[C1_2]]) {
+!CHECK: fir.store %[[IVAL]] to %[[I_PVT_REF]] : !fir.ref<i32>
+!CHECK: %[[I_PVT_VAL:.*]] = fir.load %[[I_PVT_REF]] : !fir.ref<i32>
+!CHECK: %[[CONVI_64:.*]] = fir.convert %[[I_PVT_VAL]] : (i32) -> i64
+!CHECK: %[[C1_64:.*]] = arith.constant 1 : i64
+!CHECK: %[[SUBI:.*]] = arith.subi %[[CONVI_64]], %[[C1_64]] : i64
+!CHECK: %[[Y_PVT_REF:.*]] = fir.coordinate_of %[[ARRAY]], %[[SUBI]] : (!fir.ref<!fir.array<100x!fir.logical<4>>>, i64) -> !fir.ref<!fir.logical<4>>
+!CHECK: %[[YVAL:.*]] = fir.load %[[Y_PVT_REF]] : !fir.ref<!fir.logical<4>>
+!CHECK: omp.reduction %[[YVAL]], %[[XREF]] : !fir.logical<4>, !fir.ref<!fir.logical<4>>
+!CHECK: omp.yield
+!CHECK: omp.terminator
+!CHECK: return
+subroutine simple_reduction(y)
+ logical :: x, y(100)
+ x = .true.
+ !$omp parallel
+ !$omp do reduction(.eqv.:x)
+ do i=1, 100
+ x = x .eqv. y(i)
+ end do
+ !$omp end do
+ !$omp end parallel
+end subroutine
+
+!CHECK-LABEL: func.func @_QPsimple_reduction_switch_order(
+!CHECK-SAME: %[[ARRAY:.*]]: !fir.ref<!fir.array<100x!fir.logical<4>>> {fir.bindc_name = "y"}) {
+!CHECK: %[[IREF:.*]] = fir.alloca i32 {bindc_name = "i", uniq_name = "_QFsimple_reduction_switch_orderEi"}
+!CHECK: %[[XREF:.*]] = fir.alloca !fir.logical<4> {bindc_name = "x", uniq_name = "_QFsimple_reduction_switch_orderEx"}
+!CHECK: omp.parallel
+!CHECK: %[[I_PVT_REF:.*]] = fir.alloca i32 {adapt.valuebyref, pinned}
+!CHECK: %[[C1_1:.*]] = arith.constant 1 : i32
+!CHECK: %[[C100:.*]] = arith.constant 100 : i32
+!CHECK: %[[C1_2:.*]] = arith.constant 1 : i32
+!CHECK: omp.wsloop reduction(@[[RED_NAME]] -> %[[XREF]] : !fir.ref<!fir.logical<4>>) for (%[[IVAL:.*]]) : i32 = (%[[C1_1]]) to (%[[C100]]) inclusive step (%[[C1_2]]) {
+!CHECK: fir.store %[[IVAL]] to %[[I_PVT_REF]] : !fir.ref<i32>
+!CHECK: %[[I_PVT_VAL:.*]] = fir.load %[[I_PVT_REF]] : !fir.ref<i32>
+!CHECK: %[[CONVI_64:.*]] = fir.convert %[[I_PVT_VAL]] : (i32) -> i64
+!CHECK: %[[C1_64:.*]] = arith.constant 1 : i64
+!CHECK: %[[SUBI:.*]] = arith.subi %[[CONVI_64]], %[[C1_64]] : i64
+!CHECK: %[[Y_PVT_REF:.*]] = fir.coordinate_of %[[ARRAY]], %[[SUBI]] : (!fir.ref<!fir.array<100x!fir.logical<4>>>, i64) -> !fir.ref<!fir.logical<4>>
+!CHECK: %[[YVAL:.*]] = fir.load %[[Y_PVT_REF]] : !fir.ref<!fir.logical<4>>
+!CHECK: omp.reduction %[[YVAL]], %[[XREF]] : !fir.logical<4>, !fir.ref<!fir.logical<4>>
+!CHECK: omp.yield
+!CHECK: omp.terminator
+!CHECK: return
+subroutine simple_reduction_switch_order(y)
+ logical :: x, y(100)
+ x = .true.
+ !$omp parallel
+ !$omp do reduction(.eqv.:x)
+ do i=1, 100
+ x = y(i) .eqv. x
+ end do
+ !$omp end do
+ !$omp end parallel
+end subroutine
+
+!CHECK-LABEL: func.func @_QPmultiple_reductions
+!CHECK-SAME %[[ARRAY:.*]]: !fir.ref<!fir.array<100x!fir.logical<4>>> {fir.bindc_name = "w"}) {
+!CHECK: %[[IREF:.*]] = fir.alloca i32 {bindc_name = "i", uniq_name = "_QFmultiple_reductionsEi"}
+!CHECK: %[[XREF:.*]] = fir.alloca !fir.logical<4> {bindc_name = "x", uniq_name = "_QFmultiple_reductionsEx"}
+!CHECK: %[[YREF:.*]] = fir.alloca !fir.logical<4> {bindc_name = "y", uniq_name = "_QFmultiple_reductionsEy"}
+!CHECK: %[[ZREF:.*]] = fir.alloca !fir.logical<4> {bindc_name = "z", uniq_name = "_QFmultiple_reductionsEz"}
+!CHECK: omp.parallel
+!CHECK: %[[I_PVT_REF:.*]] = fir.alloca i32 {adapt.valuebyref, pinned}
+!CHECK: %[[C1_1:.*]] = arith.constant 1 : i32
+!CHECK: %[[C100:.*]] = arith.constant 100 : i32
+!CHECK: %[[C1_2:.*]] = arith.constant 1 : i32
+!CHECK: omp.wsloop reduction(@[[RED_NAME]] -> %[[XREF]] : !fir.ref<!fir.logical<4>>, @[[RED_NAME]] -> %[[YREF]] : !fir.ref<!fir.logical<4>>, @[[RED_NAME]] -> %[[ZREF]] : !fir.ref<!fir.logical<4>>) for (%[[IVAL:.*]]) : i32 = (%[[C1_1]]) to (%[[C100]]) inclusive step (%[[C1_2]]) {
+!CHECK: fir.store %[[IVAL]] to %[[I_PVT_REF]] : !fir.ref<i32>
+!CHECK: %[[I_PVT_VAL1:.*]] = fir.load %[[I_PVT_REF]] : !fir.ref<i32>
+!CHECK: %[[CONVI_64_1:.*]] = fir.convert %[[I_PVT_VAL1]] : (i32) -> i64
+!CHECK: %[[C1_64:.*]] = arith.constant 1 : i64
+!CHECK: %[[SUBI_1:.*]] = arith.subi %[[CONVI_64_1]], %[[C1_64]] : i64
+!CHECK: %[[W_PVT_REF_1:.*]] = fir.coordinate_of %[[ARRAY]], %[[SUBI_1]] : (!fir.ref<!fir.array<100x!fir.logical<4>>>, i64) -> !fir.ref<!fir.logical<4>>
+!CHECK: %[[WVAL:.*]] = fir.load %[[W_PVT_REF_1]] : !fir.ref<!fir.logical<4>>
+!CHECK: omp.reduction %[[WVAL]], %[[XREF]] : !fir.logical<4>, !fir.ref<!fir.logical<4>>
+!CHECK: %[[I_PVT_VAL2:.*]] = fir.load %[[I_PVT_REF]] : !fir.ref<i32>
+!CHECK: %[[CONVI_64_2:.*]] = fir.convert %[[I_PVT_VAL2]] : (i32) -> i64
+!CHECK: %[[C1_64:.*]] = arith.constant 1 : i64
+!CHECK: %[[SUBI_2:.*]] = arith.subi %[[CONVI_64_2]], %[[C1_64]] : i64
+!CHECK: %[[W_PVT_REF_2:.*]] = fir.coordinate_of %[[ARRAY]], %[[SUBI_2]] : (!fir.ref<!fir.array<100x!fir.logical<4>>>, i64) -> !fir.ref<!fir.logical<4>>
+!CHECK: %[[WVAL:.*]] = fir.load %[[W_PVT_REF_2]] : !fir.ref<!fir.logical<4>>
+!CHECK: omp.reduction %[[WVAL]], %[[YREF]] : !fir.logical<4>, !fir.ref<!fir.logical<4>>
+!CHECK: %[[I_PVT_VAL3:.*]] = fir.load %[[I_PVT_REF]] : !fir.ref<i32>
+!CHECK: %[[CONVI_64_3:.*]] = fir.convert %[[I_PVT_VAL3]] : (i32) -> i64
+!CHECK: %[[C1_64:.*]] = arith.constant 1 : i64
+!CHECK: %[[SUBI_3:.*]] = arith.subi %[[CONVI_64_3]], %[[C1_64]] : i64
+!CHECK: %[[W_PVT_REF_3:.*]] = fir.coordinate_of %[[ARRAY]], %[[SUBI_3]] : (!fir.ref<!fir.array<100x!fir.logical<4>>>, i64) -> !fir.ref<!fir.logical<4>>
+!CHECK: %[[WVAL:.*]] = fir.load %[[W_PVT_REF_3]] : !fir.ref<!fir.logical<4>>
+!CHECK: omp.reduction %[[WVAL]], %[[ZREF]] : !fir.logical<4>, !fir.ref<!fir.logical<4>>
+!CHECK: omp.yield
+!CHECK: omp.terminator
+!CHECK: return
+subroutine multiple_reductions(w)
+ logical :: x,y,z,w(100)
+ x = .true.
+ y = .true.
+ z = .true.
+ !$omp parallel
+ !$omp do reduction(.eqv.:x,y,z)
+ do i=1, 100
+ x = x .eqv. w(i)
+ y = y .eqv. w(i)
+ z = z .eqv. w(i)
+ end do
+ !$omp end do
+ !$omp end parallel
+end subroutine
diff --git a/mlir/lib/Conversion/OpenMPToLLVM/OpenMPToLLVM.cpp b/mlir/lib/Conversion/OpenMPToLLVM/OpenMPToLLVM.cpp
index 4e38aaf53aa3..6d66149b7dce 100644
--- a/mlir/lib/Conversion/OpenMPToLLVM/OpenMPToLLVM.cpp
+++ b/mlir/lib/Conversion/OpenMPToLLVM/OpenMPToLLVM.cpp
@@ -121,6 +121,23 @@ struct RegionOpWithVarOperandsConversion : public ConvertOpToLLVMPattern<T> {
}
};
+template <typename T>
+struct RegionLessOpConversion : public ConvertOpToLLVMPattern<T> {
+ using ConvertOpToLLVMPattern<T>::ConvertOpToLLVMPattern;
+ LogicalResult
+ matchAndRewrite(T curOp, typename T::Adaptor adaptor,
+ ConversionPatternRewriter &rewriter) const override {
+ TypeConverter *converter = ConvertToLLVMPattern::getTypeConverter();
+ SmallVector<Type> resTypes;
+ if (failed(converter->convertTypes(curOp->getResultTypes(), resTypes)))
+ return failure();
+
+ rewriter.replaceOpWithNewOp<T>(curOp, resTypes, adaptor.getOperands(),
+ curOp->getAttrs());
+ return success();
+ }
+};
+
struct ReductionOpConversion : public ConvertOpToLLVMPattern<omp::ReductionOp> {
using ConvertOpToLLVMPattern<omp::ReductionOp>::ConvertOpToLLVMPattern;
LogicalResult
@@ -147,6 +164,29 @@ struct LegalizeDataOpForLLVMTranslation : public ConvertOpToLLVMPattern<Op> {
return success();
}
};
+
+struct ReductionDeclareOpConversion
+ : public ConvertOpToLLVMPattern<omp::ReductionDeclareOp> {
+ using ConvertOpToLLVMPattern<omp::ReductionDeclareOp>::ConvertOpToLLVMPattern;
+ LogicalResult
+ matchAndRewrite(omp::ReductionDeclareOp curOp, OpAdaptor adaptor,
+ ConversionPatternRewriter &rewriter) const override {
+ auto newOp = rewriter.create<omp::ReductionDeclareOp>(
+ curOp.getLoc(), TypeRange(), curOp.getSymNameAttr(),
+ TypeAttr::get(this->getTypeConverter()->convertType(
+ curOp.getTypeAttr().getValue())));
+ for (unsigned idx = 0; idx < curOp.getNumRegions(); idx++) {
+ rewriter.inlineRegionBefore(curOp.getRegion(idx), newOp.getRegion(idx),
+ newOp.getRegion(idx).end());
+ if (failed(rewriter.convertRegionTypes(&newOp.getRegion(idx),
+ *this->getTypeConverter())))
+ return failure();
+ }
+
+ rewriter.eraseOp(curOp);
+ return success();
+ }
+};
} // namespace
void mlir::configureOpenMPToLLVMConversionLegality(
@@ -160,17 +200,25 @@ void mlir::configureOpenMPToLLVMConversionLegality(
typeConverter.isLegal(op->getOperandTypes()) &&
typeConverter.isLegal(op->getResultTypes());
});
- target
- .addDynamicallyLegalOp<mlir::omp::AtomicReadOp, mlir::omp::AtomicWriteOp,
- mlir::omp::FlushOp, mlir::omp::ThreadprivateOp,
- mlir::omp::EnterDataOp, mlir::omp::ExitDataOp>(
- [&](Operation *op) {
- return typeConverter.isLegal(op->getOperandTypes()) &&
- typeConverter.isLegal(op->getResultTypes());
- });
+ target.addDynamicallyLegalOp<mlir::omp::AtomicReadOp,
+ mlir::omp::AtomicWriteOp, mlir::omp::FlushOp,
+ mlir::omp::ThreadprivateOp, mlir::omp::YieldOp,
+ mlir::omp::EnterDataOp, mlir::omp::ExitDataOp>(
+ [&](Operation *op) {
+ return typeConverter.isLegal(op->getOperandTypes()) &&
+ typeConverter.isLegal(op->getResultTypes());
+ });
target.addDynamicallyLegalOp<mlir::omp::ReductionOp>([&](Operation *op) {
return typeConverter.isLegal(op->getOperandTypes());
});
+ target.addDynamicallyLegalOp<mlir::omp::ReductionDeclareOp>(
+ [&](Operation *op) {
+ return typeConverter.isLegal(&op->getRegion(0)) &&
+ typeConverter.isLegal(&op->getRegion(1)) &&
+ typeConverter.isLegal(&op->getRegion(2)) &&
+ typeConverter.isLegal(op->getOperandTypes()) &&
+ typeConverter.isLegal(op->getResultTypes());
+ });
}
void mlir::populateOpenMPToLLVMConversionPatterns(LLVMTypeConverter &converter,
@@ -179,8 +227,8 @@ void mlir::populateOpenMPToLLVMConversionPatterns(LLVMTypeConverter &converter,
LegalizeDataOpForLLVMTranslation<omp::DataOp>,
LegalizeDataOpForLLVMTranslation<omp::EnterDataOp>,
LegalizeDataOpForLLVMTranslation<omp::ExitDataOp>, ReductionOpConversion,
- RegionOpConversion<omp::CriticalOp>, RegionOpConversion<omp::MasterOp>,
- ReductionOpConversion, RegionOpConversion<omp::MasterOp>,
+ ReductionDeclareOpConversion, RegionOpConversion<omp::CriticalOp>,
+ RegionOpConversion<omp::MasterOp>, ReductionOpConversion,
RegionOpConversion<omp::ParallelOp>, RegionOpConversion<omp::WsLoopOp>,
RegionOpConversion<omp::SectionsOp>, RegionOpConversion<omp::SectionOp>,
RegionOpConversion<omp::SimdLoopOp>, RegionOpConversion<omp::SingleOp>,
@@ -189,7 +237,8 @@ void mlir::populateOpenMPToLLVMConversionPatterns(LLVMTypeConverter &converter,
RegionLessOpWithVarOperandsConversion<omp::AtomicWriteOp>,
RegionOpWithVarOperandsConversion<omp::AtomicUpdateOp>,
RegionLessOpWithVarOperandsConversion<omp::FlushOp>,
- RegionLessOpWithVarOperandsConversion<omp::ThreadprivateOp>>(converter);
+ RegionLessOpWithVarOperandsConversion<omp::ThreadprivateOp>,
+ RegionLessOpConversion<omp::YieldOp>>(converter);
}
namespace {
diff --git a/mlir/test/Conversion/OpenMPToLLVM/convert-to-llvmir.mlir b/mlir/test/Conversion/OpenMPToLLVM/convert-to-llvmir.mlir
index 9db9e49859d8..3b683f36a870 100644
--- a/mlir/test/Conversion/OpenMPToLLVM/convert-to-llvmir.mlir
+++ b/mlir/test/Conversion/OpenMPToLLVM/convert-to-llvmir.mlir
@@ -256,3 +256,66 @@ llvm.func @_QPsb() {
}
llvm.return
}
+
+// -----
+
+// CHECK: omp.reduction.declare @eqv_reduction : i32 init
+// CHECK: ^bb0(%{{.*}}: i32):
+// CHECK: %[[TRUE:.*]] = llvm.mlir.constant(true) : i1
+// CHECK: %[[TRUE_EXT:.*]] = llvm.zext %[[TRUE]] : i1 to i32
+// CHECK: omp.yield(%[[TRUE_EXT]] : i32)
+// CHECK: } combiner {
+// CHECK: ^bb0(%[[ARG_1:.*]]: i32, %[[ARG_2:.*]]: i32):
+// CHECK: %[[ZERO:.*]] = llvm.mlir.constant(0 : i64) : i32
+// CHECK: %[[CMP_1:.*]] = llvm.icmp "ne" %[[ARG_1]], %[[ZERO]] : i32
+// CHECK: %[[CMP_2:.*]] = llvm.icmp "ne" %[[ARG_2]], %[[ZERO]] : i32
+// CHECK: %[[COMBINE_VAL:.*]] = llvm.icmp "eq" %[[CMP_1]], %[[CMP_2]] : i1
+// CHECK: %[[COMBINE_VAL_EXT:.*]] = llvm.zext %[[COMBINE_VAL]] : i1 to i32
+// CHECK: omp.yield(%[[COMBINE_VAL_EXT]] : i32)
+// CHECK-LABEL: @_QPsimple_reduction
+// CHECK: %[[RED_ACCUMULATOR:.*]] = llvm.alloca %{{.*}} x i32 {bindc_name = "x", uniq_name = "_QFsimple_reductionEx"} : (i64) -> !llvm.ptr<i32>
+// CHECK: omp.parallel
+// CHECK: omp.wsloop reduction(@eqv_reduction -> %[[RED_ACCUMULATOR]] : !llvm.ptr<i32>) for
+// CHECK: omp.reduction %{{.*}}, %[[RED_ACCUMULATOR]] : i32, !llvm.ptr<i32>
+// CHECK: omp.yield
+// CHECK: omp.terminator
+// CHECK: llvm.return
+
+omp.reduction.declare @eqv_reduction : i32 init {
+^bb0(%arg0: i32):
+ %0 = llvm.mlir.constant(true) : i1
+ %1 = llvm.zext %0 : i1 to i32
+ omp.yield(%1 : i32)
+} combiner {
+^bb0(%arg0: i32, %arg1: i32):
+ %0 = llvm.mlir.constant(0 : i64) : i32
+ %1 = llvm.icmp "ne" %arg0, %0 : i32
+ %2 = llvm.icmp "ne" %arg1, %0 : i32
+ %3 = llvm.icmp "eq" %1, %2 : i1
+ %4 = llvm.zext %3 : i1 to i32
+ omp.yield(%4 : i32)
+}
+llvm.func @_QPsimple_reduction(%arg0: !llvm.ptr<array<100 x i32>> {fir.bindc_name = "y"}) {
+ %0 = llvm.mlir.constant(100 : i32) : i32
+ %1 = llvm.mlir.constant(1 : i32) : i32
+ %2 = llvm.mlir.constant(true) : i1
+ %3 = llvm.mlir.constant(1 : i64) : i64
+ %4 = llvm.alloca %3 x i32 {bindc_name = "x", uniq_name = "_QFsimple_reductionEx"} : (i64) -> !llvm.ptr<i32>
+ %5 = llvm.zext %2 : i1 to i32
+ llvm.store %5, %4 : !llvm.ptr<i32>
+ omp.parallel {
+ %6 = llvm.alloca %3 x i32 {adapt.valuebyref, in_type = i32, operand_segment_sizes = array<i32: 0, 0>, pinned} : (i64) -> !llvm.ptr<i32>
+ omp.wsloop reduction(@eqv_reduction -> %4 : !llvm.ptr<i32>) for (%arg1) : i32 = (%1) to (%0) inclusive step (%1) {
+ llvm.store %arg1, %6 : !llvm.ptr<i32>
+ %7 = llvm.load %6 : !llvm.ptr<i32>
+ %8 = llvm.sext %7 : i32 to i64
+ %9 = llvm.sub %8, %3 : i64
+ %10 = llvm.getelementptr %arg0[0, %9] : (!llvm.ptr<array<100 x i32>>, i64) -> !llvm.ptr<i32>
+ %11 = llvm.load %10 : !llvm.ptr<i32>
+ omp.reduction %11, %4 : i32, !llvm.ptr<i32>
+ omp.yield
+ }
+ omp.terminator
+ }
+ llvm.return
+}
More information about the Mlir-commits
mailing list