diff --git a/flang/include/flang/Lower/PFTBuilder.h b/flang/include/flang/Lower/PFTBuilder.h --- a/flang/include/flang/Lower/PFTBuilder.h +++ b/flang/include/flang/Lower/PFTBuilder.h @@ -271,6 +271,8 @@ }}); } + bool operator==(const Evaluation &that) const { return this == &that; } + LLVM_DUMP_METHOD void dump() const; /// Return the first non-nop successor of an evaluation, possibly exiting 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 @@ -109,8 +109,35 @@ } else if (const auto &lastPrivateClause = std::get_if( &clause.u)) { - // TODO: Add lastprivate support for sections construct, simd construct - if (std::is_same_v) { + // TODO: Add lastprivate support for simd construct + if (std::is_same_v) { + if (eval == eval.parentConstruct->getLastNestedEvaluation()) { + // For `omp.sections`, lastprivatized variables occur in + // lexically final `omp.section` operation. The following FIR + // shall be generated for the same: + // + // omp.sections lastprivate(...) { + // omp.section {...} + // omp.section {...} + // omp.section { + // fir.allocate for `private`/`firstprivate` + // + // scf.if %true { + // ^%lpv_update_blk + // } + // } + // } + omp::SectionOp *sectionOp = dyn_cast(&op); + mlir::scf::IfOp ifOp = firOpBuilder.create( + sectionOp->getLoc(), + firOpBuilder.createIntegerConstant( + sectionOp->getLoc(), firOpBuilder.getIntegerType(1), 0x1), + /*else*/ false); + lastPrivBlock = &ifOp.getThenRegion().front(); + firOpBuilder.setInsertionPoint(ifOp); + insPt = firOpBuilder.saveInsertionPoint(); + } + } else if (std::is_same_v) { omp::WsLoopOp *wsLoopOp = dyn_cast(&op); mlir::Operation *lastOper = wsLoopOp->getRegion().back().getTerminator(); @@ -522,9 +549,10 @@ bool lastPrivateOp = privatizeVars(op, converter, *clauses, eval); // LastPrivatization, due to introduction of // new control flow, changes the insertion point, - // thus restore it. + // thus restore it. For `omp.section`, the current position + // of the insertion point is apt, do not revert it. // TODO: Clean up later a bit to avoid this many sets and resets. - if (lastPrivateOp) + if (lastPrivateOp && !std::is_same_v) resetBeforeTerminator(firOpBuilder, storeOp, block); } diff --git a/flang/test/Lower/OpenMP/sections.f90 b/flang/test/Lower/OpenMP/sections.f90 --- a/flang/test/Lower/OpenMP/sections.f90 +++ b/flang/test/Lower/OpenMP/sections.f90 @@ -108,3 +108,75 @@ alpha = alpha * 5 !$omp end sections end subroutine + +subroutine lastprivate() + integer :: x +!CHECK: %[[X:.*]] = fir.alloca i32 {bindc_name = "x", uniq_name = "_QFlastprivateEx"} +!CHECK: omp.sections { + !$omp sections lastprivate(x) +!CHECK: omp.section { +!CHECK: %[[PRIVATE_X:.*]] = fir.alloca i32 {bindc_name = "x", pinned, uniq_name = "_QFlastprivateEx"} +!CHECK: %[[const:.*]] = arith.constant 10 : i32 +!CHECK: %[[temp:.*]] = fir.load %1 : !fir.ref +!CHECK: %[[result:.*]] = arith.muli %c10_i32, %[[temp]] : i32 +!CHECK: fir.store %[[result]] to %[[PRIVATE_X]] : !fir.ref +!CHECK: omp.terminator +!CHECK: } + !$omp section + x = x * 10 +!CHECK: omp.section { +!CHECK: %[[PRIVATE_X:.*]] = fir.alloca i32 {bindc_name = "x", pinned, uniq_name = "_QFlastprivateEx"} +!CHECK: %[[true:.*]] = arith.constant true +!CHECK: %[[temp:.*]] = fir.load %1 : !fir.ref +!CHECK: %[[const:.*]] = arith.constant 1 : i32 +!CHECK: %[[result:.*]] = arith.addi %[[temp]], %[[const]] : i32 +!CHECK: fir.store %[[result]] to %[[PRIVATE_X]] : !fir.ref +!CHECK: scf.if %[[true]] { +!CHECK: %[[temp:.*]] = fir.load %1 : !fir.ref +!CHECK: fir.store %[[temp]] to %[[X]] : !fir.ref +!CHECK: } +!CHECK: omp.terminator +!CHECK: } + !$omp section + x = x + 1 +!CHECK: omp.terminator +!CHECK: } + !$omp end sections + +!CHECK: omp.sections { + !$omp sections firstprivate(x) lastprivate(x) +!CHECK: omp.section { +!CHECK: %[[PRIVATE_X:.*]] = fir.alloca i32 {bindc_name = "x", pinned, uniq_name = "_QFlastprivateEx"} +!CHECK: %[[temp:.*]] = fir.load %[[X]] : !fir.ref +!CHECK: fir.store %[[temp]] to %[[PRIVATE_X]] : !fir.ref +!CHECK: omp.barrier +!CHECK: %[[const:.*]] = arith.constant 10 : i32 +!CHECK: %[[temp:.*]] = fir.load %1 : !fir.ref +!CHECK: %[[result:.*]] = arith.muli %c10_i32, %[[temp]] : i32 +!CHECK: fir.store %[[result]] to %[[PRIVATE_X]] : !fir.ref +!CHECK: omp.terminator +!CHECK: } + !$omp section + x = x * 10 +!CHECK: omp.section { +!CHECK: %[[PRIVATE_X:.*]] = fir.alloca i32 {bindc_name = "x", pinned, uniq_name = "_QFlastprivateEx"} +!CHECK: %[[temp:.*]] = fir.load %[[X]] : !fir.ref +!CHECK: fir.store %[[temp]] to %[[PRIVATE_X]] : !fir.ref +!CHECK: omp.barrier +!CHECK: %[[true:.*]] = arith.constant true +!CHECK: %[[temp:.*]] = fir.load %[[PRIVATE_X]] : !fir.ref +!CHECK: %[[const:.*]] = arith.constant 1 : i32 +!CHECK: %[[result:.*]] = arith.addi %[[temp]], %[[const]] : i32 +!CHECK: fir.store %[[result]] to %[[PRIVATE_X]] : !fir.ref +!CHECK: scf.if %true { +!CHECK: %[[temp:.*]] = fir.load %1 : !fir.ref +!CHECK: fir.store %[[temp]] to %[[X]] : !fir.ref +!CHECK: } +!CHECK: omp.terminator +!CHECK: } + !$omp section + x = x + 1 +!CHECK: omp.terminator +!CHECK: } + !$omp end sections +end subroutine