[flang-commits] [flang] ddc0465 - [Flang][OpenMP] Add support for logical and reduction in worksharing-loop
Dylan Fleming via flang-commits
flang-commits at lists.llvm.org
Fri Sep 9 10:30:15 PDT 2022
Author: Dylan Fleming
Date: 2022-09-09T17:29:49Z
New Revision: ddc0465369a373f2022283905fdc7677eeaf9525
URL: https://github.com/llvm/llvm-project/commit/ddc0465369a373f2022283905fdc7677eeaf9525
DIFF: https://github.com/llvm/llvm-project/commit/ddc0465369a373f2022283905fdc7677eeaf9525.diff
LOG: [Flang][OpenMP] Add support for logical and reduction in worksharing-loop
Adds support for .and. reductions with logical types.
Because arith.addi doesn'to work with fir.logical<4> types
logical<4> must be converted to i1 prior to the operation.
This means that the pattern matched by integer reductions
(load -> op -> store) will not match logical reductions.
Instead, the pattern being searched for here is
load -> convert(logical<4> to i1) -> op -> convert(i1 to logical<4>) -> store
Reviewed By: kiranchandramohan
Differential Revision: https://reviews.llvm.org/D132228
Added:
flang/test/Lower/OpenMP/wsloop-reduction-logical-and.f90
Modified:
flang/include/flang/Lower/OpenMP.h
flang/lib/Lower/OpenMP.cpp
Removed:
flang/test/Lower/OpenMP/Todo/reduction-and.f90
################################################################################
diff --git a/flang/include/flang/Lower/OpenMP.h b/flang/include/flang/Lower/OpenMP.h
index f2a46061425ac..342012f6e6236 100644
--- a/flang/include/flang/Lower/OpenMP.h
+++ b/flang/include/flang/Lower/OpenMP.h
@@ -22,6 +22,7 @@ class Operation;
namespace fir {
class FirOpBuilder;
+class ConvertOp;
} // namespace fir
namespace Fortran {
@@ -50,11 +51,11 @@ void genThreadprivateOp(AbstractConverter &, const pft::Variable &);
void genOpenMPReduction(AbstractConverter &,
const Fortran::parser::OmpClauseList &clauseList);
+mlir::Operation *findReductionChain(mlir::Value, mlir::Value * = nullptr);
+fir::ConvertOp getConvertFromReductionOp(mlir::Operation *, mlir::Value);
void updateReduction(mlir::Operation *, fir::FirOpBuilder &, mlir::Value,
- mlir::Value);
-
-mlir::Operation *getReductionInChain(mlir::Value, mlir::Value);
-
+ mlir::Value, fir::ConvertOp * = nullptr);
+void removeStoreOp(mlir::Operation *, mlir::Value);
} // namespace lower
} // namespace Fortran
diff --git a/flang/lib/Lower/OpenMP.cpp b/flang/lib/Lower/OpenMP.cpp
index fe56621cf88d7..639184506b45f 100644
--- a/flang/lib/Lower/OpenMP.cpp
+++ b/flang/lib/Lower/OpenMP.cpp
@@ -850,7 +850,8 @@ static int getOperationIdentity(llvm::StringRef reductionOpName,
mlir::Location loc) {
if (reductionOpName.contains("add"))
return 0;
- else if (reductionOpName.contains("multiply"))
+ else if (reductionOpName.contains("multiply") ||
+ reductionOpName.contains("and"))
return 1;
TODO(loc, "Reduction of some intrinsic operators is not supported");
}
@@ -858,7 +859,8 @@ 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");
+ assert(type.isIntOrIndexOrFloat() &&
+ "only integer and float types are currently supported");
if (type.isa<FloatType>())
return builder.create<mlir::arith::ConstantOp>(
loc, type,
@@ -874,7 +876,8 @@ template <typename FloatOp, typename IntegerOp>
static Value getReductionOperation(fir::FirOpBuilder &builder, mlir::Type type,
mlir::Location loc, mlir::Value op1,
mlir::Value op2) {
- assert(type.isIntOrIndexOrFloat() && "only integer and float types are currently supported");
+ assert(type.isIntOrIndexOrFloat() &&
+ "only integer and float types are currently supported");
if (type.isIntOrIndex())
return builder.create<IntegerOp>(loc, op1, op2);
return builder.create<FloatOp>(loc, op1, op2);
@@ -898,7 +901,6 @@ static omp::ReductionDeclareOp createReductionDecl(
modBuilder.create<omp::ReductionDeclareOp>(loc, reductionOpName, type);
else
return decl;
-
builder.createBlock(&decl.initializerRegion(), decl.initializerRegion().end(),
{type}, {loc});
builder.setInsertionPointToEnd(&decl.initializerRegion().back());
@@ -923,6 +925,9 @@ 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);
+ break;
default:
TODO(loc, "Reduction of some intrinsic operators is not supported");
}
@@ -1007,6 +1012,8 @@ static std::string getReductionName(
case Fortran::parser::DefinedOperator::IntrinsicOperator::Multiply:
reductionName = "multiply_reduction";
break;
+ case Fortran::parser::DefinedOperator::IntrinsicOperator::AND:
+ return "and_reduction";
default:
reductionName = "other_reduction";
break;
@@ -1115,6 +1122,7 @@ static void genOMP(Fortran::lower::AbstractConverter &converter,
switch (intrinsicOp) {
case Fortran::parser::DefinedOperator::IntrinsicOperator::Add:
case Fortran::parser::DefinedOperator::IntrinsicOperator::Multiply:
+ case Fortran::parser::DefinedOperator::IntrinsicOperator::AND:
break;
default:
@@ -1130,6 +1138,8 @@ static void genOMP(Fortran::lower::AbstractConverter &converter,
mlir::Type redType =
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, redType),
@@ -1785,11 +1795,10 @@ void Fortran::lower::genOpenMPDeclarativeConstruct(
ompDeclConstruct.u);
}
-// Generate an OpenMP reduction operation. This implementation finds the chain :
-// load reduction var -> reduction_operation -> store reduction var and replaces
-// it with the reduction operation.
-// TODO: Currently assumes it is an integer addition/multiplication reduction.
-// Generalize this for various reduction operation types.
+// Generate an OpenMP reduction operation.
+// TODO: Currently assumes it is either an integer addition/multiplication
+// reduction, or a logical and reduction. Generalize this for various reduction
+// operation types.
// TODO: Generate the reduction operation during lowering instead of creating
// and removing operations since this is not a robust approach. Also, removing
// ops in the builder (instead of a rewriter) is probably not the best approach.
@@ -1814,6 +1823,7 @@ void Fortran::lower::genOpenMPReduction(
switch (intrinsicOp) {
case Fortran::parser::DefinedOperator::IntrinsicOperator::Add:
case Fortran::parser::DefinedOperator::IntrinsicOperator::Multiply:
+ case Fortran::parser::DefinedOperator::IntrinsicOperator::AND:
break;
default:
continue;
@@ -1825,16 +1835,28 @@ void Fortran::lower::genOpenMPReduction(
mlir::Value reductionVal = converter.getSymbolAddress(*symbol);
mlir::Type reductionType =
reductionVal.getType().cast<fir::ReferenceType>().getEleTy();
- if (!reductionType.isIntOrIndexOrFloat())
- continue;
+ if (intrinsicOp !=
+ Fortran::parser::DefinedOperator::IntrinsicOperator::AND) {
+ if (!reductionType.isIntOrIndexOrFloat())
+ continue;
+ }
for (mlir::OpOperand &reductionValUse : reductionVal.getUses()) {
-
- if (auto loadOp =
- mlir::dyn_cast<fir::LoadOp>(reductionValUse.getOwner())) {
+ if (auto loadOp = mlir::dyn_cast<fir::LoadOp>(
+ reductionValUse.getOwner())) {
mlir::Value loadVal = loadOp.getRes();
- if (auto reductionOp = getReductionInChain(reductionVal, loadVal)) {
- updateReduction(reductionOp, firOpBuilder, loadVal, reductionVal);
+ if (intrinsicOp == Fortran::parser::DefinedOperator::
+ IntrinsicOperator::AND) {
+ mlir::Operation *reductionOp = findReductionChain(loadVal);
+ fir::ConvertOp convertOp =
+ getConvertFromReductionOp(reductionOp, loadVal);
+ updateReduction(reductionOp, firOpBuilder, loadVal,
+ reductionVal, &convertOp);
+ removeStoreOp(reductionOp, reductionVal);
+ } else if (auto reductionOp =
+ findReductionChain(loadVal, &reductionVal)) {
+ updateReduction(reductionOp, firOpBuilder, loadVal,
+ reductionVal);
}
}
}
@@ -1846,19 +1868,20 @@ void Fortran::lower::genOpenMPReduction(
}
}
-// Checks whether loadVal is used in an operation,
-// the result of which is then stored into reductionVal.
-// If yes, then the operation corresponding to the reduction is returned.
-// loadVal is assumed to be the value of a load operation
-// reductionVal is the results of an OpenMP reduction operation.
-mlir::Operation *Fortran::lower::getReductionInChain(mlir::Value reductionVal,
- mlir::Value loadVal) {
- for (mlir::OpOperand &loadUse : loadVal.getUses()) {
- if (auto reductionOp = loadUse.getOwner()) {
+mlir::Operation *Fortran::lower::findReductionChain(mlir::Value loadVal,
+ mlir::Value *reductionVal) {
+ for (mlir::OpOperand &loadOperand : loadVal.getUses()) {
+ if (auto reductionOp = loadOperand.getOwner()) {
+ if (auto convertOp = mlir::dyn_cast<fir::ConvertOp>(reductionOp)) {
+ for (mlir::OpOperand &convertOperand : convertOp.getRes().getUses()) {
+ if (auto reductionOp = convertOperand.getOwner())
+ return reductionOp;
+ }
+ }
for (mlir::OpOperand &reductionOperand : reductionOp->getUses()) {
if (auto store =
mlir::dyn_cast<fir::StoreOp>(reductionOperand.getOwner())) {
- if (store.getMemref() == reductionVal) {
+ if (store.getMemref() == *reductionVal) {
store.erase();
return reductionOp;
}
@@ -1871,16 +1894,53 @@ mlir::Operation *Fortran::lower::getReductionInChain(mlir::Value reductionVal,
void Fortran::lower::updateReduction(mlir::Operation *op,
fir::FirOpBuilder &firOpBuilder,
- mlir::Value loadVal, mlir::Value reductionVal) {
+ mlir::Value loadVal,
+ mlir::Value reductionVal,
+ fir::ConvertOp *convertOp) {
mlir::OpBuilder::InsertPoint insertPtDel = firOpBuilder.saveInsertionPoint();
firOpBuilder.setInsertionPoint(op);
- if (op->getOperand(0) == loadVal)
- firOpBuilder.create<mlir::omp::ReductionOp>(op->getLoc(), op->getOperand(1),
- reductionVal);
+ mlir::Value reductionOp;
+ if (convertOp)
+ reductionOp = convertOp->getOperand();
+ else if (op->getOperand(0) == loadVal)
+ reductionOp = op->getOperand(1);
else
- firOpBuilder.create<mlir::omp::ReductionOp>(op->getLoc(), op->getOperand(0),
- reductionVal);
+ reductionOp = op->getOperand(0);
+ firOpBuilder.create<mlir::omp::ReductionOp>(op->getLoc(), reductionOp,
+ reductionVal);
firOpBuilder.restoreInsertionPoint(insertPtDel);
}
+
+// for a logical operator 'op' reduction X = X op Y
+// This function returns the operation responsible for converting Y from
+// fir.logical<4> to i1
+fir::ConvertOp
+Fortran::lower::getConvertFromReductionOp(mlir::Operation *reductionOp,
+ mlir::Value loadVal) {
+ for (auto reductionOperand : reductionOp->getOperands()) {
+ if (auto convertOp =
+ mlir::dyn_cast<fir::ConvertOp>(reductionOperand.getDefiningOp())) {
+ if (convertOp.getOperand() == loadVal)
+ continue;
+ return convertOp;
+ }
+ }
+ return nullptr;
+}
+
+void Fortran::lower::removeStoreOp(mlir::Operation *reductionOp,
+ mlir::Value symVal) {
+ for (auto reductionOpUse : reductionOp->getUsers()) {
+ if (auto convertReduction =
+ mlir::dyn_cast<fir::ConvertOp>(reductionOpUse)) {
+ for (auto convertReductionUse : convertReduction.getRes().getUsers()) {
+ if (auto storeOp = mlir::dyn_cast<fir::StoreOp>(convertReductionUse)) {
+ if (storeOp.getMemref() == symVal)
+ storeOp.erase();
+ }
+ }
+ }
+ }
+}
diff --git a/flang/test/Lower/OpenMP/Todo/reduction-and.f90 b/flang/test/Lower/OpenMP/Todo/reduction-and.f90
deleted file mode 100644
index 0dc34635211df..0000000000000
--- a/flang/test/Lower/OpenMP/Todo/reduction-and.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_and(y)
- logical :: x, y(100)
- !$omp parallel
- !$omp do reduction(.and.:x)
- do i=1, 100
- x = x .and. 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
new file mode 100644
index 0000000000000..6dc9977ea6d4e
--- /dev/null
+++ b/flang/test/Lower/OpenMP/wsloop-reduction-logical-and.f90
@@ -0,0 +1,133 @@
+! 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:.*]] : i1 init {
+!CHECK: ^bb0(%{{.*}}: i1):
+!CHECK: %true = arith.constant true
+!CHECK: omp.yield(%true : i1)
+!CHECK: } combiner {
+!CHECK: ^bb0(%[[ARG0:.*]]: i1, %[[ARG1:.*]]: i1):
+!CHECK: %[[RES:.*]] = arith.andi %[[ARG0]], %[[ARG1]] : i1
+!CHECK: omp.yield(%[[RES]] : i1)
+!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.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(.and.:x)
+ do i=1, 100
+ x = x .and. 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.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(.and.:x)
+ do i=1, 100
+ x = y(i) .and. 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.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.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.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(.and.:x,y,z)
+ do i=1, 100
+ x = x .and. w(i)
+ y = y .and. w(i)
+ z = z .and. w(i)
+ end do
+ !$omp end do
+ !$omp end parallel
+end subroutine
+
More information about the flang-commits
mailing list