Index: flang/lib/Lower/OpenMP.cpp =================================================================== --- flang/lib/Lower/OpenMP.cpp +++ flang/lib/Lower/OpenMP.cpp @@ -1110,7 +1110,7 @@ /// 1 * x = x static int getOperationIdentity(llvm::StringRef reductionOpName, mlir::Location loc) { - if (reductionOpName.contains("add")) + if (reductionOpName.contains("add") || reductionOpName.contains("or")) return 0; if (reductionOpName.contains("multiply") || reductionOpName.contains("and")) return 1; @@ -1190,6 +1190,9 @@ case Fortran::parser::DefinedOperator::IntrinsicOperator::AND: reductionOp = builder.create(loc, op1, op2); break; + case Fortran::parser::DefinedOperator::IntrinsicOperator::OR: + reductionOp = builder.create(loc, op1, op2); + break; default: TODO(loc, "Reduction of some intrinsic operators is not supported"); } @@ -1276,6 +1279,8 @@ break; case Fortran::parser::DefinedOperator::IntrinsicOperator::AND: return "and_reduction"; + case Fortran::parser::DefinedOperator::IntrinsicOperator::OR: + return "or_reduction"; default: reductionName = "other_reduction"; break; @@ -1385,6 +1390,7 @@ case Fortran::parser::DefinedOperator::IntrinsicOperator::Add: case Fortran::parser::DefinedOperator::IntrinsicOperator::Multiply: case Fortran::parser::DefinedOperator::IntrinsicOperator::AND: + case Fortran::parser::DefinedOperator::IntrinsicOperator::OR: break; default: @@ -2105,6 +2111,7 @@ case Fortran::parser::DefinedOperator::IntrinsicOperator::Add: case Fortran::parser::DefinedOperator::IntrinsicOperator::Multiply: case Fortran::parser::DefinedOperator::IntrinsicOperator::AND: + case Fortran::parser::DefinedOperator::IntrinsicOperator::OR: break; default: continue; @@ -2117,8 +2124,10 @@ mlir::Type reductionType = reductionVal.getType().cast().getEleTy(); - if (intrinsicOp != - Fortran::parser::DefinedOperator::IntrinsicOperator::AND) { + if ((intrinsicOp != + Fortran::parser::DefinedOperator::IntrinsicOperator::AND && + intrinsicOp != + Fortran::parser::DefinedOperator::IntrinsicOperator::OR)) { if (!reductionType.isIntOrIndexOrFloat()) continue; } @@ -2127,7 +2136,9 @@ reductionValUse.getOwner())) { mlir::Value loadVal = loadOp.getRes(); if (intrinsicOp == Fortran::parser::DefinedOperator:: - IntrinsicOperator::AND) { + IntrinsicOperator::AND || + intrinsicOp == Fortran::parser::DefinedOperator:: + IntrinsicOperator::OR) { mlir::Operation *reductionOp = findReductionChain(loadVal); fir::ConvertOp convertOp = getConvertFromReductionOp(reductionOp, loadVal); Index: flang/test/Lower/OpenMP/Todo/reduction-or.f90 =================================================================== --- flang/test/Lower/OpenMP/Todo/reduction-or.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_or(y) - logical :: x, y(100) - !$omp parallel - !$omp do reduction(.or.:x) - do i=1, 100 - x = x .or. y(i) - end do - !$omp end do - !$omp end parallel - print *, x -end subroutine Index: flang/test/Lower/OpenMP/wsloop-reduction-logical-or.f90 =================================================================== --- /dev/null +++ flang/test/Lower/OpenMP/wsloop-reduction-logical-or.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: %false = arith.constant false +!CHECK: omp.yield(%false : i1) +!CHECK: } combiner { +!CHECK: ^bb0(%[[ARG0:.*]]: i1, %[[ARG1:.*]]: i1): +!CHECK: %[[RES:.*]] = arith.ori %[[ARG0]], %[[ARG1]] : i1 +!CHECK: omp.yield(%[[RES]] : i1) +!CHECK: } + +!CHECK-LABEL: func.func @_QPsimple_reduction( +!CHECK-SAME: %[[ARRAY:.*]]: !fir.ref>> {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>) for (%[[IVAL:.*]]) : i32 = (%[[C1_1]]) to (%[[C100]]) inclusive step (%[[C1_2]]) { +!CHECK: fir.store %[[IVAL]] to %[[I_PVT_REF]] : !fir.ref +!CHECK: %[[I_PVT_VAL:.*]] = fir.load %[[I_PVT_REF]] : !fir.ref +!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>>, i64) -> !fir.ref> +!CHECK: %[[YVAL:.*]] = fir.load %[[Y_PVT_REF]] : !fir.ref> +!CHECK: omp.reduction %[[YVAL]], %[[XREF]] : !fir.logical<4>, !fir.ref> +!CHECK: omp.yield +!CHECK: omp.terminator +!CHECK: return +subroutine simple_reduction(y) + logical :: x, y(100) + x = .true. + !$omp parallel + !$omp do reduction(.or.:x) + do i=1, 100 + x = x .or. 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.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>) for (%[[IVAL:.*]]) : i32 = (%[[C1_1]]) to (%[[C100]]) inclusive step (%[[C1_2]]) { +!CHECK: fir.store %[[IVAL]] to %[[I_PVT_REF]] : !fir.ref +!CHECK: %[[I_PVT_VAL:.*]] = fir.load %[[I_PVT_REF]] : !fir.ref +!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>>, i64) -> !fir.ref> +!CHECK: %[[YVAL:.*]] = fir.load %[[Y_PVT_REF]] : !fir.ref> +!CHECK: omp.reduction %[[YVAL]], %[[XREF]] : !fir.logical<4>, !fir.ref> +!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(.or.:x) + do i=1, 100 + x = y(i) .or. x + end do + !$omp end do + !$omp end parallel +end subroutine + +!CHECK-LABEL: func.func @_QPmultiple_reductions +!CHECK-SAME %[[ARRAY:.*]]: !fir.ref>> {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>, @[[RED_NAME]] -> %[[YREF]] : !fir.ref>, @[[RED_NAME]] -> %[[ZREF]] : !fir.ref>) for (%[[IVAL:.*]]) : i32 = (%[[C1_1]]) to (%[[C100]]) inclusive step (%[[C1_2]]) { +!CHECK: fir.store %[[IVAL]] to %[[I_PVT_REF]] : !fir.ref +!CHECK: %[[I_PVT_VAL1:.*]] = fir.load %[[I_PVT_REF]] : !fir.ref +!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>>, i64) -> !fir.ref> +!CHECK: %[[WVAL:.*]] = fir.load %[[W_PVT_REF_1]] : !fir.ref> +!CHECK: omp.reduction %[[WVAL]], %[[XREF]] : !fir.logical<4>, !fir.ref> +!CHECK: %[[I_PVT_VAL2:.*]] = fir.load %[[I_PVT_REF]] : !fir.ref +!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>>, i64) -> !fir.ref> +!CHECK: %[[WVAL:.*]] = fir.load %[[W_PVT_REF_2]] : !fir.ref> +!CHECK: omp.reduction %[[WVAL]], %[[YREF]] : !fir.logical<4>, !fir.ref> +!CHECK: %[[I_PVT_VAL3:.*]] = fir.load %[[I_PVT_REF]] : !fir.ref +!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>>, i64) -> !fir.ref> +!CHECK: %[[WVAL:.*]] = fir.load %[[W_PVT_REF_3]] : !fir.ref> +!CHECK: omp.reduction %[[WVAL]], %[[ZREF]] : !fir.logical<4>, !fir.ref> +!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(.or.:x,y,z) + do i=1, 100 + x = x .or. w(i) + y = y .or. w(i) + z = z .or. w(i) + end do + !$omp end do + !$omp end parallel +end subroutine +