Index: flang/lib/Lower/OpenMP.cpp =================================================================== --- flang/lib/Lower/OpenMP.cpp +++ flang/lib/Lower/OpenMP.cpp @@ -772,7 +772,7 @@ linearStepVars, reductionVars; mlir::Value scheduleChunkClauseOperand, ifClauseOperand; mlir::Attribute scheduleClauseOperand, noWaitClauseOperand, - orderedClauseOperand, orderClauseOperand; + orderedClauseOperand, orderClauseOperand, simdlenClauseOperand; Fortran::lower::StatementContext stmtCtx; const auto &loopOpClauseList = std::get( std::get(loopConstruct.t).t); @@ -841,6 +841,13 @@ } else if (const auto &ifClause = std::get_if(&clause.u)) { ifClauseOperand = getIfClauseOperand(converter, stmtCtx, ifClause); + } else if (const auto &simdlenClause = + std::get_if( + &clause.u)) { + const auto *expr = Fortran::semantics::GetExpr(simdlenClause->v); + const std::optional simdlenVal = + Fortran::evaluate::ToInt64(*expr); + simdlenClauseOperand = firOpBuilder.getI64IntegerAttr(*simdlenVal); } } @@ -862,7 +869,8 @@ TypeRange resultType; auto SimdLoopOp = firOpBuilder.create( currentLocation, resultType, lowerBound, upperBound, step, - ifClauseOperand, /*inclusive=*/firOpBuilder.getUnitAttr()); + ifClauseOperand, simdlenClauseOperand.dyn_cast_or_null(), + /*inclusive=*/firOpBuilder.getUnitAttr()); createBodyOfOp(SimdLoopOp, converter, currentLocation, eval, &loopOpClauseList, iv); return; Index: flang/test/Lower/OpenMP/simd.f90 =================================================================== --- flang/test/Lower/OpenMP/simd.f90 +++ flang/test/Lower/OpenMP/simd.f90 @@ -36,3 +36,38 @@ end do !$OMP END SIMD end subroutine + +!CHECK-LABEL: func @_QPsimdloop_with_simdlen_clause +subroutine simdloop_with_simdlen_clause(n, threshold) +integer :: i, n, threshold + !$OMP SIMD SIMDLEN(2) + ! CHECK: %[[LB:.*]] = arith.constant 1 : i32 + ! CHECK: %[[UB:.*]] = fir.load %arg0 + ! CHECK: %[[STEP:.*]] = arith.constant 1 : i32 + ! CHECK: omp.simdloop simdlen(2) for (%[[I:.*]]) : i32 = (%[[LB]]) to (%[[UB]]) inclusive step (%[[STEP]]) { + do i = 1, n + ! CHECK: fir.store %[[I]] to %[[LOCAL:.*]] : !fir.ref + ! CHECK: %[[LD:.*]] = fir.load %[[LOCAL]] : !fir.ref + ! CHECK: fir.call @_FortranAioOutputInteger32({{.*}}, %[[LD]]) : (!fir.ref, i32) -> i1 + print*, i + end do + !$OMP END SIMD +end subroutine + +!CHECK-LABEL: func @_QPsimdloop_with_simdlen_clause_from_param +subroutine simdloop_with_simdlen_clause_from_param(n, threshold) +integer :: i, n, threshold +integer, parameter :: simdlen = 2; + !$OMP SIMD SIMDLEN(simdlen) + ! CHECK: %[[LB:.*]] = arith.constant 1 : i32 + ! CHECK: %[[UB:.*]] = fir.load %arg0 + ! CHECK: %[[STEP:.*]] = arith.constant 1 : i32 + ! CHECK: omp.simdloop simdlen(2) for (%[[I:.*]]) : i32 = (%[[LB]]) to (%[[UB]]) inclusive step (%[[STEP]]) { + do i = 1, n + ! CHECK: fir.store %[[I]] to %[[LOCAL:.*]] : !fir.ref + ! CHECK: %[[LD:.*]] = fir.load %[[LOCAL]] : !fir.ref + ! CHECK: fir.call @_FortranAioOutputInteger32({{.*}}, %[[LD]]) : (!fir.ref, i32) -> i1 + print*, i + end do + !$OMP END SIMD +end subroutine Index: mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td =================================================================== --- mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td +++ mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td @@ -412,6 +412,9 @@ When an if clause is present and evaluates to false, the preferred number of iterations to be executed concurrently is one, regardless of whether a simdlen clause is speciļ¬ed. + + When a simdlen clause is present, the preferred number of iterations to be + executed concurrently is the value provided to the simdlen clause. ``` omp.simdloop for (%i1, %i2) : index = (%c0, %c0) to (%c10, %c10) step (%c1, %c1) { @@ -426,12 +429,14 @@ Variadic:$upperBound, Variadic:$step, Optional:$if_expr, + Confined, [IntPositive]>:$simdlen, UnitAttr:$inclusive ); let regions = (region AnyRegion:$region); let assemblyFormat = [{ oilist(`if` `(` $if_expr `)` + |`simdlen` `(` $simdlen `)` ) `for` custom($region, $lowerBound, $upperBound, $step, type($step), $inclusive) attr-dict }]; Index: mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp =================================================================== --- mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp +++ mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp @@ -971,7 +971,11 @@ llvm::CanonicalLoopInfo *loopInfo = ompBuilder->collapseLoops(ompLoc.DL, loopInfos, {}); - ompBuilder->applySimd(loopInfo, nullptr); + llvm::ConstantInt *simdlen = nullptr; + if (auto simdlenVar = loop.simdlen()) + simdlen = builder.getInt64(simdlenVar.getValue()); + + ompBuilder->applySimd(loopInfo, simdlen); builder.restoreIP(afterIP); return success(); Index: mlir/test/Dialect/OpenMP/invalid.mlir =================================================================== --- mlir/test/Dialect/OpenMP/invalid.mlir +++ mlir/test/Dialect/OpenMP/invalid.mlir @@ -205,6 +205,16 @@ // ----- +func.func @omp_simdloop_pretty_simdlen(%lb : index, %ub : index, %step : index) -> () { + // expected-error @below {{op attribute 'simdlen' failed to satisfy constraint: 64-bit signless integer attribute whose value is positive}} + omp.simdloop simdlen(0) for (%iv): index = (%lb) to (%ub) step (%step) { + omp.yield + } + return +} + +// ----- + // expected-error @below {{op expects initializer region with one argument of the reduction type}} omp.reduction.declare @add_f32 : f64 init { Index: mlir/test/Dialect/OpenMP/ops.mlir =================================================================== --- mlir/test/Dialect/OpenMP/ops.mlir +++ mlir/test/Dialect/OpenMP/ops.mlir @@ -357,6 +357,15 @@ return } +// CHECK-LABEL: omp_simdloop_pretty_simdlen +func.func @omp_simdloop_pretty_simdlen(%lb : index, %ub : index, %step : index) -> () { + // CHECK: omp.simdloop simdlen(2) for (%{{.*}}) : index = (%{{.*}}) to (%{{.*}}) step (%{{.*}}) + omp.simdloop simdlen(2) for (%iv): index = (%lb) to (%ub) step (%step) { + omp.yield + } + return +} + // CHECK-LABEL: omp_simdloop_pretty_multiple func.func @omp_simdloop_pretty_multiple(%lb1 : index, %ub1 : index, %step1 : index, %lb2 : index, %ub2 : index, %step2 : index) -> () { // CHECK: omp.simdloop for (%{{.*}}, %{{.*}}) : index = (%{{.*}}, %{{.*}}) to (%{{.*}}, %{{.*}}) step (%{{.*}}, %{{.*}})