diff --git a/llvm/include/llvm/Frontend/OpenMP/OMPIRBuilder.h b/llvm/include/llvm/Frontend/OpenMP/OMPIRBuilder.h index a97deafa3683c..1f0b129f867ae 100644 --- a/llvm/include/llvm/Frontend/OpenMP/OMPIRBuilder.h +++ b/llvm/include/llvm/Frontend/OpenMP/OMPIRBuilder.h @@ -1262,12 +1262,15 @@ class OpenMPIRBuilder { /// cannot be resumed until execution of the structured /// block that is associated with the generated task is /// completed. + /// \param EventHandle If present, signifies the event handle as part of + /// the detach clause /// \param Mergeable If the given task is `mergeable` InsertPointOrErrorTy createTask(const LocationDescription &Loc, InsertPointTy AllocaIP, BodyGenCallbackTy BodyGenCB, bool Tied = true, Value *Final = nullptr, Value *IfCondition = nullptr, - SmallVector Dependencies = {}, bool Mergeable = false); + SmallVector Dependencies = {}, bool Mergeable = false, + Value *EventHandle = nullptr); /// Generator for the taskgroup construct /// diff --git a/llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp b/llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp index 1fae138b449ed..21004e6a15d49 100644 --- a/llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp +++ b/llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp @@ -1818,7 +1818,7 @@ static Value *emitTaskDependencies( OpenMPIRBuilder::InsertPointOrErrorTy OpenMPIRBuilder::createTask( const LocationDescription &Loc, InsertPointTy AllocaIP, BodyGenCallbackTy BodyGenCB, bool Tied, Value *Final, Value *IfCondition, - SmallVector Dependencies, bool Mergeable) { + SmallVector Dependencies, bool Mergeable, Value *EventHandle) { if (!updateToLocation(Loc)) return InsertPointTy(); @@ -1864,7 +1864,7 @@ OpenMPIRBuilder::InsertPointOrErrorTy OpenMPIRBuilder::createTask( Builder, AllocaIP, ToBeDeleted, TaskAllocaIP, "global.tid", false)); OI.PostOutlineCB = [this, Ident, Tied, Final, IfCondition, Dependencies, - Mergeable, TaskAllocaBB, + Mergeable, EventHandle, TaskAllocaBB, ToBeDeleted](Function &OutlinedFn) mutable { // Replace the Stale CI by appropriate RTL function call. assert(OutlinedFn.getNumUses() == 1 && @@ -1935,6 +1935,20 @@ OpenMPIRBuilder::InsertPointOrErrorTy OpenMPIRBuilder::createTask( /*sizeof_task=*/TaskSize, /*sizeof_shared=*/SharedsSize, /*task_func=*/&OutlinedFn}); + // Emit detach clause initialization. + // evt = (typeof(evt))__kmpc_task_allow_completion_event(loc, tid, + // task_descriptor); + if (EventHandle) { + Function *TaskDetachFn = getOrCreateRuntimeFunctionPtr( + OMPRTL___kmpc_task_allow_completion_event); + llvm::Value *EventVal = + Builder.CreateCall(TaskDetachFn, {Ident, ThreadID, TaskData}); + llvm::Value *EventHandleAddr = + Builder.CreatePointerBitCastOrAddrSpaceCast(EventHandle, + Builder.getPtrTy(0)); + EventVal = Builder.CreatePtrToInt(EventVal, Builder.getInt64Ty()); + Builder.CreateStore(EventVal, EventHandleAddr); + } // Copy the arguments for outlined function if (HasShareds) { Value *Shareds = StaleCI->getArgOperand(1); diff --git a/mlir/include/mlir/Dialect/OpenMP/OpenMPClauses.td b/mlir/include/mlir/Dialect/OpenMP/OpenMPClauses.td index 855deab94b2f1..077d6602628aa 100644 --- a/mlir/include/mlir/Dialect/OpenMP/OpenMPClauses.td +++ b/mlir/include/mlir/Dialect/OpenMP/OpenMPClauses.td @@ -909,6 +909,34 @@ class OpenMP_ParallelizationLevelClauseSkip< def OpenMP_ParallelizationLevelClause : OpenMP_ParallelizationLevelClauseSkip<>; +//===----------------------------------------------------------------------===// +// OpenMPV5.2: [12.5.2] `detach` clause +//===----------------------------------------------------------------------===// + +class OpenMP_DetachClauseSkip< + bit traits = false, bit arguments = false, bit assemblyFormat = false, + bit description = false, bit extraClassDeclaration = false> + : OpenMP_Clause { + + let traits = [BlockArgOpenMPOpInterface]; + + let arguments = (ins Optional:$event_handle); + + let optAssemblyFormat = [{ + `detach` `(` $event_handle `:` type($event_handle) `)` + }]; + + let description = [{ + The detach clause specifies that the task generated by the construct on which it appears is a + detachable task. A new allow-completion event is created and connected to the completion of the + associated task region. The original event-handle is updated to represent that allow-completion + event before the task data environment is created. + }]; +} + +def OpenMP_DetachClause : OpenMP_DetachClauseSkip<>; + //===----------------------------------------------------------------------===// // V5.2: [12.4] `priority` clause //===----------------------------------------------------------------------===// diff --git a/mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td b/mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td index f6c7f19fffddf..85b6a6638036f 100644 --- a/mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td +++ b/mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td @@ -657,15 +657,18 @@ def DistributeOp : OpenMP_Op<"distribute", traits = [ // 2.10.1 task Construct //===----------------------------------------------------------------------===// -def TaskOp : OpenMP_Op<"task", traits = [ - AttrSizedOperandSegments, AutomaticAllocationScope, - OutlineableOpenMPOpInterface - ], clauses = [ - // TODO: Complete clause list (affinity, detach). - OpenMP_AllocateClause, OpenMP_DependClause, OpenMP_FinalClause, - OpenMP_IfClause, OpenMP_InReductionClause, OpenMP_MergeableClause, - OpenMP_PriorityClause, OpenMP_PrivateClause, OpenMP_UntiedClause - ], singleRegion = true> { +def TaskOp + : OpenMP_Op<"task", + traits = [AttrSizedOperandSegments, AutomaticAllocationScope, + OutlineableOpenMPOpInterface], + clauses = [ + // TODO: Complete clause list (affinity, detach). + OpenMP_AllocateClause, OpenMP_DependClause, + OpenMP_FinalClause, OpenMP_IfClause, + OpenMP_InReductionClause, OpenMP_MergeableClause, + OpenMP_PriorityClause, OpenMP_PrivateClause, + OpenMP_UntiedClause, OpenMP_DetachClause], + singleRegion = true> { let summary = "task construct"; let description = [{ The task construct defines an explicit task. diff --git a/mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp b/mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp index 6d7dbbf58bbda..e20530be07b2f 100644 --- a/mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp +++ b/mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp @@ -2303,7 +2303,7 @@ void TaskOp::build(OpBuilder &builder, OperationState &state, makeArrayAttr(ctx, clauses.inReductionSyms), clauses.mergeable, clauses.priority, /*private_vars=*/clauses.privateVars, /*private_syms=*/makeArrayAttr(ctx, clauses.privateSyms), - clauses.untied); + clauses.untied, clauses.eventHandle); } LogicalResult TaskOp::verify() { diff --git a/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp b/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp index 063055f8015b8..946c3c423267d 100644 --- a/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp +++ b/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp @@ -1703,7 +1703,8 @@ convertOmpTaskOp(omp::TaskOp taskOp, llvm::IRBuilderBase &builder, ompLoc, allocaIP, bodyCB, !taskOp.getUntied(), moduleTranslation.lookupValue(taskOp.getFinal()), moduleTranslation.lookupValue(taskOp.getIfExpr()), dds, - taskOp.getMergeable()); + taskOp.getMergeable(), + moduleTranslation.lookupValue(taskOp.getEventHandle())); if (failed(handleError(afterIP, *taskOp))) return failure(); diff --git a/mlir/test/Dialect/OpenMP/invalid.mlir b/mlir/test/Dialect/OpenMP/invalid.mlir index 2a19e4837f550..1fbb4c93e855b 100644 --- a/mlir/test/Dialect/OpenMP/invalid.mlir +++ b/mlir/test/Dialect/OpenMP/invalid.mlir @@ -1634,7 +1634,7 @@ func.func @omp_single_copyprivate(%data_var : memref) -> () { // ----- func.func @omp_task_depend(%data_var: memref) { - // expected-error @below {{op expected as many depend values as depend variables}} + // expected-error @below {{'omp.task' op operand count (1) does not match with the total size (0) specified in attribute 'operandSegmentSizes'}} "omp.task"(%data_var) ({ "omp.terminator"() : () -> () }) {depend_kinds = [], operandSegmentSizes = array} : (memref) -> () diff --git a/mlir/test/Dialect/OpenMP/ops.mlir b/mlir/test/Dialect/OpenMP/ops.mlir index 94c63dd8e9aa0..26943068ed95a 100644 --- a/mlir/test/Dialect/OpenMP/ops.mlir +++ b/mlir/test/Dialect/OpenMP/ops.mlir @@ -1975,8 +1975,8 @@ func.func @omp_single_copyprivate(%data_var: memref) { } // CHECK-LABEL: @omp_task -// CHECK-SAME: (%[[bool_var:.*]]: i1, %[[i64_var:.*]]: i64, %[[i32_var:.*]]: i32, %[[data_var:.*]]: memref) -func.func @omp_task(%bool_var: i1, %i64_var: i64, %i32_var: i32, %data_var: memref) { +// CHECK-SAME: (%[[bool_var:.*]]: i1, %[[i64_var:.*]]: i64, %[[i32_var:.*]]: i32, %[[data_var:.*]]: memref, %[[event_handle:.*]]: !llvm.ptr) +func.func @omp_task(%bool_var: i1, %i64_var: i64, %i32_var: i32, %data_var: memref, %event_handle : !llvm.ptr) { // Checking simple task // CHECK: omp.task { @@ -2054,7 +2054,11 @@ func.func @omp_task(%bool_var: i1, %i64_var: i64, %i32_var: i32, %data_var: memr // CHECK: omp.terminator omp.terminator } - + // Checking detach clause + // CHECK: omp.task detach(%[[event_handle]] : !llvm.ptr) + omp.task detach(%event_handle : !llvm.ptr){ + omp.terminator + } // Checking multiple clauses // CHECK: omp.task allocate(%[[data_var]] : memref -> %[[data_var]] : memref) omp.task allocate(%data_var : memref -> %data_var : memref) diff --git a/mlir/test/Target/LLVMIR/openmp-llvm.mlir b/mlir/test/Target/LLVMIR/openmp-llvm.mlir index b40ec0a831d2e..5f8bdf8afdf78 100644 --- a/mlir/test/Target/LLVMIR/openmp-llvm.mlir +++ b/mlir/test/Target/LLVMIR/openmp-llvm.mlir @@ -2505,6 +2505,23 @@ llvm.mlir.global internal @_QFsubEx() : i32 // ----- +// CHECK-LABEL: define void @omp_task_detach +// CHECK-SAME: (ptr %[[event_handle:.*]]) +llvm.func @omp_task_detach(%event_handle : !llvm.ptr){ + // CHECK: %[[omp_global_thread_num:.+]] = call i32 @__kmpc_global_thread_num({{.+}}) + // CHECK: %[[task_data:.+]] = call ptr @__kmpc_omp_task_alloc + // CHECK: %[[return_val:.*]] = call ptr @__kmpc_task_allow_completion_event(ptr {{.*}}, i32 %[[omp_global_thread_num]], ptr %[[task_data]]) + // CHECK: %[[conv:.*]] = ptrtoint ptr %[[return_val]] to i64 + // CHECK: store i64 %[[conv]], ptr %[[event_handle]], align 4 + // CHECK: call i32 @__kmpc_omp_task(ptr @{{.+}}, i32 %[[omp_global_thread_num]], ptr %[[task_data]]) + omp.task detach(%event_handle : !llvm.ptr){ + omp.terminator + } + llvm.return +} + +// ----- + // CHECK-LABEL: define void @omp_task // CHECK-SAME: (i32 %[[x:.+]], i32 %[[y:.+]], ptr %[[zaddr:.+]]) llvm.func @omp_task(%x: i32, %y: i32, %zaddr: !llvm.ptr) {