diff --git a/flang/lib/Lower/OpenMP.cpp b/flang/lib/Lower/OpenMP.cpp --- a/flang/lib/Lower/OpenMP.cpp +++ b/flang/lib/Lower/OpenMP.cpp @@ -1112,7 +1112,7 @@ 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 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()) return builder.create( loc, type, builder.getFloatAttr( type, (double)getOperationIdentity(reductionOpName, loc))); + if (type.isa()) { + Value intConst = builder.create( + loc, builder.getI1Type(), + builder.getIntegerAttr(builder.getI1Type(), + getOperationIdentity(reductionOpName, loc))); + return builder.createConvert(loc, type, intConst); + } return builder.create( loc, type, builder.getIntegerAttr(type, getOperationIdentity(reductionOpName, loc))); @@ -1187,9 +1192,25 @@ getReductionOperation( builder, type, loc, op1, op2); break; - case Fortran::parser::DefinedOperator::IntrinsicOperator::AND: - reductionOp = builder.create(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(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( + 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 @@ 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 @@ 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 @@ symVal.getType().cast().getEleTy(); reductionVars.push_back(symVal); if (redType.isa()) - 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 @@ 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 @@ mlir::Value reductionVal = converter.getSymbolAddress(*symbol); mlir::Type reductionType = reductionVal.getType().cast().getEleTy(); - - if (intrinsicOp != - Fortran::parser::DefinedOperator::IntrinsicOperator::AND) { + if (!reductionType.isa()) { if (!reductionType.isIntOrIndexOrFloat()) continue; } @@ -2126,8 +2152,7 @@ if (auto loadOp = mlir::dyn_cast( reductionValUse.getOwner())) { mlir::Value loadVal = loadOp.getRes(); - if (intrinsicOp == Fortran::parser::DefinedOperator:: - IntrinsicOperator::AND) { + if (reductionType.isa()) { 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 --- 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 @@ // 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> +// CHECK: %[[RED_ACCUMULATOR:.*]] = llvm.alloca %2 x i32 {bindc_name = "x", in_type = !fir.logical<4>, operand_segment_sizes = array, uniq_name = "_QFsimple_reductionEx"} : (i64) -> !llvm.ptr +// CHECK: omp.parallel { +// CHECK: omp.wsloop reduction(@[[EQV_REDUCTION]] -> %[[RED_ACCUMULATOR]] : !llvm.ptr) for +// CHECK: %[[ARRAY_ELEM_REF:.*]] = llvm.getelementptr %[[ARRAY_REF]][0, %{{.*}}] : (!llvm.ptr>, i64) -> !llvm.ptr +// CHECK: %[[ARRAY_ELEM:.*]] = llvm.load %[[ARRAY_ELEM_REF]] : !llvm.ptr +// CHECK: omp.reduction %[[ARRAY_ELEM]], %[[RED_ACCUMULATOR]] : i32, !llvm.ptr +// 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.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> + 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>) for (%arg1) : i32 = (%c1_i32) to (%c100_i32) inclusive step (%c1_i32_0) { + fir.store %arg1 to %3 : !fir.ref + %4 = fir.load %3 : !fir.ref + %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>>, i64) -> !fir.ref> + %8 = fir.load %7 : !fir.ref> + omp.reduction %8, %1 : !fir.logical<4>, !fir.ref> + 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 --- 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 --- 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-and.f90 b/flang/test/Lower/OpenMP/wsloop-reduction-logical-eqv.f90 copy from flang/test/Lower/OpenMP/wsloop-reduction-logical-and.f90 copy to flang/test/Lower/OpenMP/wsloop-reduction-logical-eqv.f90 --- a/flang/test/Lower/OpenMP/wsloop-reduction-logical-and.f90 +++ b/flang/test/Lower/OpenMP/wsloop-reduction-logical-eqv.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.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( @@ -37,9 +41,9 @@ logical :: x, y(100) x = .true. !$omp parallel - !$omp do reduction(.and.:x) + !$omp do reduction(.eqv.:x) do i=1, 100 - x = x .and. y(i) + x = x .eqv. y(i) end do !$omp end do !$omp end parallel @@ -70,9 +74,9 @@ logical :: x, y(100) x = .true. !$omp parallel - !$omp do reduction(.and.:x) + !$omp do reduction(.eqv.:x) do i=1, 100 - x = y(i) .and. x + x = y(i) .eqv. x end do !$omp end do !$omp end parallel @@ -121,13 +125,12 @@ y = .true. z = .true. !$omp parallel - !$omp do reduction(.and.:x,y,z) + !$omp do reduction(.eqv.:x,y,z) do i=1, 100 - x = x .and. w(i) - y = y .and. w(i) - z = z .and. w(i) + 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 --- a/mlir/lib/Conversion/OpenMPToLLVM/OpenMPToLLVM.cpp +++ b/mlir/lib/Conversion/OpenMPToLLVM/OpenMPToLLVM.cpp @@ -121,6 +121,23 @@ } }; +template +struct RegionLessOpConversion : public ConvertOpToLLVMPattern { + using ConvertOpToLLVMPattern::ConvertOpToLLVMPattern; + LogicalResult + matchAndRewrite(T curOp, typename T::Adaptor adaptor, + ConversionPatternRewriter &rewriter) const override { + TypeConverter *converter = ConvertToLLVMPattern::getTypeConverter(); + SmallVector resTypes; + if (failed(converter->convertTypes(curOp->getResultTypes(), resTypes))) + return failure(); + + rewriter.replaceOpWithNewOp(curOp, resTypes, adaptor.getOperands(), + curOp->getAttrs()); + return success(); + } +}; + struct ReductionOpConversion : public ConvertOpToLLVMPattern { using ConvertOpToLLVMPattern::ConvertOpToLLVMPattern; LogicalResult @@ -147,6 +164,29 @@ return success(); } }; + +struct ReductionDeclareOpConversion + : public ConvertOpToLLVMPattern { + using ConvertOpToLLVMPattern::ConvertOpToLLVMPattern; + LogicalResult + matchAndRewrite(omp::ReductionDeclareOp curOp, OpAdaptor adaptor, + ConversionPatternRewriter &rewriter) const override { + auto newOp = rewriter.create( + 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 @@ typeConverter.isLegal(op->getOperandTypes()) && typeConverter.isLegal(op->getResultTypes()); }); - target - .addDynamicallyLegalOp( - [&](Operation *op) { - return typeConverter.isLegal(op->getOperandTypes()) && - typeConverter.isLegal(op->getResultTypes()); - }); + target.addDynamicallyLegalOp( + [&](Operation *op) { + return typeConverter.isLegal(op->getOperandTypes()) && + typeConverter.isLegal(op->getResultTypes()); + }); target.addDynamicallyLegalOp([&](Operation *op) { return typeConverter.isLegal(op->getOperandTypes()); }); + target.addDynamicallyLegalOp( + [&](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 @@ LegalizeDataOpForLLVMTranslation, LegalizeDataOpForLLVMTranslation, LegalizeDataOpForLLVMTranslation, ReductionOpConversion, - RegionOpConversion, RegionOpConversion, - ReductionOpConversion, RegionOpConversion, + ReductionDeclareOpConversion, RegionOpConversion, + RegionOpConversion, ReductionOpConversion, RegionOpConversion, RegionOpConversion, RegionOpConversion, RegionOpConversion, RegionOpConversion, RegionOpConversion, @@ -189,7 +237,8 @@ RegionLessOpWithVarOperandsConversion, RegionOpWithVarOperandsConversion, RegionLessOpWithVarOperandsConversion, - RegionLessOpWithVarOperandsConversion>(converter); + RegionLessOpWithVarOperandsConversion, + RegionLessOpConversion>(converter); } namespace { diff --git a/mlir/test/Conversion/OpenMPToLLVM/convert-to-llvmir.mlir b/mlir/test/Conversion/OpenMPToLLVM/convert-to-llvmir.mlir --- a/mlir/test/Conversion/OpenMPToLLVM/convert-to-llvmir.mlir +++ b/mlir/test/Conversion/OpenMPToLLVM/convert-to-llvmir.mlir @@ -256,3 +256,66 @@ } 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 +// CHECK: omp.parallel +// CHECK: omp.wsloop reduction(@eqv_reduction -> %[[RED_ACCUMULATOR]] : !llvm.ptr) for +// CHECK: omp.reduction %{{.*}}, %[[RED_ACCUMULATOR]] : i32, !llvm.ptr +// 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> {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 + %5 = llvm.zext %2 : i1 to i32 + llvm.store %5, %4 : !llvm.ptr + omp.parallel { + %6 = llvm.alloca %3 x i32 {adapt.valuebyref, in_type = i32, operand_segment_sizes = array, pinned} : (i64) -> !llvm.ptr + omp.wsloop reduction(@eqv_reduction -> %4 : !llvm.ptr) for (%arg1) : i32 = (%1) to (%0) inclusive step (%1) { + llvm.store %arg1, %6 : !llvm.ptr + %7 = llvm.load %6 : !llvm.ptr + %8 = llvm.sext %7 : i32 to i64 + %9 = llvm.sub %8, %3 : i64 + %10 = llvm.getelementptr %arg0[0, %9] : (!llvm.ptr>, i64) -> !llvm.ptr + %11 = llvm.load %10 : !llvm.ptr + omp.reduction %11, %4 : i32, !llvm.ptr + omp.yield + } + omp.terminator + } + llvm.return +}