[Flang][OpenMP] Fix for unstructured regions in OpenMP constructs - 2

The following changes are made for OpenMP operations with unstructured region,
1. For combined constructs the outer operation is considered a structured
region and the inner one as the unstructured.
2. Added a condition to ensure that we create new blocks only once for nested
unstructured OpenMP constructs.

Tests are added for checking the structure of the CFG.

Note: This is part of upstreaming from the fir-dev branch of
https://github.com/flang-compiler/f18-llvm-project. Code originally reviewed
at https://github.com/flang-compiler/f18-llvm-project/pull/1394.

Reviewed By: vdonaldson, shraiysh, peixin

Differential Revision: https://reviews.llvm.org/D126375
This commit is contained in:
kiranchandramohan 2022-05-31 09:25:00 +00:00 committed by Kiran Chandramohan
parent 5a2e640eb7
commit b501503ca0
2 changed files with 209 additions and 6 deletions

View File

@ -156,7 +156,7 @@ void createEmptyRegionBlocks(
"expected terminator op");
}
}
if (eval.hasNestedEvaluations())
if (!eval.isDirective() && eval.hasNestedEvaluations())
createEmptyRegionBlocks(firOpBuilder, eval.getNestedEvaluations());
}
}
@ -179,7 +179,7 @@ createBodyOfOp(Op &op, Fortran::lower::AbstractConverter &converter,
const Fortran::parser::OmpClauseList *clauses = nullptr,
const SmallVector<const Fortran::semantics::Symbol *> &args = {},
bool outerCombined = false) {
auto &firOpBuilder = converter.getFirOpBuilder();
fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder();
// If an argument for the region is provided then create the block with that
// argument. Also update the symbol's address with the mlir argument value.
// e.g. For loops the argument is the induction variable. And all further
@ -205,13 +205,15 @@ createBodyOfOp(Op &op, Fortran::lower::AbstractConverter &converter,
} else {
firOpBuilder.createBlock(&op.getRegion());
}
auto &block = op.getRegion().back();
firOpBuilder.setInsertionPointToStart(&block);
mlir::Block &block = op.getRegion().back();
firOpBuilder.setInsertionPointToEnd(&block);
if (eval.lowerAsUnstructured())
// If it is an unstructured region and is not the outer region of a combined
// construct, create empty blocks for all evaluations.
if (eval.lowerAsUnstructured() && !outerCombined)
createEmptyRegionBlocks(firOpBuilder, eval.getNestedEvaluations());
// Ensure the block is well-formed by inserting terminators.
// Insert the terminator.
if constexpr (std::is_same_v<Op, omp::WsLoopOp>) {
mlir::ValueRange results;
firOpBuilder.create<mlir::omp::YieldOp>(loc, results);
@ -221,6 +223,7 @@ createBodyOfOp(Op &op, Fortran::lower::AbstractConverter &converter,
// Reset the insertion point to the start of the first block.
firOpBuilder.setInsertionPointToStart(&block);
// Handle privatization. Do not privatize if this is the outer operation.
if (clauses && !outerCombined)
privatizeVars(converter, *clauses);

View File

@ -105,9 +105,209 @@ subroutine ss3(n) ! nested unstructured OpenMP constructs
!$omp end parallel
end
! CHECK-LABEL: func @_QPss4{{.*}} {
! CHECK: omp.parallel {
! CHECK: omp.wsloop for (%[[ARG:.*]]) : {{.*}} {
! CHECK: cond_br %{{.*}}, ^bb1, ^bb2
! CHECK: ^bb1:
! CHECK: @_FortranAioBeginExternalListOutput
! CHECK: @_FortranAioOutputInteger32(%{{.*}}, %[[ARG]])
! CHECK: br ^bb2
! CHECK: ^bb2:
! CHECK-NEXT: omp.yield
! CHECK-NEXT: }
! CHECK: omp.terminator
! CHECK-NEXT:}
subroutine ss4(n) ! CYCLE in OpenMP wsloop constructs
!$omp parallel
do i = 1, 3
!$omp do
do j = 1, 3
if (j .eq. n) cycle
print*, 'ss4', j
enddo
!$omp end do
enddo
!$omp end parallel
end
! CHECK-LABEL: func @_QPss5() {
! CHECK: omp.parallel {
! CHECK: omp.wsloop {{.*}} {
! CHECK: br ^[[BB1:.*]]
! CHECK: ^[[BB1]]:
! CHECK: cond_br %{{.*}}, ^[[BB2:.*]], ^[[BB4:.*]]
! CHECK: ^[[BB2]]:
! CHECK: cond_br %{{.*}}, ^[[BB4]], ^[[BB3:.*]]
! CHECK: ^[[BB3]]:
! CHECK: br ^[[BB1]]
! CHECK: ^[[BB4]]:
! CHECK: omp.yield
! CHECK: }
! CHECK: omp.terminator
! CHECK: }
subroutine ss5() ! EXIT inside OpenMP wsloop (inside parallel)
integer :: x
!$omp parallel private(x)
!$omp do
do j = 1, 3
x = j * i
do k = 1, 3
if (k .eq. n) exit
x = k
x = x + k
enddo
x = j - 222
enddo
!$omp end do
!$omp end parallel
end
! CHECK-LABEL: func @_QPss6() {
! CHECK: omp.parallel {
! CHECK: br ^[[BB1_OUTER:.*]]
! CHECK: ^[[BB1_OUTER]]:
! CHECK: cond_br %{{.*}}, ^[[BB2_OUTER:.*]], ^[[BB3_OUTER:.*]]
! CHECK: ^[[BB2_OUTER]]:
! CHECK: omp.wsloop {{.*}} {
! CHECK: br ^[[BB1:.*]]
! CHECK: ^[[BB1]]:
! CHECK: cond_br %{{.*}}, ^[[BB2:.*]], ^[[BB4:.*]]
! CHECK: ^[[BB2]]:
! CHECK: cond_br %{{.*}}, ^[[BB4]], ^[[BB3:.*]]
! CHECK: ^[[BB3]]:
! CHECK: br ^[[BB1]]
! CHECK: ^[[BB4]]:
! CHECK: omp.yield
! CHECK: }
! CHECK: br ^[[BB1_OUTER]]
! CHECK: ^[[BB3_OUTER]]:
! CHECK: omp.terminator
! CHECK: }
subroutine ss6() ! EXIT inside OpenMP wsloop in a do loop (inside parallel)
integer :: x
!$omp parallel private(x)
do i = 1, 3
!$omp do
do j = 1, 3
x = j * i
do k = 1, 3
if (k .eq. n) exit
x = k
x = x + k
enddo
x = j - 222
enddo
!$omp end do
enddo
!$omp end parallel
end
! CHECK-LABEL: func @_QPss7() {
! CHECK: br ^[[BB1_OUTER:.*]]
! CHECK: ^[[BB1_OUTER]]:
! CHECK: cond_br %{{.*}}, ^[[BB2_OUTER:.*]], ^[[BB3_OUTER:.*]]
! CHECK-NEXT: ^[[BB2_OUTER:.*]]:
! CHECK: omp.parallel {
! CHECK: omp.wsloop {{.*}} {
! CHECK: br ^[[BB1:.*]]
! CHECK-NEXT: ^[[BB1]]:
! CHECK: cond_br %{{.*}}, ^[[BB2:.*]], ^[[BB4:.*]]
! CHECK-NEXT: ^[[BB2]]:
! CHECK: cond_br %{{.*}}, ^[[BB4]], ^[[BB3:.*]]
! CHECK-NEXT: ^[[BB3]]:
! CHECK: br ^bb1
! CHECK-NEXT: ^[[BB4]]:
! CHECK: omp.yield
! CHECK: }
! CHECK: omp.terminator
! CHECK: }
! CHECK: br ^[[BB1_OUTER]]
! CHECK-NEXT: ^[[BB3_OUTER]]:
! CHECK-NEXT: return
subroutine ss7() ! EXIT inside OpenMP parallel do (inside do loop)
integer :: x
do i = 1, 3
!$omp parallel do private(x)
do j = 1, 3
x = j * i
do k = 1, 3
if (k .eq. n) exit
x = k
x = x + k
enddo
enddo
!$omp end parallel do
enddo
end
! CHECK-LABEL: func @_QPss8() {
! CHECK: omp.parallel {
! CHECK: omp.wsloop {{.*}} {
! CHECK: br ^[[BB1:.*]]
! CHECK: ^[[BB1]]:
! CHECK: cond_br %{{.*}}, ^[[BB2:.*]], ^[[BB4:.*]]
! CHECK: ^[[BB2]]:
! CHECK: cond_br %{{.*}}, ^[[BB4]], ^[[BB3:.*]]
! CHECK: ^[[BB3]]:
! CHECK: br ^[[BB1]]
! CHECK: ^[[BB4]]:
! CHECK: omp.yield
! CHECK: }
! CHECK: omp.terminator
! CHECK: }
subroutine ss8() ! EXIT inside OpenMP parallel do
integer :: x
!$omp parallel do private(x)
do j = 1, 3
x = j * i
do k = 1, 3
if (k .eq. n) exit
x = k
x = x + k
enddo
enddo
!$omp end parallel do
end
! CHECK-LABEL: func @_QPss9() {
! CHECK: omp.parallel {
! CHECK-NEXT: omp.parallel {
! CHECK: br ^[[BB1:.*]]
! CHECK: ^[[BB1]]:
! CHECK: cond_br %{{.*}}, ^[[BB2:.*]], ^[[BB4:.*]]
! CHECK-NEXT: ^[[BB2]]:
! CHECK: cond_br %{{.*}}, ^[[BB4]], ^[[BB3:.*]]
! CHECK-NEXT: ^[[BB3]]:
! CHECK: br ^[[BB1]]
! CHECK-NEXT: ^[[BB4]]:
! CHECK: omp.terminator
! CHECK-NEXT: }
! CHECK: omp.terminator
! CHECK-NEXT }
! CHECK: }
subroutine ss9() ! EXIT inside OpenMP parallel (inside parallel)
integer :: x
!$omp parallel
!$omp parallel private(x)
do k = 1, 3
if (k .eq. n) exit
x = k
x = x + k
end do
!$omp end parallel
!$omp end parallel
end
! CHECK-LABEL: func @_QQmain
program p
call ss1(2)
call ss2(2)
call ss3(2)
call ss4(2)
call ss5()
call ss6()
call ss7()
call ss8()
call ss9()
end