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 @@ -1055,9 +1055,12 @@ mlir::Location currentLocation = converter.getCurrentLocation(); llvm::SmallVector lowerBound, upperBound, step, linearVars, linearStepVars, reductionVars; - mlir::Value scheduleChunkClauseOperand, ifClauseOperand; + mlir::Value scheduleChunkClauseOperand, ifClauseOperand, + grainSizeClauseOperand, numTasksClauseOperand, finalClauseOperand, + priorityClauseOperand; mlir::Attribute scheduleClauseOperand, noWaitClauseOperand, orderedClauseOperand, orderClauseOperand; + mlir::UnitAttr untiedAttr, mergeableAttr, nogroupAttr; mlir::IntegerAttr simdlenClauseOperand, safelenClauseOperand; SmallVector reductionDeclSymbols; Fortran::lower::StatementContext stmtCtx; @@ -1073,6 +1076,7 @@ converter, eval, std::get(loopConstruct.t)); } else if (llvm::omp::OMPD_do != ompDirective && + llvm::omp::OMPD_taskloop != ompDirective && llvm::omp::OMPD_simd != ompDirective) { TODO(converter.getCurrentLocation(), "Construct enclosing do loop"); } @@ -1193,6 +1197,36 @@ const std::optional safelenVal = Fortran::evaluate::ToInt64(*expr); safelenClauseOperand = firOpBuilder.getI64IntegerAttr(*safelenVal); + } // `TaskLoop` construct clauses. + else if (const auto &grainSizeClause = + std::get_if( + &clause.u)) { + const auto *expr = Fortran::semantics::GetExpr(grainSizeClause->v); + grainSizeClauseOperand = + fir::getBase(converter.genExprValue(*expr, stmtCtx)); + } else if (const auto &numTasksClause = + std::get_if( + &clause.u)) { + const auto *expr = Fortran::semantics::GetExpr(numTasksClause->v); + numTasksClauseOperand = + fir::getBase(converter.genExprValue(*expr, stmtCtx)); + } else if (std::get_if(&clause.u)) { + mergeableAttr = firOpBuilder.getUnitAttr(); + } else if (std::get_if(&clause.u)) { + untiedAttr = firOpBuilder.getUnitAttr(); + } else if (std::get_if(&clause.u)) { + nogroupAttr = firOpBuilder.getUnitAttr(); + } else if (const auto &finalClause = + std::get_if(&clause.u)) { + mlir::Value finalVal = fir::getBase(converter.genExprValue( + *Fortran::semantics::GetExpr(finalClause->v), stmtCtx)); + finalClauseOperand = firOpBuilder.createConvert( + currentLocation, firOpBuilder.getI1Type(), finalVal); + } else if (const auto &priorityClause = + std::get_if( + &clause.u)) { + priorityClauseOperand = fir::getBase(converter.genExprValue( + *Fortran::semantics::GetExpr(priorityClause->v), stmtCtx)); } } @@ -1221,6 +1255,21 @@ return; } + // TODO: Support all the clauses + if (llvm::omp::OMPD_taskloop == ompDirective) { + auto TaskLoopOp = firOpBuilder.create( + currentLocation, lowerBound, upperBound, step, + /*inclusive=*/firOpBuilder.getUnitAttr(), ifClauseOperand, + finalClauseOperand, untiedAttr, mergeableAttr, + /*in_reduction_vars*/ ValueRange(), /*in_reductions*/ nullptr, + /*reduction_vars*/ ValueRange(), + /*reductions*/ nullptr, priorityClauseOperand, + /*allocate_vars*/ ValueRange(), /*allocators_vars*/ ValueRange(), + grainSizeClauseOperand, numTasksClauseOperand, nogroupAttr); + createBodyOfOp(TaskLoopOp, converter, currentLocation, + eval, &loopOpClauseList, iv); + return; + } // FIXME: Add support for following clauses: // 1. linear // 2. order 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 @@ -297,3 +297,39 @@ // CHECK: } // CHECK: llvm.func @_QPwork() attributes {sym_visibility = "private"} // CHECK: } + +// ----- + +func.func @_QPomp_taskloop() { + %0 = fir.alloca i32 {adapt.valuebyref} + %1 = fir.alloca i32 {bindc_name = "i", uniq_name = "_QFomp_taskloopEi"} + %c1_i32 = arith.constant 1 : i32 + %c10000_i32 = arith.constant 10000 : i32 + %c1_i32_0 = arith.constant 1 : i32 + %c2_i32 = arith.constant 2 : i32 + omp.taskloop num_tasks(%c2_i32 : i32) nogroup for (%arg0) : i32 = (%c1_i32) to (%c10000_i32) inclusive step (%c1_i32_0) { + fir.store %arg0 to %0 : !fir.ref + fir.call @_QPwork(%0) : (!fir.ref) -> () + omp.terminator + } + return + } + func.func private @_QPwork(!fir.ref) + +// CHECK-LABEL: llvm.func @_QPomp_taskloop() { +// CHECK: %0 = llvm.mlir.constant(1 : i64) : i64 +// CHECK: %1 = llvm.alloca %0 x i32 {adapt.valuebyref, in_type = i32, operand_segment_sizes = array} : (i64) -> !llvm.ptr +// CHECK: %2 = llvm.mlir.constant(1 : i64) : i64 +// CHECK: %3 = llvm.alloca %2 x i32 {bindc_name = "i", in_type = i32, operand_segment_sizes = array, uniq_name = "_QFomp_taskloopEi"} : (i64) -> !llvm.ptr +// CHECK: %[[LOWER:.*]] = llvm.mlir.constant(1 : i32) : i32 +// CHECK: %[[UPPER:.*]] = llvm.mlir.constant(10000 : i32) : i32 +// CHECK: %[[STEP:.*]] = llvm.mlir.constant(1 : i32) : i32 +// CHECK: %7 = llvm.mlir.constant(2 : i32) : i32 +// CHECK: omp.taskloop num_tasks(%7 : i32) nogroup for (%arg0) : i32 = (%[[LOWER]]) to (%[[UPPER]]) inclusive step (%[[STEP]]) { +// CHECK: llvm.store %arg0, %1 : !llvm.ptr +// CHECK: llvm.call @_QPwork(%1) : (!llvm.ptr) -> () +// CHECK: omp.terminator +// CHECK: } +// CHECK: llvm.return +// CHECK: } +// CHECK: llvm.func @_QPwork(!llvm.ptr) attributes {sym_visibility = "private"} diff --git a/flang/test/Lower/OpenMP/taskloop.f90 b/flang/test/Lower/OpenMP/taskloop.f90 new file mode 100644 --- /dev/null +++ b/flang/test/Lower/OpenMP/taskloop.f90 @@ -0,0 +1,17 @@ +!RUN: %flang_fc1 -emit-fir -fopenmp %s -o - | FileCheck %s + +!CHECK-LABEL: @_QPomp_taskloop +subroutine omp_taskloop +integer i + +!CHECK: omp.taskloop num_tasks(%{{.*}} : i32) nogroup for (%{{.*}}) : i32 = (%c1_i32) to ({{.*}}) inclusive step (%{{.*}}) { + !$omp taskloop private(i) num_tasks(2) nogroup + do i=1,10000 +!CHECK: fir.store %{{.*}} to %{{.*}} : !fir.ref +!CHECK: fir.call @_QPwork(%{{.*}}) : (!fir.ref) -> () + call work(i) + end do +!CHECK: omp.terminator + !$omp end taskloop + + end subroutine