diff --git a/flang/lib/Lower/OpenMP.cpp b/flang/lib/Lower/OpenMP.cpp index 8cc18bea602f..156aa89c1562 100644 --- a/flang/lib/Lower/OpenMP.cpp +++ b/flang/lib/Lower/OpenMP.cpp @@ -261,10 +261,11 @@ genOMP(Fortran::lower::AbstractConverter &converter, Fortran::lower::StatementContext stmtCtx; llvm::ArrayRef argTy; - mlir::Value ifClauseOperand, numThreadsClauseOperand; + mlir::Value ifClauseOperand, numThreadsClauseOperand, finalClauseOperand, + priorityClauseOperand; mlir::omp::ClauseProcBindKindAttr procBindKindAttr; SmallVector allocateOperands, allocatorOperands; - mlir::UnitAttr nowaitAttr; + mlir::UnitAttr nowaitAttr, untiedAttr, mergeableAttr; const auto &opClauseList = std::get(beginBlockDirective.t); @@ -315,6 +316,21 @@ genOMP(Fortran::lower::AbstractConverter &converter, } else if (std::get_if(&clause.u)) { // Nothing needs to be done for threads clause. continue; + } 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 (std::get_if(&clause.u)) { + untiedAttr = firOpBuilder.getUnitAttr(); + } else if (std::get_if(&clause.u)) { + mergeableAttr = firOpBuilder.getUnitAttr(); + } else if (const auto &priorityClause = + std::get_if( + &clause.u)) { + priorityClauseOperand = fir::getBase(converter.genExprValue( + *Fortran::semantics::GetExpr(priorityClause->v), stmtCtx)); } else { TODO(currentLocation, "OpenMP Block construct clauses"); } @@ -346,6 +362,13 @@ genOMP(Fortran::lower::AbstractConverter &converter, auto orderedOp = firOpBuilder.create( currentLocation, /*simd=*/nullptr); createBodyOfOp(orderedOp, converter, currentLocation); + } else if (blockDirective.v == llvm::omp::OMPD_task) { + auto taskOp = firOpBuilder.create( + currentLocation, ifClauseOperand, finalClauseOperand, untiedAttr, + mergeableAttr, /*in_reduction_vars=*/ValueRange(), + /*in_reductions=*/nullptr, priorityClauseOperand, allocateOperands, + allocatorOperands); + createBodyOfOp(taskOp, converter, currentLocation, &opClauseList); } else { TODO(converter.getCurrentLocation(), "Unhandled block directive"); } diff --git a/flang/test/Lower/OpenMP/task.f90 b/flang/test/Lower/OpenMP/task.f90 new file mode 100644 index 000000000000..4ad875877108 --- /dev/null +++ b/flang/test/Lower/OpenMP/task.f90 @@ -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) { + !$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, !fir.ref>) -> () + 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, !fir.ref>) -> () + 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, !fir.ref>) -> () + 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 + !CHECK: fir.store %[[int_var_load]] to %[[int_var_firstprivate]] : !fir.ref + !CHECK: %[[mytype_var_firstprivate:.+]] = fir.alloca !fir.type<_QFtask_firstprivateTmytype{x:i32}> + !CHECK: %[[mytype_var_load:.+]] = fir.load %[[mytype_var]] : !fir.ref> + !CHECK: fir.store %[[mytype_var_load]] to %[[mytype_var_firstprivate]] + !CHECK: fir.call @_QPbaz(%[[int_var_firstprivate]], %[[mytype_var_firstprivate]]) : (!fir.ref, !fir.ref>) -> () + 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) { + !$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 + !CHECK: fir.store %[[y_load]] to %[[y_priv]] : !fir.ref + + !CHECK: arith.addi + x = x + 12 + !CHECK: arith.subi + y = y - 12 + + !CHECK: omp.terminator + !$omp end task +end subroutine task_multiple_clauses