[flang][OpenMP] Lowering for task construct

This patch adds lowering for task construct from Fortran to
`omp.task` operation in OpenMPDialect Dialect (mlir). Also added tests
for the same.

Reviewed By: kiranchandramohan, peixin

Differential Revision: https://reviews.llvm.org/D124138
This commit is contained in:
Shraiysh Vaishay 2022-05-10 10:16:06 +05:30
parent 9d2dd6d762
commit 04cb01cf10
2 changed files with 215 additions and 2 deletions

View File

@ -261,10 +261,11 @@ genOMP(Fortran::lower::AbstractConverter &converter,
Fortran::lower::StatementContext stmtCtx; Fortran::lower::StatementContext stmtCtx;
llvm::ArrayRef<mlir::Type> argTy; llvm::ArrayRef<mlir::Type> argTy;
mlir::Value ifClauseOperand, numThreadsClauseOperand; mlir::Value ifClauseOperand, numThreadsClauseOperand, finalClauseOperand,
priorityClauseOperand;
mlir::omp::ClauseProcBindKindAttr procBindKindAttr; mlir::omp::ClauseProcBindKindAttr procBindKindAttr;
SmallVector<Value> allocateOperands, allocatorOperands; SmallVector<Value> allocateOperands, allocatorOperands;
mlir::UnitAttr nowaitAttr; mlir::UnitAttr nowaitAttr, untiedAttr, mergeableAttr;
const auto &opClauseList = const auto &opClauseList =
std::get<Fortran::parser::OmpClauseList>(beginBlockDirective.t); std::get<Fortran::parser::OmpClauseList>(beginBlockDirective.t);
@ -315,6 +316,21 @@ genOMP(Fortran::lower::AbstractConverter &converter,
} else if (std::get_if<Fortran::parser::OmpClause::Threads>(&clause.u)) { } else if (std::get_if<Fortran::parser::OmpClause::Threads>(&clause.u)) {
// Nothing needs to be done for threads clause. // Nothing needs to be done for threads clause.
continue; continue;
} else if (const auto &finalClause =
std::get_if<Fortran::parser::OmpClause::Final>(&clause.u)) {
mlir::Value finalVal = fir::getBase(converter.genExprValue(
*Fortran::semantics::GetExpr(finalClause->v), stmtCtx));
finalClauseOperand = firOpBuilder.createConvert(
currentLocation, firOpBuilder.getI1Type(), finalVal);
} else if (std::get_if<Fortran::parser::OmpClause::Untied>(&clause.u)) {
untiedAttr = firOpBuilder.getUnitAttr();
} else if (std::get_if<Fortran::parser::OmpClause::Mergeable>(&clause.u)) {
mergeableAttr = firOpBuilder.getUnitAttr();
} else if (const auto &priorityClause =
std::get_if<Fortran::parser::OmpClause::Priority>(
&clause.u)) {
priorityClauseOperand = fir::getBase(converter.genExprValue(
*Fortran::semantics::GetExpr(priorityClause->v), stmtCtx));
} else { } else {
TODO(currentLocation, "OpenMP Block construct clauses"); TODO(currentLocation, "OpenMP Block construct clauses");
} }
@ -346,6 +362,13 @@ genOMP(Fortran::lower::AbstractConverter &converter,
auto orderedOp = firOpBuilder.create<mlir::omp::OrderedRegionOp>( auto orderedOp = firOpBuilder.create<mlir::omp::OrderedRegionOp>(
currentLocation, /*simd=*/nullptr); currentLocation, /*simd=*/nullptr);
createBodyOfOp<omp::OrderedRegionOp>(orderedOp, converter, currentLocation); createBodyOfOp<omp::OrderedRegionOp>(orderedOp, converter, currentLocation);
} else if (blockDirective.v == llvm::omp::OMPD_task) {
auto taskOp = firOpBuilder.create<mlir::omp::TaskOp>(
currentLocation, ifClauseOperand, finalClauseOperand, untiedAttr,
mergeableAttr, /*in_reduction_vars=*/ValueRange(),
/*in_reductions=*/nullptr, priorityClauseOperand, allocateOperands,
allocatorOperands);
createBodyOfOp(taskOp, converter, currentLocation, &opClauseList);
} else { } else {
TODO(converter.getCurrentLocation(), "Unhandled block directive"); TODO(converter.getCurrentLocation(), "Unhandled block directive");
} }

View File

@ -0,0 +1,190 @@
!RUN: %flang_fc1 -emit-fir -fopenmp %s -o - | FileCheck %s
!CHECK-LABEL: func @_QPomp_task_simple() {
subroutine omp_task_simple
!CHECK: omp.task {
!$omp task
!CHECK: fir.call @_QPfoo() : () -> ()
call foo()
!CHECK: omp.terminator
!$omp end task
end subroutine omp_task_simple
!===============================================================================
! `if` clause
!===============================================================================
!CHECK-LABEL: func @_QPomp_task_if(%{{.+}}) {
subroutine omp_task_if(bar)
logical, intent(inout) :: bar
!CHECK: omp.task if(%{{.+}}) {
!$omp task if(bar)
!CHECK: fir.call @_QPfoo() : () -> ()
call foo()
!CHECK: omp.terminator
!$omp end task
end subroutine omp_task_if
!===============================================================================
! `final` clause
!===============================================================================
!CHECK-LABEL: func @_QPomp_task_final(%{{.+}}) {
subroutine omp_task_final(bar)
logical, intent(inout) :: bar
!CHECK: omp.task final(%{{.+}}) {
!$omp task final(bar)
!CHECK: fir.call @_QPfoo() : () -> ()
call foo()
!CHECK: omp.terminator
!$omp end task
end subroutine omp_task_final
!===============================================================================
! `untied` clause
!===============================================================================
!CHECK-LABEL: func @_QPomp_task_untied() {
subroutine omp_task_untied()
!CHECK: omp.task untied {
!$omp task untied
!CHECK: fir.call @_QPfoo() : () -> ()
call foo()
!CHECK: omp.terminator
!$omp end task
end subroutine omp_task_untied
!===============================================================================
! `mergeable` clause
!===============================================================================
!CHECK-LABEL: func @_QPomp_task_mergeable() {
subroutine omp_task_mergeable()
!CHECK: omp.task mergeable {
!$omp task mergeable
!CHECK: fir.call @_QPfoo() : () -> ()
call foo()
!CHECK: omp.terminator
!$omp end task
end subroutine omp_task_mergeable
!===============================================================================
! `priority` clause
!===============================================================================
!CHECK-LABEL: func @_QPomp_task_priority(%{{.+}}) {
subroutine omp_task_priority(bar)
integer, intent(inout) :: bar
!CHECK: omp.task priority(%{{.+}}) {
!$omp task priority(bar)
!CHECK: fir.call @_QPfoo() : () -> ()
call foo()
!CHECK: omp.terminator
!$omp end task
end subroutine omp_task_priority
!===============================================================================
! `allocate` clause
!===============================================================================
!CHECK-LABEL: func @_QPtask_allocate
subroutine task_allocate()
use omp_lib
integer :: x
!CHECK: omp.task allocate(%{{.+}} : i32 -> %{{.+}} : !fir.ref<i32>) {
!$omp task allocate(omp_high_bw_mem_alloc: x) private(x)
!CHECK: arith.addi
x = x + 12
!CHECK: omp.terminator
!$omp end task
end subroutine task_allocate
!===============================================================================
! `private` clause
!===============================================================================
!CHECK-LABEL: func @_QPtask_private
subroutine task_private
type mytype
integer :: x
end type mytype
!CHECK: %[[int_var:.+]] = fir.alloca i32
!CHECK: %[[mytype_var:.+]] = fir.alloca !fir.type<_QFtask_privateTmytype{x:i32}>
integer :: int_var
type(mytype) :: mytype_var
!CHECK: fir.call @_QPbar(%[[int_var]], %[[mytype_var]]) : (!fir.ref<i32>, !fir.ref<!fir.type<_QFtask_privateTmytype{x:i32}>>) -> ()
call bar(int_var, mytype_var)
!CHECK: omp.task {
!$omp task private(int_var, mytype_var)
!CHECK: %[[int_var_private:.+]] = fir.alloca i32
!CHECK: %[[mytype_var_private:.+]] = fir.alloca !fir.type<_QFtask_privateTmytype{x:i32}>
!CHECK: fir.call @_QPbar(%[[int_var_private]], %[[mytype_var_private]]) : (!fir.ref<i32>, !fir.ref<!fir.type<_QFtask_privateTmytype{x:i32}>>) -> ()
call bar(int_var, mytype_var)
!CHECK: omp.terminator
!$omp end task
end subroutine task_private
!===============================================================================
! `firstprivate` clause
!===============================================================================
!CHECK-LABEL: func @_QPtask_firstprivate
subroutine task_firstprivate
type mytype
integer :: x
end type mytype
!CHECK: %[[int_var:.+]] = fir.alloca i32
!CHECK: %[[mytype_var:.+]] = fir.alloca !fir.type<_QFtask_firstprivateTmytype{x:i32}>
integer :: int_var
type(mytype) :: mytype_var
!CHECK: fir.call @_QPbaz(%[[int_var]], %[[mytype_var]]) : (!fir.ref<i32>, !fir.ref<!fir.type<_QFtask_firstprivateTmytype{x:i32}>>) -> ()
call baz(int_var, mytype_var)
!CHECK: omp.task {
!$omp task firstprivate(int_var, mytype_var)
!CHECK: %[[int_var_firstprivate:.+]] = fir.alloca i32
!CHECK: %[[int_var_load:.+]] = fir.load %[[int_var]] : !fir.ref<i32>
!CHECK: fir.store %[[int_var_load]] to %[[int_var_firstprivate]] : !fir.ref<i32>
!CHECK: %[[mytype_var_firstprivate:.+]] = fir.alloca !fir.type<_QFtask_firstprivateTmytype{x:i32}>
!CHECK: %[[mytype_var_load:.+]] = fir.load %[[mytype_var]] : !fir.ref<!fir.type<_QFtask_firstprivateTmytype{x:i32}>>
!CHECK: fir.store %[[mytype_var_load]] to %[[mytype_var_firstprivate]]
!CHECK: fir.call @_QPbaz(%[[int_var_firstprivate]], %[[mytype_var_firstprivate]]) : (!fir.ref<i32>, !fir.ref<!fir.type<_QFtask_firstprivateTmytype{x:i32}>>) -> ()
call baz(int_var, mytype_var)
!CHECK: omp.terminator
!$omp end task
end subroutine task_firstprivate
!===============================================================================
! Multiple clauses
!===============================================================================
!CHECK-LABEL: func @_QPtask_multiple_clauses
subroutine task_multiple_clauses()
use omp_lib
!CHECK: %[[x:.+]] = fir.alloca i32 {bindc_name = "x", uniq_name = "_QFtask_multiple_clausesEx"}
!CHECK: %[[y:.+]] = fir.alloca i32 {bindc_name = "y", uniq_name = "_QFtask_multiple_clausesEy"}
!CHECK: %[[z:.+]] = fir.alloca i32 {bindc_name = "z", uniq_name = "_QFtask_multiple_clausesEz"}
integer :: x, y, z
logical :: buzz
!CHECK: omp.task if(%{{.+}}) final(%{{.+}}) untied mergeable priority(%{{.+}}) allocate(%{{.+}} : i32 -> %{{.+}} : !fir.ref<i32>) {
!$omp task if(buzz) final(buzz) untied mergeable priority(z) allocate(omp_high_bw_mem_alloc: x) private(x) firstprivate(y)
!CHECK: %[[x_priv:.+]] = fir.alloca i32
!CHECK: %[[y_priv:.+]] = fir.alloca i32
!CHECK: %[[y_load:.+]] = fir.load %[[y]] : !fir.ref<i32>
!CHECK: fir.store %[[y_load]] to %[[y_priv]] : !fir.ref<i32>
!CHECK: arith.addi
x = x + 12
!CHECK: arith.subi
y = y - 12
!CHECK: omp.terminator
!$omp end task
end subroutine task_multiple_clauses