Index: flang/lib/Lower/OpenMP.cpp =================================================================== --- flang/lib/Lower/OpenMP.cpp +++ flang/lib/Lower/OpenMP.cpp @@ -525,6 +525,18 @@ ifVal); } +static mlir::Value getSimdlenClauseOperand( + Fortran::lower::AbstractConverter &converter, + Fortran::lower::StatementContext &stmtCtx, + const Fortran::parser::OmpClause::Simdlen *simdlenClause) { + fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder(); + mlir::Location currentLocation = converter.getCurrentLocation(); + mlir::Value simdlenVal = fir::getBase(converter.genExprValue( + *Fortran::semantics::GetExpr(simdlenClause->v), stmtCtx)); + return firOpBuilder.createConvert(currentLocation, firOpBuilder.getI32Type(), + simdlenVal); +} + /* When parallel is used in a combined construct, then use this function to * create the parallel operation. It handles the parallel specific clauses * and leaves the rest for handling at the inner operations. @@ -770,7 +782,7 @@ mlir::Location currentLocation = converter.getCurrentLocation(); llvm::SmallVector<mlir::Value> lowerBound, upperBound, step, linearVars, linearStepVars, reductionVars; - mlir::Value scheduleChunkClauseOperand, ifClauseOperand; + mlir::Value scheduleChunkClauseOperand, ifClauseOperand, simdlenClauseOperand; mlir::Attribute scheduleClauseOperand, noWaitClauseOperand, orderedClauseOperand, orderClauseOperand; Fortran::lower::StatementContext stmtCtx; @@ -841,6 +853,11 @@ } else if (const auto &ifClause = std::get_if<Fortran::parser::OmpClause::If>(&clause.u)) { ifClauseOperand = getIfClauseOperand(converter, stmtCtx, ifClause); + } else if (const auto &simdlenClause = + std::get_if<Fortran::parser::OmpClause::Simdlen>( + &clause.u)) { + simdlenClauseOperand = + getSimdlenClauseOperand(converter, stmtCtx, simdlenClause); } } @@ -862,7 +879,8 @@ TypeRange resultType; auto SimdLoopOp = firOpBuilder.create<mlir::omp::SimdLoopOp>( currentLocation, resultType, lowerBound, upperBound, step, - ifClauseOperand, /*inclusive=*/firOpBuilder.getUnitAttr()); + ifClauseOperand, simdlenClauseOperand, + /*inclusive=*/firOpBuilder.getUnitAttr()); createBodyOfOp<omp::SimdLoopOp>(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,21 @@ 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: %[[COND:.*]] = arith.constant 2 : i32 + ! CHECK: omp.simdloop simdlen(%[[COND:.*]]) for (%[[I:.*]]) : i32 = (%[[LB]]) to (%[[UB]]) inclusive step (%[[STEP]]) { + do i = 1, n + ! CHECK: fir.store %[[I]] to %[[LOCAL:.*]] : !fir.ref<i32> + ! CHECK: %[[LD:.*]] = fir.load %[[LOCAL]] : !fir.ref<i32> + ! CHECK: fir.call @_FortranAioOutputInteger32({{.*}}, %[[LD]]) : (!fir.ref<i8>, 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 <clauses> for (%i1, %i2) : index = (%c0, %c0) to (%c10, %c10) step (%c1, %c1) { @@ -426,12 +429,14 @@ Variadic<IntLikeType>:$upperBound, Variadic<IntLikeType>:$step, Optional<I1>:$if_expr, + Optional<I32>:$simdlen, UnitAttr:$inclusive ); let regions = (region AnyRegion:$region); let assemblyFormat = [{ oilist(`if` `(` $if_expr `)` + |`simdlen` `(` $simdlen `)` ) `for` custom<LoopControl>($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,12 @@ llvm::CanonicalLoopInfo *loopInfo = ompBuilder->collapseLoops(ompLoc.DL, loopInfos, {}); - ompBuilder->applySimd(loopInfo, nullptr); + llvm::ConstantInt *simdlen = nullptr; + if (auto simdlenVar = loop.simdlen()) + simdlen = dyn_cast_or_null<llvm::ConstantInt>( + moduleTranslation.lookupValue(simdlenVar)); + + 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 @@ -197,7 +197,7 @@ "omp.simdloop" (%lb, %ub, %step) ({ ^bb0(%iv: index): omp.yield - }) {operand_segment_sizes = dense<[1,1,1,0]> : vector<4xi32>} : + }) {operand_segment_sizes = dense<[1,1,1,0,0]> : vector<5xi32>} : (index, index, i32) -> () return Index: mlir/test/Dialect/OpenMP/ops.mlir =================================================================== --- mlir/test/Dialect/OpenMP/ops.mlir +++ mlir/test/Dialect/OpenMP/ops.mlir @@ -333,7 +333,7 @@ "omp.simdloop" (%lb, %ub, %step) ({ ^bb0(%iv: index): omp.yield - }) {operand_segment_sizes = dense<[1,1,1,0]> : vector<4xi32>} : + }) {operand_segment_sizes = dense<[1,1,1,0,0]> : vector<5xi32>} : (index, index, index) -> () return @@ -357,6 +357,15 @@ return } +// CHECK-LABEL: omp_simdloop_pretty_simdlen +func.func @omp_simdloop_pretty_simdlen(%lb : index, %ub : index, %step : index, %simdlen : i32) -> () { + // CHECK: omp.simdloop simdlen(%{{.*}}) for (%{{.*}}) : index = (%{{.*}}) to (%{{.*}}) step (%{{.*}}) + omp.simdloop simdlen(%simdlen) 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 (%{{.*}}, %{{.*}}) Index: mlir/test/Target/LLVMIR/openmp-llvm.mlir =================================================================== --- mlir/test/Target/LLVMIR/openmp-llvm.mlir +++ mlir/test/Target/LLVMIR/openmp-llvm.mlir @@ -697,7 +697,7 @@ %4 = llvm.getelementptr %arg0[%iv] : (!llvm.ptr<f32>, i64) -> !llvm.ptr<f32> llvm.store %3, %4 : !llvm.ptr<f32> omp.yield - }) {operand_segment_sizes = dense<[1,1,1,0]> : vector<4xi32>} : + }) {operand_segment_sizes = dense<[1,1,1,0,0]> : vector<5xi32>} : (i64, i64, i64) -> () llvm.return