https://github.com/tblah created 
https://github.com/llvm/llvm-project/pull/174815

Implementation follows exactly what is done for omp.wsloop and omp.task. See 
#137841.

The change to the operation verifier is to allow a taskgroup cancellation point 
inside of a taskloop. This was already allowed for omp.cancel.

>From 56790672df6aa76925b8f15724645b2c60eec1c4 Mon Sep 17 00:00:00 2001
From: Tom Eccles <[email protected]>
Date: Tue, 6 Jan 2026 17:49:44 +0000
Subject: [PATCH] [MLIR][OpenMP] Support cancel taskgroup inside of taskloop

Implementation follows exactly what is done for omp.wsloop and omp.task.
See #137841.

The change to the operation verifier is to allow a taskgroup
cancellation point inside of a taskloop. This was already allowed for
omp.cancel.
---
 mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp  |   3 +-
 .../OpenMP/OpenMPToLLVMIRTranslation.cpp      |  32 +-
 .../Target/LLVMIR/openmp-taskloop-cancel.mlir | 419 ++++++++++++++++++
 .../openmp-taskloop-cancellation-point.mlir   | 280 ++++++++++++
 4 files changed, 713 insertions(+), 21 deletions(-)
 create mode 100644 mlir/test/Target/LLVMIR/openmp-taskloop-cancel.mlir
 create mode 100644 
mlir/test/Target/LLVMIR/openmp-taskloop-cancellation-point.mlir

diff --git a/mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp 
b/mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp
index 103295d136dbb..01dd510162a49 100644
--- a/mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp
+++ b/mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp
@@ -4129,7 +4129,8 @@ LogicalResult CancellationPointOp::verify() {
                          << "inside a sections region";
   }
   if ((cct == ClauseCancellationConstructType::Taskgroup) &&
-      !mlir::isa<omp::TaskOp>(structuralParent)) {
+      (!mlir::isa<omp::TaskOp>(structuralParent) &&
+       !mlir::isa<omp::TaskloopOp>(structuralParent->getParentOp()))) {
     return emitOpError() << "cancellation point taskgroup must appear "
                          << "inside a task region";
   }
diff --git 
a/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp 
b/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp
index 43c503757ddf5..c64fbfe890e9a 100644
--- a/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp
+++ b/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp
@@ -329,22 +329,6 @@ static LogicalResult checkImplementationStatus(Operation 
&op) {
     if (op.getBare())
       result = todo("ompx_bare");
   };
-  auto checkCancelDirective = [&todo](auto op, LogicalResult &result) {
-    omp::ClauseCancellationConstructType cancelledDirective =
-        op.getCancelDirective();
-    // Cancelling a taskloop is not yet supported because we don't yet have 
LLVM
-    // IR conversion for taskloop
-    if (cancelledDirective == omp::ClauseCancellationConstructType::Taskgroup) 
{
-      Operation *parent = op->getParentOp();
-      while (parent) {
-        if (parent->getDialect() == op->getDialect())
-          break;
-        parent = parent->getParentOp();
-      }
-      if (isa_and_nonnull<omp::TaskloopOp>(parent))
-        result = todo("cancel directive inside of taskloop");
-    }
-  };
   auto checkCollapse = [&todo](auto op, LogicalResult &result) {
     if (op.getCollapseNumLoops() > 1)
       result = todo("collapse");
@@ -399,10 +383,6 @@ static LogicalResult checkImplementationStatus(Operation 
&op) {
 
   LogicalResult result = success();
   llvm::TypeSwitch<Operation &>(op)
-      .Case([&](omp::CancelOp op) { checkCancelDirective(op, result); })
-      .Case([&](omp::CancellationPointOp op) {
-        checkCancelDirective(op, result);
-      })
       .Case([&](omp::DistributeOp op) {
         checkAllocate(op, result);
         checkOrder(op, result);
@@ -2773,6 +2753,16 @@ convertOmpTaskloopOp(Operation &opInst, 
llvm::IRBuilderBase &builder,
   if (taskStructMgr.getStructPtr())
     taskDupOrNull = taskDupCB;
 
+  llvm::OpenMPIRBuilder &ompBuilder = *moduleTranslation.getOpenMPBuilder();
+  SmallVector<llvm::BranchInst *> cancelTerminators;
+  // The directive to match here is OMPD_taskgroup because it is the
+  // taskgroup which is canceled. This is handled here because it is the
+  // task's cleanup block which should be branched to. It doesn't depend upon
+  // nogroup because even in that case the taskloop might still be inside an
+  // explicit taskgroup.
+  pushCancelFinalizationCB(cancelTerminators, builder, ompBuilder, taskloopOp,
+                           llvm::omp::Directive::OMPD_taskgroup);
+
   llvm::OpenMPIRBuilder::LocationDescription ompLoc(builder);
   llvm::OpenMPIRBuilder::InsertPointOrErrorTy afterIP =
       moduleTranslation.getOpenMPBuilder()->createTaskloop(
@@ -2789,6 +2779,8 @@ convertOmpTaskloopOp(Operation &opInst, 
llvm::IRBuilderBase &builder,
   if (failed(handleError(afterIP, opInst)))
     return failure();
 
+  popCancelFinalizationCB(cancelTerminators, ompBuilder, afterIP.get());
+
   builder.restoreIP(*afterIP);
   return success();
 }
diff --git a/mlir/test/Target/LLVMIR/openmp-taskloop-cancel.mlir 
b/mlir/test/Target/LLVMIR/openmp-taskloop-cancel.mlir
new file mode 100644
index 0000000000000..7aa6398a7f113
--- /dev/null
+++ b/mlir/test/Target/LLVMIR/openmp-taskloop-cancel.mlir
@@ -0,0 +1,419 @@
+// RUN: mlir-translate -mlir-to-llvmir %s | FileCheck %s
+
+omp.private {type = private} @_QFtestEi_private_i32 : i32
+omp.private {type = firstprivate} @_QFtestEarg_firstprivate_i32 : i32 init {
+^bb0(%arg0: !llvm.ptr, %arg1: !llvm.ptr):
+  llvm.call @_init(%arg0, %arg1) : (!llvm.ptr, !llvm.ptr) -> ()
+  omp.yield(%arg1 : !llvm.ptr)
+} copy {
+^bb0(%arg0: !llvm.ptr, %arg1: !llvm.ptr):
+  llvm.call @_copy(%arg0, %arg1) : (!llvm.ptr, !llvm.ptr) -> ()
+  omp.yield(%arg1 : !llvm.ptr)
+} dealloc {
+^bb0(%arg0: !llvm.ptr):
+  llvm.call @_dealloc(%arg0) : (!llvm.ptr) -> ()
+  omp.yield
+}
+
+// Test cancelling implicit taskgroup created by taskloop
+llvm.func @_QPtest(%arg0: !llvm.ptr {fir.bindc_name = "arg", llvm.noalias, 
llvm.nocapture}) {
+  %0 = llvm.mlir.constant(1 : i32) : i32
+  %1 = llvm.mlir.constant(100 : i32) : i32
+  %2 = llvm.mlir.constant(1 : i64) : i64
+  %3 = llvm.alloca %2 x i32 {bindc_name = "i"} : (i64) -> !llvm.ptr
+  omp.taskloop private(@_QFtestEarg_firstprivate_i32 %arg0 -> %arg1, 
@_QFtestEi_private_i32 %3 -> %arg2 : !llvm.ptr, !llvm.ptr) {
+    omp.loop_nest (%arg3) : i32 = (%0) to (%1) inclusive step (%0) {
+      llvm.store %arg3, %arg2 : i32, !llvm.ptr
+      llvm.call @_QPbefore(%arg1) : (!llvm.ptr) -> ()
+      omp.cancel cancellation_construct_type(taskgroup)
+      llvm.call @_QPafter(%arg1) : (!llvm.ptr) -> ()
+      omp.yield
+    }
+  }
+  llvm.return
+}
+// CHECK-LABEL: define void @_QPtest(
+// CHECK:         %[[STRUCTARG:.*]] = alloca { i64, i64, i64, ptr }, align 8
+// CHECK:         %[[VAL_0:.*]] = alloca i32, i64 1, align 4
+// CHECK:         br label %[[VAL_1:.*]]
+// CHECK:       entry:                                            ; preds = 
%[[VAL_2:.*]]
+// CHECK:         br label %[[VAL_3:.*]]
+// CHECK:       omp.private.init:                                 ; preds = 
%[[VAL_1]]
+// CHECK:         %[[VAL_4:.*]] = tail call ptr @malloc(i64 ptrtoint (ptr 
getelementptr ({ i32 }, ptr null, i32 1) to i64))
+// CHECK:         %[[VAL_5:.*]] = getelementptr { i32 }, ptr %[[VAL_4]], i32 
0, i32 0
+// CHECK:         call void @_init(ptr %[[VAL_6:.*]], ptr %[[VAL_5]])
+// CHECK:         br label %[[VAL_7:.*]]
+// CHECK:       omp.private.copy:                                 ; preds = 
%[[VAL_3]]
+// CHECK:         br label %[[VAL_8:.*]]
+// CHECK:       omp.private.copy1:                                ; preds = 
%[[VAL_7]]
+// CHECK:         call void @_copy(ptr %[[VAL_6]], ptr %[[VAL_5]])
+// CHECK:         br label %[[VAL_9:.*]]
+// CHECK:       omp.taskloop.start:                               ; preds = 
%[[VAL_8]]
+// CHECK:         br label %[[VAL_10:.*]]
+// CHECK:       codeRepl:                                         ; preds = 
%[[VAL_9]]
+// CHECK:         %[[VAL_11:.*]] = getelementptr { i64, i64, i64, ptr }, ptr 
%[[STRUCTARG]], i32 0, i32 0
+// CHECK:         store i64 1, ptr %[[VAL_11]], align 4
+// CHECK:         %[[VAL_12:.*]] = getelementptr { i64, i64, i64, ptr }, ptr 
%[[STRUCTARG]], i32 0, i32 1
+// CHECK:         store i64 100, ptr %[[VAL_12]], align 4
+// CHECK:         %[[VAL_13:.*]] = getelementptr { i64, i64, i64, ptr }, ptr 
%[[STRUCTARG]], i32 0, i32 2
+// CHECK:         store i64 1, ptr %[[VAL_13]], align 4
+// CHECK:         %[[VAL_14:.*]] = getelementptr { i64, i64, i64, ptr }, ptr 
%[[STRUCTARG]], i32 0, i32 3
+// CHECK:         store ptr %[[VAL_4]], ptr %[[VAL_14]], align 8
+// CHECK:         %[[VAL_15:.*]] = call i32 @__kmpc_global_thread_num(ptr @1)
+// CHECK:         call void @__kmpc_taskgroup(ptr @1, i32 %[[VAL_15]])
+// CHECK:         %[[VAL_16:.*]] = call ptr @__kmpc_omp_task_alloc(ptr @1, i32 
%[[VAL_15]], i32 1, i64 40, i64 32, ptr @_QPtest..omp_par)
+// CHECK:         %[[VAL_17:.*]] = load ptr, ptr %[[VAL_16]], align 8
+// CHECK:         call void @llvm.memcpy.p0.p0.i64(ptr align 1 %[[VAL_17]], 
ptr align 1 %[[STRUCTARG]], i64 32, i1 false)
+// CHECK:         %[[VAL_18:.*]] = getelementptr { i64, i64, i64, ptr }, ptr 
%[[VAL_17]], i32 0, i32 0
+// CHECK:         %[[VAL_19:.*]] = getelementptr { i64, i64, i64, ptr }, ptr 
%[[VAL_17]], i32 0, i32 1
+// CHECK:         %[[VAL_20:.*]] = getelementptr { i64, i64, i64, ptr }, ptr 
%[[VAL_17]], i32 0, i32 2
+// CHECK:         %[[VAL_21:.*]] = load i64, ptr %[[VAL_20]], align 4
+// CHECK:         call void @__kmpc_taskloop(ptr @1, i32 %[[VAL_15]], ptr 
%[[VAL_16]], i32 1, ptr %[[VAL_18]], ptr %[[VAL_19]], i64 %[[VAL_21]], i32 1, 
i32 0, i64 0, ptr @omp_taskloop_dup)
+// CHECK:         call void @__kmpc_end_taskgroup(ptr @1, i32 %[[VAL_15]])
+// CHECK:         br label %[[VAL_22:.*]]
+// CHECK:       taskloop.exit:                                    ; preds = 
%[[VAL_10]]
+// CHECK:         ret void
+
+// CHECK-LABEL: define internal void @_QPtest..omp_par
+// CHECK:       taskloop.alloca:
+// CHECK:         %[[VAL_23:.*]] = load ptr, ptr %[[VAL_24:.*]], align 8
+// CHECK:         %[[VAL_25:.*]] = getelementptr { i64, i64, i64, ptr }, ptr 
%[[VAL_23]], i32 0, i32 0
+// CHECK:         %[[VAL_26:.*]] = load i64, ptr %[[VAL_25]], align 4
+// CHECK:         %[[VAL_27:.*]] = getelementptr { i64, i64, i64, ptr }, ptr 
%[[VAL_23]], i32 0, i32 1
+// CHECK:         %[[VAL_28:.*]] = load i64, ptr %[[VAL_27]], align 4
+// CHECK:         %[[VAL_29:.*]] = getelementptr { i64, i64, i64, ptr }, ptr 
%[[VAL_23]], i32 0, i32 2
+// CHECK:         %[[VAL_30:.*]] = load i64, ptr %[[VAL_29]], align 4
+// CHECK:         %[[VAL_31:.*]] = getelementptr { i64, i64, i64, ptr }, ptr 
%[[VAL_23]], i32 0, i32 3
+// CHECK:         %[[VAL_32:.*]] = load ptr, ptr %[[VAL_31]], align 8, !align 
!1
+// CHECK:         %[[VAL_33:.*]] = alloca i32, align 4
+// CHECK:         br label %[[VAL_34:.*]]
+// CHECK:       taskloop.body:                                    ; preds = 
%[[VAL_35:.*]]
+// CHECK:         %[[VAL_36:.*]] = getelementptr { i32 }, ptr %[[VAL_32]], i32 
0, i32 0
+// CHECK:         br label %[[VAL_37:.*]]
+// CHECK:       omp.taskloop.region:                              ; preds = 
%[[VAL_34]]
+// CHECK:         br label %[[VAL_38:.*]]
+// CHECK:       omp_loop.preheader:                               ; preds = 
%[[VAL_37]]
+// CHECK:         %[[VAL_39:.*]] = sub i64 %[[VAL_28]], %[[VAL_26]]
+// CHECK:         %[[VAL_40:.*]] = sdiv i64 %[[VAL_39]], 1
+// CHECK:         %[[VAL_41:.*]] = add i64 %[[VAL_40]], 1
+// CHECK:         %[[VAL_42:.*]] = trunc i64 %[[VAL_41]] to i32
+// CHECK:         %[[VAL_43:.*]] = trunc i64 %[[VAL_26]] to i32
+// CHECK:         br label %[[VAL_44:.*]]
+// CHECK:       omp_loop.header:                                  ; preds = 
%[[VAL_45:.*]], %[[VAL_38]]
+// CHECK:         %[[VAL_46:.*]] = phi i32 [ 0, %[[VAL_38]] ], [ 
%[[VAL_47:.*]], %[[VAL_45]] ]
+// CHECK:         br label %[[VAL_48:.*]]
+// CHECK:       omp_loop.cond:                                    ; preds = 
%[[VAL_44]]
+// CHECK:         %[[VAL_49:.*]] = icmp ult i32 %[[VAL_46]], %[[VAL_42]]
+// CHECK:         br i1 %[[VAL_49]], label %[[VAL_50:omp_loop.body]], label 
%[[VAL_51:omp_loop.exit]]
+// CHECK:       omp_loop.exit:                                    ; preds = 
%[[VAL_48]]
+// CHECK:         br label %[[OMP_LOOP_AFTER:omp_loop.after]]
+// CHECK:       omp_loop.after:                                   ; preds = 
%[[VAL_51]]
+// CHECK:         br label %[[CONT:omp.region.cont]]
+// CHECK:       omp.region.cont:                                  ; preds = 
%[[FINI:.fini]], %[[OMP_LOOP_AFTER]]
+// CHECK:         call void @_dealloc(ptr %[[VAL_36]])
+// CHECK:         tail call void @free(ptr %[[VAL_32]])
+// CHECK:         br label %[[VAL_55:.*]]
+// CHECK:       omp_loop.body:                                    ; preds = 
%[[VAL_48]]
+// CHECK:         %[[VAL_56:.*]] = mul i32 %[[VAL_46]], 1
+// CHECK:         %[[VAL_57:.*]] = add i32 %[[VAL_56]], %[[VAL_43]]
+// CHECK:         br label %[[LOOP_REGION:omp.loop_nest.region]]
+// CHECK:       omp.loop_nest.region:                             ; preds = 
%[[VAL_50]]
+// CHECK:         store i32 %[[VAL_57]], ptr %[[VAL_33]], align 4
+// CHECK:         call void @_QPbefore(ptr %[[VAL_36]])
+// CHECK:         %[[VAL_59:.*]] = call i32 @__kmpc_global_thread_num(ptr @1)
+// CHECK:         %[[VAL_60:.*]] = call i32 @__kmpc_cancel(ptr @1, i32 
%[[VAL_59]], i32 4)
+// CHECK:         %[[VAL_61:.*]] = icmp eq i32 %[[VAL_60]], 0
+// CHECK:         br i1 %[[VAL_61]], label 
%[[VAL_62:omp.loop_nest.region.split]], label 
%[[CNCL:omp.loop_nest.region.cncl]]
+// CHECK:       omp.loop_nest.region.cncl:                        ; preds = 
%[[LOOP_REGION]]
+// CHECK:         br label %[[FINI]]
+// CHECK:       .fini:                                            ; preds = 
%[[CNCL]]
+// CHECK:         br label %[[CONT]]
+// CHECK:       omp.loop_nest.region.split:                       ; preds = 
%[[LOOP_REGION]]
+// CHECK:         call void @_QPafter(ptr %[[VAL_36]])
+// CHECK:         br label %[[VAL_64:.*]]
+// CHECK:       omp.region.cont2:                                 ; preds = 
%[[VAL_62]]
+// CHECK:         br label %[[VAL_45]]
+// CHECK:       omp_loop.inc:                                     ; preds = 
%[[VAL_64]]
+// CHECK:         %[[VAL_47]] = add nuw i32 %[[VAL_46]], 1
+// CHECK:         br label %[[VAL_44]]
+// CHECK:       taskloop.exit.exitStub:                           ; preds = 
%[[CONT]]
+// CHECK:         ret void
+
+// Tesk cancelling explicit taskgroup enclosing taskloop
+llvm.func @_QPtest2(%arg0: !llvm.ptr {fir.bindc_name = "arg", llvm.noalias, 
llvm.nocapture}) {
+  %0 = llvm.mlir.constant(1 : i32) : i32
+  %1 = llvm.mlir.constant(100 : i32) : i32
+  %2 = llvm.mlir.constant(1 : i64) : i64
+  %3 = llvm.alloca %2 x i32 {bindc_name = "i"} : (i64) -> !llvm.ptr
+  omp.taskgroup {
+    omp.taskloop nogroup private(@_QFtestEarg_firstprivate_i32 %arg0 -> %arg1, 
@_QFtestEi_private_i32 %3 -> %arg2 : !llvm.ptr, !llvm.ptr) {
+      omp.loop_nest (%arg3) : i32 = (%0) to (%1) inclusive step (%0) {
+        llvm.store %arg3, %arg2 : i32, !llvm.ptr
+        llvm.call @_QPbefore(%arg1) : (!llvm.ptr) -> ()
+        omp.cancel cancellation_construct_type(taskgroup)
+        llvm.call @_QPafter(%arg1) : (!llvm.ptr) -> ()
+        omp.yield
+      }
+    }
+    omp.terminator
+  }
+  llvm.return
+}
+// CHECK-LABEL: define void @_QPtest2(
+// CHECK:         %[[VAL_65:.*]] = alloca { i64, i64, i64, ptr }, align 8
+// CHECK:         %[[VAL_66:.*]] = alloca i32, i64 1, align 4
+// CHECK:         br label %[[VAL_67:.*]]
+// CHECK:       entry:                                            ; preds = 
%[[VAL_68:.*]]
+// CHECK:         %[[VAL_69:.*]] = call i32 @__kmpc_global_thread_num(ptr @1)
+// CHECK:         call void @__kmpc_taskgroup(ptr @1, i32 %[[VAL_69]])
+// CHECK:         br label %[[VAL_70:.*]]
+// CHECK:       omp.taskgroup.region:                             ; preds = 
%[[VAL_67]]
+// CHECK:         br label %[[VAL_71:.*]]
+// CHECK:       omp.private.init:                                 ; preds = 
%[[VAL_70]]
+// CHECK:         %[[VAL_72:.*]] = tail call ptr @malloc(i64 ptrtoint (ptr 
getelementptr ({ i32 }, ptr null, i32 1) to i64))
+// CHECK:         %[[VAL_73:.*]] = getelementptr { i32 }, ptr %[[VAL_72]], i32 
0, i32 0
+// CHECK:         call void @_init(ptr %[[VAL_74:.*]], ptr %[[VAL_73]])
+// CHECK:         br label %[[VAL_75:.*]]
+// CHECK:       omp.private.copy:                                 ; preds = 
%[[VAL_71]]
+// CHECK:         br label %[[VAL_76:.*]]
+// CHECK:       omp.private.copy1:                                ; preds = 
%[[VAL_75]]
+// CHECK:         call void @_copy(ptr %[[VAL_74]], ptr %[[VAL_73]])
+// CHECK:         br label %[[VAL_77:.*]]
+// CHECK:       omp.region.cont:                                  ; preds = 
%[[VAL_78:.*]]
+// CHECK:         br label %[[VAL_79:.*]]
+// CHECK:       taskgroup.exit:                                   ; preds = 
%[[VAL_80:.*]]
+// CHECK:         call void @__kmpc_end_taskgroup(ptr @1, i32 %[[VAL_69]])
+// CHECK:         ret void
+// CHECK:       omp.taskloop.start:                               ; preds = 
%[[VAL_76]]
+// CHECK:         br label %[[VAL_81:.*]]
+// CHECK:       codeRepl:                                         ; preds = 
%[[VAL_77]]
+// CHECK:         %[[VAL_82:.*]] = getelementptr { i64, i64, i64, ptr }, ptr 
%[[VAL_65]], i32 0, i32 0
+// CHECK:         store i64 1, ptr %[[VAL_82]], align 4
+// CHECK:         %[[VAL_83:.*]] = getelementptr { i64, i64, i64, ptr }, ptr 
%[[VAL_65]], i32 0, i32 1
+// CHECK:         store i64 100, ptr %[[VAL_83]], align 4
+// CHECK:         %[[VAL_84:.*]] = getelementptr { i64, i64, i64, ptr }, ptr 
%[[VAL_65]], i32 0, i32 2
+// CHECK:         store i64 1, ptr %[[VAL_84]], align 4
+// CHECK:         %[[VAL_85:.*]] = getelementptr { i64, i64, i64, ptr }, ptr 
%[[VAL_65]], i32 0, i32 3
+// CHECK:         store ptr %[[VAL_72]], ptr %[[VAL_85]], align 8
+// CHECK:         %[[VAL_86:.*]] = call i32 @__kmpc_global_thread_num(ptr @1)
+// CHECK:         %[[VAL_87:.*]] = call ptr @__kmpc_omp_task_alloc(ptr @1, i32 
%[[VAL_86]], i32 1, i64 40, i64 32, ptr @_QPtest2..omp_par)
+// CHECK:         %[[VAL_88:.*]] = load ptr, ptr %[[VAL_87]], align 8
+// CHECK:         call void @llvm.memcpy.p0.p0.i64(ptr align 1 %[[VAL_88]], 
ptr align 1 %[[VAL_65]], i64 32, i1 false)
+// CHECK:         %[[VAL_89:.*]] = getelementptr { i64, i64, i64, ptr }, ptr 
%[[VAL_88]], i32 0, i32 0
+// CHECK:         %[[VAL_90:.*]] = getelementptr { i64, i64, i64, ptr }, ptr 
%[[VAL_88]], i32 0, i32 1
+// CHECK:         %[[VAL_91:.*]] = getelementptr { i64, i64, i64, ptr }, ptr 
%[[VAL_88]], i32 0, i32 2
+// CHECK:         %[[VAL_92:.*]] = load i64, ptr %[[VAL_91]], align 4
+// CHECK:         call void @__kmpc_taskloop(ptr @1, i32 %[[VAL_86]], ptr 
%[[VAL_87]], i32 1, ptr %[[VAL_89]], ptr %[[VAL_90]], i64 %[[VAL_92]], i32 1, 
i32 0, i64 0, ptr @omp_taskloop_dup.1)
+// CHECK:         br label %[[VAL_78]]
+// CHECK:       taskloop.exit:                                    ; preds = 
%[[VAL_81]]
+// CHECK:         br label %[[VAL_80]]
+
+// CHECK-LABEL: define internal void @_QPtest2..omp_par(
+// CHECK:       taskloop.alloca:
+// CHECK:         %[[VAL_93:.*]] = load ptr, ptr %[[VAL_94:.*]], align 8
+// CHECK:         %[[VAL_95:.*]] = getelementptr { i64, i64, i64, ptr }, ptr 
%[[VAL_93]], i32 0, i32 0
+// CHECK:         %[[VAL_96:.*]] = load i64, ptr %[[VAL_95]], align 4
+// CHECK:         %[[VAL_97:.*]] = getelementptr { i64, i64, i64, ptr }, ptr 
%[[VAL_93]], i32 0, i32 1
+// CHECK:         %[[VAL_98:.*]] = load i64, ptr %[[VAL_97]], align 4
+// CHECK:         %[[VAL_99:.*]] = getelementptr { i64, i64, i64, ptr }, ptr 
%[[VAL_93]], i32 0, i32 2
+// CHECK:         %[[VAL_100:.*]] = load i64, ptr %[[VAL_99]], align 4
+// CHECK:         %[[VAL_101:.*]] = getelementptr { i64, i64, i64, ptr }, ptr 
%[[VAL_93]], i32 0, i32 3
+// CHECK:         %[[VAL_102:.*]] = load ptr, ptr %[[VAL_101]], align 8, 
!align !1
+// CHECK:         %[[VAL_103:.*]] = alloca i32, align 4
+// CHECK:         br label %[[VAL_104:.*]]
+// CHECK:       taskloop.body:                                    ; preds = 
%[[VAL_105:.*]]
+// CHECK:         %[[VAL_106:.*]] = getelementptr { i32 }, ptr %[[VAL_102]], 
i32 0, i32 0
+// CHECK:         br label %[[VAL_107:.*]]
+// CHECK:       omp.taskloop.region:                              ; preds = 
%[[VAL_104]]
+// CHECK:         br label %[[VAL_108:.*]]
+// CHECK:       omp_loop.preheader:                               ; preds = 
%[[VAL_107]]
+// CHECK:         %[[VAL_109:.*]] = sub i64 %[[VAL_98]], %[[VAL_96]]
+// CHECK:         %[[VAL_110:.*]] = sdiv i64 %[[VAL_109]], 1
+// CHECK:         %[[VAL_111:.*]] = add i64 %[[VAL_110]], 1
+// CHECK:         %[[VAL_112:.*]] = trunc i64 %[[VAL_111]] to i32
+// CHECK:         %[[VAL_113:.*]] = trunc i64 %[[VAL_96]] to i32
+// CHECK:         br label %[[VAL_114:.*]]
+// CHECK:       omp_loop.header:                                  ; preds = 
%[[VAL_115:.*]], %[[VAL_108]]
+// CHECK:         %[[VAL_116:.*]] = phi i32 [ 0, %[[VAL_108]] ], [ 
%[[VAL_117:.*]], %[[VAL_115]] ]
+// CHECK:         br label %[[VAL_118:.*]]
+// CHECK:       omp_loop.cond:                                    ; preds = 
%[[VAL_114]]
+// CHECK:         %[[VAL_119:.*]] = icmp ult i32 %[[VAL_116]], %[[VAL_112]]
+// CHECK:         br i1 %[[VAL_119]], label %[[VAL_120:.*]], label 
%[[VAL_121:.*]]
+// CHECK:       omp_loop.exit:                                    ; preds = 
%[[VAL_118]]
+// CHECK:         br label %[[VAL_122:.*]]
+// CHECK:       omp_loop.after:                                   ; preds = 
%[[VAL_121]]
+// CHECK:         br label %[[VAL_123:omp.region.cont2]]
+// CHECK:       omp.region.cont2:                                 ; preds = 
%[[VAL_124:.fini]], %[[VAL_122]]
+// CHECK:         call void @_dealloc(ptr %[[VAL_106]])
+// CHECK:         tail call void @free(ptr %[[VAL_102]])
+// CHECK:         br label %[[VAL_125:.*]]
+// CHECK:       omp_loop.body:                                    ; preds = 
%[[VAL_118]]
+// CHECK:         %[[VAL_126:.*]] = mul i32 %[[VAL_116]], 1
+// CHECK:         %[[VAL_127:.*]] = add i32 %[[VAL_126]], %[[VAL_113]]
+// CHECK:         br label %[[VAL_128:.*]]
+// CHECK:       omp.loop_nest.region:                             ; preds = 
%[[VAL_120]]
+// CHECK:         store i32 %[[VAL_127]], ptr %[[VAL_103]], align 4
+// CHECK:         call void @_QPbefore(ptr %[[VAL_106]])
+// CHECK:         %[[VAL_129:.*]] = call i32 @__kmpc_global_thread_num(ptr @1)
+// CHECK:         %[[VAL_130:.*]] = call i32 @__kmpc_cancel(ptr @1, i32 
%[[VAL_129]], i32 4)
+// CHECK:         %[[VAL_131:.*]] = icmp eq i32 %[[VAL_130]], 0
+// CHECK:         br i1 %[[VAL_131]], label 
%[[VAL_132:omp.loop_nest.region.split]], label 
%[[VAL_133:omp.loop_nest.region.cncl]]
+// CHECK:       omp.loop_nest.region.cncl:                        ; preds = 
%[[VAL_128]]
+// CHECK:         br label %[[VAL_124]]
+// CHECK:       .fini:                                            ; preds = 
%[[VAL_133]]
+// CHECK:         br label %[[VAL_123]]
+// CHECK:       omp.loop_nest.region.split:                       ; preds = 
%[[VAL_128]]
+// CHECK:         call void @_QPafter(ptr %[[VAL_106]])
+// CHECK:         br label %[[VAL_134:.*]]
+// CHECK:       omp.region.cont3:                                 ; preds = 
%[[VAL_132]]
+// CHECK:         br label %[[VAL_115]]
+// CHECK:       omp_loop.inc:                                     ; preds = 
%[[VAL_134]]
+// CHECK:         %[[VAL_117]] = add nuw i32 %[[VAL_116]], 1
+// CHECK:         br label %[[VAL_114]]
+// CHECK:       taskloop.exit.exitStub:                           ; preds = 
%[[VAL_123]]
+// CHECK:         ret void
+
+// Test if clause
+llvm.func @_QPtest3(%arg0: !llvm.ptr {fir.bindc_name = "arg", llvm.noalias, 
llvm.nocapture}) {
+  %0 = llvm.mlir.constant(1 : i32) : i32
+  %1 = llvm.mlir.constant(100 : i32) : i32
+  %2 = llvm.mlir.constant(1 : i64) : i64
+  %3 = llvm.alloca %2 x i32 {bindc_name = "i"} : (i64) -> !llvm.ptr
+  omp.taskloop private(@_QFtestEarg_firstprivate_i32 %arg0 -> %arg1, 
@_QFtestEi_private_i32 %3 -> %arg2 : !llvm.ptr, !llvm.ptr) {
+    omp.loop_nest (%arg3) : i32 = (%0) to (%1) inclusive step (%0) {
+      llvm.store %arg3, %arg2 : i32, !llvm.ptr
+      llvm.call @_QPbefore(%arg1) : (!llvm.ptr) -> ()
+      %true = llvm.mlir.constant(1 : i1) : i1
+      omp.cancel cancellation_construct_type(taskgroup) if(%true)
+      llvm.call @_QPafter(%arg1) : (!llvm.ptr) -> ()
+      omp.yield
+    }
+  }
+  llvm.return
+}
+// CHECK-LABEL: define void @_QPtest3(
+// CHECK:         %[[VAL_135:.*]] = alloca { i64, i64, i64, ptr }, align 8
+// CHECK:         %[[VAL_136:.*]] = alloca i32, i64 1, align 4
+// CHECK:         br label %[[VAL_137:.*]]
+// CHECK:       entry:                                            ; preds = 
%[[VAL_138:.*]]
+// CHECK:         br label %[[VAL_139:.*]]
+// CHECK:       omp.private.init:                                 ; preds = 
%[[VAL_137]]
+// CHECK:         %[[VAL_140:.*]] = tail call ptr @malloc(i64 ptrtoint (ptr 
getelementptr ({ i32 }, ptr null, i32 1) to i64))
+// CHECK:         %[[VAL_141:.*]] = getelementptr { i32 }, ptr %[[VAL_140]], 
i32 0, i32 0
+// CHECK:         call void @_init(ptr %[[VAL_142:.*]], ptr %[[VAL_141]])
+// CHECK:         br label %[[VAL_143:.*]]
+// CHECK:       omp.private.copy:                                 ; preds = 
%[[VAL_139]]
+// CHECK:         br label %[[VAL_144:.*]]
+// CHECK:       omp.private.copy1:                                ; preds = 
%[[VAL_143]]
+// CHECK:         call void @_copy(ptr %[[VAL_142]], ptr %[[VAL_141]])
+// CHECK:         br label %[[VAL_145:.*]]
+// CHECK:       omp.taskloop.start:                               ; preds = 
%[[VAL_144]]
+// CHECK:         br label %[[VAL_146:.*]]
+// CHECK:       codeRepl:                                         ; preds = 
%[[VAL_145]]
+// CHECK:         %[[VAL_147:.*]] = getelementptr { i64, i64, i64, ptr }, ptr 
%[[VAL_135]], i32 0, i32 0
+// CHECK:         store i64 1, ptr %[[VAL_147]], align 4
+// CHECK:         %[[VAL_148:.*]] = getelementptr { i64, i64, i64, ptr }, ptr 
%[[VAL_135]], i32 0, i32 1
+// CHECK:         store i64 100, ptr %[[VAL_148]], align 4
+// CHECK:         %[[VAL_149:.*]] = getelementptr { i64, i64, i64, ptr }, ptr 
%[[VAL_135]], i32 0, i32 2
+// CHECK:         store i64 1, ptr %[[VAL_149]], align 4
+// CHECK:         %[[VAL_150:.*]] = getelementptr { i64, i64, i64, ptr }, ptr 
%[[VAL_135]], i32 0, i32 3
+// CHECK:         store ptr %[[VAL_140]], ptr %[[VAL_150]], align 8
+// CHECK:         %[[VAL_151:.*]] = call i32 @__kmpc_global_thread_num(ptr @1)
+// CHECK:         call void @__kmpc_taskgroup(ptr @1, i32 %[[VAL_151]])
+// CHECK:         %[[VAL_152:.*]] = call ptr @__kmpc_omp_task_alloc(ptr @1, 
i32 %[[VAL_151]], i32 1, i64 40, i64 32, ptr @_QPtest3..omp_par)
+// CHECK:         %[[VAL_153:.*]] = load ptr, ptr %[[VAL_152]], align 8
+// CHECK:         call void @llvm.memcpy.p0.p0.i64(ptr align 1 %[[VAL_153]], 
ptr align 1 %[[VAL_135]], i64 32, i1 false)
+// CHECK:         %[[VAL_154:.*]] = getelementptr { i64, i64, i64, ptr }, ptr 
%[[VAL_153]], i32 0, i32 0
+// CHECK:         %[[VAL_155:.*]] = getelementptr { i64, i64, i64, ptr }, ptr 
%[[VAL_153]], i32 0, i32 1
+// CHECK:         %[[VAL_156:.*]] = getelementptr { i64, i64, i64, ptr }, ptr 
%[[VAL_153]], i32 0, i32 2
+// CHECK:         %[[VAL_157:.*]] = load i64, ptr %[[VAL_156]], align 4
+// CHECK:         call void @__kmpc_taskloop(ptr @1, i32 %[[VAL_151]], ptr 
%[[VAL_152]], i32 1, ptr %[[VAL_154]], ptr %[[VAL_155]], i64 %[[VAL_157]], i32 
1, i32 0, i64 0, ptr @omp_taskloop_dup.2)
+// CHECK:         call void @__kmpc_end_taskgroup(ptr @1, i32 %[[VAL_151]])
+// CHECK:         br label %[[VAL_158:.*]]
+// CHECK:       taskloop.exit:                                    ; preds = 
%[[VAL_146]]
+// CHECK:         ret void
+
+// CHECK-LABEL: define internal void @_QPtest3..omp_par(
+// CHECK:       taskloop.alloca:
+// CHECK:         %[[VAL_159:.*]] = load ptr, ptr %[[VAL_160:.*]], align 8
+// CHECK:         %[[VAL_161:.*]] = getelementptr { i64, i64, i64, ptr }, ptr 
%[[VAL_159]], i32 0, i32 0
+// CHECK:         %[[VAL_162:.*]] = load i64, ptr %[[VAL_161]], align 4
+// CHECK:         %[[VAL_163:.*]] = getelementptr { i64, i64, i64, ptr }, ptr 
%[[VAL_159]], i32 0, i32 1
+// CHECK:         %[[VAL_164:.*]] = load i64, ptr %[[VAL_163]], align 4
+// CHECK:         %[[VAL_165:.*]] = getelementptr { i64, i64, i64, ptr }, ptr 
%[[VAL_159]], i32 0, i32 2
+// CHECK:         %[[VAL_166:.*]] = load i64, ptr %[[VAL_165]], align 4
+// CHECK:         %[[VAL_167:.*]] = getelementptr { i64, i64, i64, ptr }, ptr 
%[[VAL_159]], i32 0, i32 3
+// CHECK:         %[[VAL_168:.*]] = load ptr, ptr %[[VAL_167]], align 8, 
!align !1
+// CHECK:         %[[VAL_169:.*]] = alloca i32, align 4
+// CHECK:         br label %[[VAL_170:.*]]
+// CHECK:       taskloop.body:                                    ; preds = 
%[[VAL_171:.*]]
+// CHECK:         %[[VAL_172:.*]] = getelementptr { i32 }, ptr %[[VAL_168]], 
i32 0, i32 0
+// CHECK:         br label %[[VAL_173:.*]]
+// CHECK:       omp.taskloop.region:                              ; preds = 
%[[VAL_170]]
+// CHECK:         br label %[[VAL_174:.*]]
+// CHECK:       omp_loop.preheader:                               ; preds = 
%[[VAL_173]]
+// CHECK:         %[[VAL_175:.*]] = sub i64 %[[VAL_164]], %[[VAL_162]]
+// CHECK:         %[[VAL_176:.*]] = sdiv i64 %[[VAL_175]], 1
+// CHECK:         %[[VAL_177:.*]] = add i64 %[[VAL_176]], 1
+// CHECK:         %[[VAL_178:.*]] = trunc i64 %[[VAL_177]] to i32
+// CHECK:         %[[VAL_179:.*]] = trunc i64 %[[VAL_162]] to i32
+// CHECK:         br label %[[VAL_180:.*]]
+// CHECK:       omp_loop.header:                                  ; preds = 
%[[VAL_181:.*]], %[[VAL_174]]
+// CHECK:         %[[VAL_182:.*]] = phi i32 [ 0, %[[VAL_174]] ], [ 
%[[VAL_183:.*]], %[[VAL_181]] ]
+// CHECK:         br label %[[VAL_184:.*]]
+// CHECK:       omp_loop.cond:                                    ; preds = 
%[[VAL_180]]
+// CHECK:         %[[VAL_185:.*]] = icmp ult i32 %[[VAL_182]], %[[VAL_178]]
+// CHECK:         br i1 %[[VAL_185]], label %[[LOOP_BODY:omp_loop.body]], 
label %[[LOOP_EXIT:.*]]
+// CHECK:       omp_loop.exit:                                    ; preds = 
%[[VAL_184]]
+// CHECK:         br label %[[LOOP_AFTER:omp_loop.after]]
+// CHECK:       omp_loop.after:                                   ; preds = 
%[[LOOP_EXIT]]
+// CHECK:         br label %[[OMP_REGION_CONT:omp.region.cont]]
+// CHECK:       omp.region.cont:                                  ; preds = 
%[[FINI:.*]], %[[LOOP_AFTER]]
+// CHECK:         call void @_dealloc(ptr %[[VAL_172]])
+// CHECK:         tail call void @free(ptr %[[VAL_168]])
+// CHECK:         br label %[[VAL_191:.*]]
+// CHECK:       omp_loop.body:                                    ; preds = 
%[[VAL_184]]
+// CHECK:         %[[VAL_192:.*]] = mul i32 %[[VAL_182]], 1
+// CHECK:         %[[VAL_193:.*]] = add i32 %[[VAL_192]], %[[VAL_179]]
+// CHECK:         br label %[[VAL_194:.*]]
+// CHECK:       omp.loop_nest.region:                             ; preds = 
%[[LOOP_BODY]]
+// CHECK:         store i32 %[[VAL_193]], ptr %[[VAL_169]], align 4
+// CHECK:         call void @_QPbefore(ptr %[[VAL_172]])
+// IF CLAUSE:
+// CHECK:         br i1 true, label %[[CANCEL_IF_TRUE:.*]], label 
%[[CANCEL_IF_FALSE:.*]]
+// CHECK:       [[CANCEL_IF_FALSE]]:                                           
     ; preds = %[[VAL_194]]
+// CHECK:         %[[VAL_197:.*]] = call i32 @__kmpc_global_thread_num(ptr @1)
+// CHECK:         %[[VAL_198:.*]] = call i32 @__kmpc_cancellationpoint(ptr @1, 
i32 %[[VAL_197]], i32 4)
+// CHECK:         %[[VAL_199:.*]] = icmp eq i32 %[[VAL_198]], 0
+// CHECK:         br i1 %[[VAL_199]], label %[[CANCEL_IF_FALSE_CONT:.*]], 
label %[[CANCEL_IF_FALSE_CANCEL:.*]]
+// CHECK:       [[CANCEL_IF_FALSE_CANCEL]]:                       ; preds = 
%[[CANCEL_IF_FALSE]]
+// CHECK:         br label %[[FINI]]
+// CHECK:       [[FINI]]:                                         ; preds = 
%[[CANCEL_IF_TRUE_CANCEL:.*]], %[[CANCEL_IF_FALSE_CANCEL]]
+// CHECK:         br label %[[OMP_REGION_CONT]]
+// CHECK:       [[CANCEL_IF_FALSE_CONT]]:                         ; preds = 
%[[CANCEL_IF_FALSE]]
+// CHECK:         br label %[[AFTER:.*]]
+// CHECK:       [[AFTER]]:                                        ; preds = 
%[[CANCEL_IF_FALSE_CONT]], %[[CANCEL_IF_TRUE_CONT:.*]]
+// CHECK:         call void @_QPafter(ptr %[[VAL_172]])
+// CHECK:         br label %[[VAL_205:.*]]
+// CHECK:       omp.region.cont2:                                 ; preds = 
%[[AFTER]]
+// CHECK:         br label %[[VAL_181]]
+// CHECK:       omp_loop.inc:                                     ; preds = 
%[[VAL_205]]
+// CHECK:         %[[VAL_183]] = add nuw i32 %[[VAL_182]], 1
+// CHECK:         br label %[[VAL_180]]
+// CHECK:       [[CANCEL_IF_TRUE]]:                               ; preds = 
%[[VAL_194]]
+// CHECK:         %[[VAL_206:.*]] = call i32 @__kmpc_global_thread_num(ptr @1)
+// CHECK:         %[[VAL_207:.*]] = call i32 @__kmpc_cancel(ptr @1, i32 
%[[VAL_206]], i32 4)
+// CHECK:         %[[VAL_208:.*]] = icmp eq i32 %[[VAL_207]], 0
+// CHECK:         br i1 %[[VAL_208]], label %[[CANCEL_IF_TRUE_CONT]], label 
%[[CANCEL_IF_TRUE_CANCEL]]
+// CHECK:       [[CANCEL_IF_TRUE_CANCEL]]:                        ; preds = 
%[[CANCEL_IF_TRUE]]
+// CHECK:         br label %[[FINI]]
+// CHECK:       [[CANCEL_IF_TRUE_CONT]]:                          ; preds = 
%[[CANCEL_IF_TRUE]]
+// CHECK:         br label %[[AFTER]]
+// CHECK:       taskloop.exit.exitStub:                           ; preds = 
%[[OMP_REGION_CONT]]
+// CHECK:         ret void
+
+llvm.func @_QPbefore(!llvm.ptr) attributes {sym_visibility = "private"}
+llvm.func @_QPafter(!llvm.ptr) attributes {sym_visibility = "private"}
+llvm.func @_init(!llvm.ptr, !llvm.ptr) attributes {sym_visibility = "private"}
+llvm.func @_copy(!llvm.ptr, !llvm.ptr) attributes {sym_visibility = "private"}
+llvm.func @_dealloc(!llvm.ptr) attributes {sym_visibility = "private"}
diff --git a/mlir/test/Target/LLVMIR/openmp-taskloop-cancellation-point.mlir 
b/mlir/test/Target/LLVMIR/openmp-taskloop-cancellation-point.mlir
new file mode 100644
index 0000000000000..5d2dd9472421d
--- /dev/null
+++ b/mlir/test/Target/LLVMIR/openmp-taskloop-cancellation-point.mlir
@@ -0,0 +1,280 @@
+// RUN: mlir-translate -mlir-to-llvmir %s | FileCheck %s
+
+omp.private {type = private} @_QFtestEi_private_i32 : i32
+omp.private {type = firstprivate} @_QFtestEarg_firstprivate_i32 : i32 init {
+^bb0(%arg0: !llvm.ptr, %arg1: !llvm.ptr):
+  llvm.call @_init(%arg0, %arg1) : (!llvm.ptr, !llvm.ptr) -> ()
+  omp.yield(%arg1 : !llvm.ptr)
+} copy {
+^bb0(%arg0: !llvm.ptr, %arg1: !llvm.ptr):
+  llvm.call @_copy(%arg0, %arg1) : (!llvm.ptr, !llvm.ptr) -> ()
+  omp.yield(%arg1 : !llvm.ptr)
+} dealloc {
+^bb0(%arg0: !llvm.ptr):
+  llvm.call @_dealloc(%arg0) : (!llvm.ptr) -> ()
+  omp.yield
+}
+
+// Test cancelling implicit taskgroup created by taskloop
+llvm.func @_QPtest(%arg0: !llvm.ptr {fir.bindc_name = "arg", llvm.noalias, 
llvm.nocapture}) {
+  %0 = llvm.mlir.constant(1 : i32) : i32
+  %1 = llvm.mlir.constant(100 : i32) : i32
+  %2 = llvm.mlir.constant(1 : i64) : i64
+  %3 = llvm.alloca %2 x i32 {bindc_name = "i"} : (i64) -> !llvm.ptr
+  omp.taskloop private(@_QFtestEarg_firstprivate_i32 %arg0 -> %arg1, 
@_QFtestEi_private_i32 %3 -> %arg2 : !llvm.ptr, !llvm.ptr) {
+    omp.loop_nest (%arg3) : i32 = (%0) to (%1) inclusive step (%0) {
+      llvm.store %arg3, %arg2 : i32, !llvm.ptr
+      llvm.call @_QPbefore(%arg1) : (!llvm.ptr) -> ()
+      omp.cancellation_point cancellation_construct_type(taskgroup)
+      llvm.call @_QPafter(%arg1) : (!llvm.ptr) -> ()
+      omp.yield
+    }
+  }
+  llvm.return
+}
+// CHECK-LABEL: define void @_QPtest(
+// CHECK:         %[[STRUCTARG:.*]] = alloca { i64, i64, i64, ptr }, align 8
+// CHECK:         %[[VAL_0:.*]] = alloca i32, i64 1, align 4
+// CHECK:         br label %[[VAL_1:.*]]
+// CHECK:       entry:                                            ; preds = 
%[[VAL_2:.*]]
+// CHECK:         br label %[[VAL_3:.*]]
+// CHECK:       omp.private.init:                                 ; preds = 
%[[VAL_1]]
+// CHECK:         %[[VAL_4:.*]] = tail call ptr @malloc(i64 ptrtoint (ptr 
getelementptr ({ i32 }, ptr null, i32 1) to i64))
+// CHECK:         %[[VAL_5:.*]] = getelementptr { i32 }, ptr %[[VAL_4]], i32 
0, i32 0
+// CHECK:         call void @_init(ptr %[[VAL_6:.*]], ptr %[[VAL_5]])
+// CHECK:         br label %[[VAL_7:.*]]
+// CHECK:       omp.private.copy:                                 ; preds = 
%[[VAL_3]]
+// CHECK:         br label %[[VAL_8:.*]]
+// CHECK:       omp.private.copy1:                                ; preds = 
%[[VAL_7]]
+// CHECK:         call void @_copy(ptr %[[VAL_6]], ptr %[[VAL_5]])
+// CHECK:         br label %[[VAL_9:.*]]
+// CHECK:       omp.taskloop.start:                               ; preds = 
%[[VAL_8]]
+// CHECK:         br label %[[VAL_10:.*]]
+// CHECK:       codeRepl:                                         ; preds = 
%[[VAL_9]]
+// CHECK:         %[[VAL_11:.*]] = getelementptr { i64, i64, i64, ptr }, ptr 
%[[STRUCTARG]], i32 0, i32 0
+// CHECK:         store i64 1, ptr %[[VAL_11]], align 4
+// CHECK:         %[[VAL_12:.*]] = getelementptr { i64, i64, i64, ptr }, ptr 
%[[STRUCTARG]], i32 0, i32 1
+// CHECK:         store i64 100, ptr %[[VAL_12]], align 4
+// CHECK:         %[[VAL_13:.*]] = getelementptr { i64, i64, i64, ptr }, ptr 
%[[STRUCTARG]], i32 0, i32 2
+// CHECK:         store i64 1, ptr %[[VAL_13]], align 4
+// CHECK:         %[[VAL_14:.*]] = getelementptr { i64, i64, i64, ptr }, ptr 
%[[STRUCTARG]], i32 0, i32 3
+// CHECK:         store ptr %[[VAL_4]], ptr %[[VAL_14]], align 8
+// CHECK:         %[[VAL_15:.*]] = call i32 @__kmpc_global_thread_num(ptr @1)
+// CHECK:         call void @__kmpc_taskgroup(ptr @1, i32 %[[VAL_15]])
+// CHECK:         %[[VAL_16:.*]] = call ptr @__kmpc_omp_task_alloc(ptr @1, i32 
%[[VAL_15]], i32 1, i64 40, i64 32, ptr @_QPtest..omp_par)
+// CHECK:         %[[VAL_17:.*]] = load ptr, ptr %[[VAL_16]], align 8
+// CHECK:         call void @llvm.memcpy.p0.p0.i64(ptr align 1 %[[VAL_17]], 
ptr align 1 %[[STRUCTARG]], i64 32, i1 false)
+// CHECK:         %[[VAL_18:.*]] = getelementptr { i64, i64, i64, ptr }, ptr 
%[[VAL_17]], i32 0, i32 0
+// CHECK:         %[[VAL_19:.*]] = getelementptr { i64, i64, i64, ptr }, ptr 
%[[VAL_17]], i32 0, i32 1
+// CHECK:         %[[VAL_20:.*]] = getelementptr { i64, i64, i64, ptr }, ptr 
%[[VAL_17]], i32 0, i32 2
+// CHECK:         %[[VAL_21:.*]] = load i64, ptr %[[VAL_20]], align 4
+// CHECK:         call void @__kmpc_taskloop(ptr @1, i32 %[[VAL_15]], ptr 
%[[VAL_16]], i32 1, ptr %[[VAL_18]], ptr %[[VAL_19]], i64 %[[VAL_21]], i32 1, 
i32 0, i64 0, ptr @omp_taskloop_dup)
+// CHECK:         call void @__kmpc_end_taskgroup(ptr @1, i32 %[[VAL_15]])
+// CHECK:         br label %[[VAL_22:.*]]
+// CHECK:       taskloop.exit:                                    ; preds = 
%[[VAL_10]]
+// CHECK:         ret void
+
+// CHECK-LABEL: define internal void @_QPtest..omp_par
+// CHECK:       taskloop.alloca:
+// CHECK:         %[[VAL_23:.*]] = load ptr, ptr %[[VAL_24:.*]], align 8
+// CHECK:         %[[VAL_25:.*]] = getelementptr { i64, i64, i64, ptr }, ptr 
%[[VAL_23]], i32 0, i32 0
+// CHECK:         %[[VAL_26:.*]] = load i64, ptr %[[VAL_25]], align 4
+// CHECK:         %[[VAL_27:.*]] = getelementptr { i64, i64, i64, ptr }, ptr 
%[[VAL_23]], i32 0, i32 1
+// CHECK:         %[[VAL_28:.*]] = load i64, ptr %[[VAL_27]], align 4
+// CHECK:         %[[VAL_29:.*]] = getelementptr { i64, i64, i64, ptr }, ptr 
%[[VAL_23]], i32 0, i32 2
+// CHECK:         %[[VAL_30:.*]] = load i64, ptr %[[VAL_29]], align 4
+// CHECK:         %[[VAL_31:.*]] = getelementptr { i64, i64, i64, ptr }, ptr 
%[[VAL_23]], i32 0, i32 3
+// CHECK:         %[[VAL_32:.*]] = load ptr, ptr %[[VAL_31]], align 8, !align 
!1
+// CHECK:         %[[VAL_33:.*]] = alloca i32, align 4
+// CHECK:         br label %[[VAL_34:.*]]
+// CHECK:       taskloop.body:                                    ; preds = 
%[[VAL_35:.*]]
+// CHECK:         %[[VAL_36:.*]] = getelementptr { i32 }, ptr %[[VAL_32]], i32 
0, i32 0
+// CHECK:         br label %[[VAL_37:.*]]
+// CHECK:       omp.taskloop.region:                              ; preds = 
%[[VAL_34]]
+// CHECK:         br label %[[VAL_38:.*]]
+// CHECK:       omp_loop.preheader:                               ; preds = 
%[[VAL_37]]
+// CHECK:         %[[VAL_39:.*]] = sub i64 %[[VAL_28]], %[[VAL_26]]
+// CHECK:         %[[VAL_40:.*]] = sdiv i64 %[[VAL_39]], 1
+// CHECK:         %[[VAL_41:.*]] = add i64 %[[VAL_40]], 1
+// CHECK:         %[[VAL_42:.*]] = trunc i64 %[[VAL_41]] to i32
+// CHECK:         %[[VAL_43:.*]] = trunc i64 %[[VAL_26]] to i32
+// CHECK:         br label %[[VAL_44:.*]]
+// CHECK:       omp_loop.header:                                  ; preds = 
%[[VAL_45:.*]], %[[VAL_38]]
+// CHECK:         %[[VAL_46:.*]] = phi i32 [ 0, %[[VAL_38]] ], [ 
%[[VAL_47:.*]], %[[VAL_45]] ]
+// CHECK:         br label %[[VAL_48:.*]]
+// CHECK:       omp_loop.cond:                                    ; preds = 
%[[VAL_44]]
+// CHECK:         %[[VAL_49:.*]] = icmp ult i32 %[[VAL_46]], %[[VAL_42]]
+// CHECK:         br i1 %[[VAL_49]], label %[[VAL_50:omp_loop.body]], label 
%[[VAL_51:omp_loop.exit]]
+// CHECK:       omp_loop.exit:                                    ; preds = 
%[[VAL_48]]
+// CHECK:         br label %[[OMP_LOOP_AFTER:omp_loop.after]]
+// CHECK:       omp_loop.after:                                   ; preds = 
%[[VAL_51]]
+// CHECK:         br label %[[CONT:omp.region.cont]]
+// CHECK:       omp.region.cont:                                  ; preds = 
%[[FINI:.fini]], %[[OMP_LOOP_AFTER]]
+// CHECK:         call void @_dealloc(ptr %[[VAL_36]])
+// CHECK:         tail call void @free(ptr %[[VAL_32]])
+// CHECK:         br label %[[VAL_55:.*]]
+// CHECK:       omp_loop.body:                                    ; preds = 
%[[VAL_48]]
+// CHECK:         %[[VAL_56:.*]] = mul i32 %[[VAL_46]], 1
+// CHECK:         %[[VAL_57:.*]] = add i32 %[[VAL_56]], %[[VAL_43]]
+// CHECK:         br label %[[LOOP_REGION:omp.loop_nest.region]]
+// CHECK:       omp.loop_nest.region:                             ; preds = 
%[[VAL_50]]
+// CHECK:         store i32 %[[VAL_57]], ptr %[[VAL_33]], align 4
+// CHECK:         call void @_QPbefore(ptr %[[VAL_36]])
+// CHECK:         %[[VAL_59:.*]] = call i32 @__kmpc_global_thread_num(ptr @1)
+// CHECK:         %[[VAL_60:.*]] = call i32 @__kmpc_cancellationpoint(ptr @1, 
i32 %[[VAL_59]], i32 4)
+// CHECK:         %[[VAL_61:.*]] = icmp eq i32 %[[VAL_60]], 0
+// CHECK:         br i1 %[[VAL_61]], label 
%[[VAL_62:omp.loop_nest.region.split]], label 
%[[CNCL:omp.loop_nest.region.cncl]]
+// CHECK:       omp.loop_nest.region.cncl:                        ; preds = 
%[[LOOP_REGION]]
+// CHECK:         br label %[[FINI]]
+// CHECK:       .fini:                                            ; preds = 
%[[CNCL]]
+// CHECK:         br label %[[CONT]]
+// CHECK:       omp.loop_nest.region.split:                       ; preds = 
%[[LOOP_REGION]]
+// CHECK:         call void @_QPafter(ptr %[[VAL_36]])
+// CHECK:         br label %[[VAL_64:.*]]
+// CHECK:       omp.region.cont2:                                 ; preds = 
%[[VAL_62]]
+// CHECK:         br label %[[VAL_45]]
+// CHECK:       omp_loop.inc:                                     ; preds = 
%[[VAL_64]]
+// CHECK:         %[[VAL_47]] = add nuw i32 %[[VAL_46]], 1
+// CHECK:         br label %[[VAL_44]]
+// CHECK:       taskloop.exit.exitStub:                           ; preds = 
%[[CONT]]
+// CHECK:         ret void
+
+// Tesk cancelling explicit taskgroup enclosing taskloop
+llvm.func @_QPtest2(%arg0: !llvm.ptr {fir.bindc_name = "arg", llvm.noalias, 
llvm.nocapture}) {
+  %0 = llvm.mlir.constant(1 : i32) : i32
+  %1 = llvm.mlir.constant(100 : i32) : i32
+  %2 = llvm.mlir.constant(1 : i64) : i64
+  %3 = llvm.alloca %2 x i32 {bindc_name = "i"} : (i64) -> !llvm.ptr
+  omp.taskgroup {
+    omp.taskloop nogroup private(@_QFtestEarg_firstprivate_i32 %arg0 -> %arg1, 
@_QFtestEi_private_i32 %3 -> %arg2 : !llvm.ptr, !llvm.ptr) {
+      omp.loop_nest (%arg3) : i32 = (%0) to (%1) inclusive step (%0) {
+        llvm.store %arg3, %arg2 : i32, !llvm.ptr
+        llvm.call @_QPbefore(%arg1) : (!llvm.ptr) -> ()
+        omp.cancellation_point cancellation_construct_type(taskgroup)
+        llvm.call @_QPafter(%arg1) : (!llvm.ptr) -> ()
+        omp.yield
+      }
+    }
+    omp.terminator
+  }
+  llvm.return
+}
+// CHECK-LABEL: define void @_QPtest2(
+// CHECK:         %[[VAL_65:.*]] = alloca { i64, i64, i64, ptr }, align 8
+// CHECK:         %[[VAL_66:.*]] = alloca i32, i64 1, align 4
+// CHECK:         br label %[[VAL_67:.*]]
+// CHECK:       entry:                                            ; preds = 
%[[VAL_68:.*]]
+// CHECK:         %[[VAL_69:.*]] = call i32 @__kmpc_global_thread_num(ptr @1)
+// CHECK:         call void @__kmpc_taskgroup(ptr @1, i32 %[[VAL_69]])
+// CHECK:         br label %[[VAL_70:.*]]
+// CHECK:       omp.taskgroup.region:                             ; preds = 
%[[VAL_67]]
+// CHECK:         br label %[[VAL_71:.*]]
+// CHECK:       omp.private.init:                                 ; preds = 
%[[VAL_70]]
+// CHECK:         %[[VAL_72:.*]] = tail call ptr @malloc(i64 ptrtoint (ptr 
getelementptr ({ i32 }, ptr null, i32 1) to i64))
+// CHECK:         %[[VAL_73:.*]] = getelementptr { i32 }, ptr %[[VAL_72]], i32 
0, i32 0
+// CHECK:         call void @_init(ptr %[[VAL_74:.*]], ptr %[[VAL_73]])
+// CHECK:         br label %[[VAL_75:.*]]
+// CHECK:       omp.private.copy:                                 ; preds = 
%[[VAL_71]]
+// CHECK:         br label %[[VAL_76:.*]]
+// CHECK:       omp.private.copy1:                                ; preds = 
%[[VAL_75]]
+// CHECK:         call void @_copy(ptr %[[VAL_74]], ptr %[[VAL_73]])
+// CHECK:         br label %[[VAL_77:.*]]
+// CHECK:       omp.region.cont:                                  ; preds = 
%[[VAL_78:.*]]
+// CHECK:         br label %[[VAL_79:.*]]
+// CHECK:       taskgroup.exit:                                   ; preds = 
%[[VAL_80:.*]]
+// CHECK:         call void @__kmpc_end_taskgroup(ptr @1, i32 %[[VAL_69]])
+// CHECK:         ret void
+// CHECK:       omp.taskloop.start:                               ; preds = 
%[[VAL_76]]
+// CHECK:         br label %[[VAL_81:.*]]
+// CHECK:       codeRepl:                                         ; preds = 
%[[VAL_77]]
+// CHECK:         %[[VAL_82:.*]] = getelementptr { i64, i64, i64, ptr }, ptr 
%[[VAL_65]], i32 0, i32 0
+// CHECK:         store i64 1, ptr %[[VAL_82]], align 4
+// CHECK:         %[[VAL_83:.*]] = getelementptr { i64, i64, i64, ptr }, ptr 
%[[VAL_65]], i32 0, i32 1
+// CHECK:         store i64 100, ptr %[[VAL_83]], align 4
+// CHECK:         %[[VAL_84:.*]] = getelementptr { i64, i64, i64, ptr }, ptr 
%[[VAL_65]], i32 0, i32 2
+// CHECK:         store i64 1, ptr %[[VAL_84]], align 4
+// CHECK:         %[[VAL_85:.*]] = getelementptr { i64, i64, i64, ptr }, ptr 
%[[VAL_65]], i32 0, i32 3
+// CHECK:         store ptr %[[VAL_72]], ptr %[[VAL_85]], align 8
+// CHECK:         %[[VAL_86:.*]] = call i32 @__kmpc_global_thread_num(ptr @1)
+// CHECK:         %[[VAL_87:.*]] = call ptr @__kmpc_omp_task_alloc(ptr @1, i32 
%[[VAL_86]], i32 1, i64 40, i64 32, ptr @_QPtest2..omp_par)
+// CHECK:         %[[VAL_88:.*]] = load ptr, ptr %[[VAL_87]], align 8
+// CHECK:         call void @llvm.memcpy.p0.p0.i64(ptr align 1 %[[VAL_88]], 
ptr align 1 %[[VAL_65]], i64 32, i1 false)
+// CHECK:         %[[VAL_89:.*]] = getelementptr { i64, i64, i64, ptr }, ptr 
%[[VAL_88]], i32 0, i32 0
+// CHECK:         %[[VAL_90:.*]] = getelementptr { i64, i64, i64, ptr }, ptr 
%[[VAL_88]], i32 0, i32 1
+// CHECK:         %[[VAL_91:.*]] = getelementptr { i64, i64, i64, ptr }, ptr 
%[[VAL_88]], i32 0, i32 2
+// CHECK:         %[[VAL_92:.*]] = load i64, ptr %[[VAL_91]], align 4
+// CHECK:         call void @__kmpc_taskloop(ptr @1, i32 %[[VAL_86]], ptr 
%[[VAL_87]], i32 1, ptr %[[VAL_89]], ptr %[[VAL_90]], i64 %[[VAL_92]], i32 1, 
i32 0, i64 0, ptr @omp_taskloop_dup.1)
+// CHECK:         br label %[[VAL_78]]
+// CHECK:       taskloop.exit:                                    ; preds = 
%[[VAL_81]]
+// CHECK:         br label %[[VAL_80]]
+
+// CHECK-LABEL: define internal void @_QPtest2..omp_par(
+// CHECK:       taskloop.alloca:
+// CHECK:         %[[VAL_93:.*]] = load ptr, ptr %[[VAL_94:.*]], align 8
+// CHECK:         %[[VAL_95:.*]] = getelementptr { i64, i64, i64, ptr }, ptr 
%[[VAL_93]], i32 0, i32 0
+// CHECK:         %[[VAL_96:.*]] = load i64, ptr %[[VAL_95]], align 4
+// CHECK:         %[[VAL_97:.*]] = getelementptr { i64, i64, i64, ptr }, ptr 
%[[VAL_93]], i32 0, i32 1
+// CHECK:         %[[VAL_98:.*]] = load i64, ptr %[[VAL_97]], align 4
+// CHECK:         %[[VAL_99:.*]] = getelementptr { i64, i64, i64, ptr }, ptr 
%[[VAL_93]], i32 0, i32 2
+// CHECK:         %[[VAL_100:.*]] = load i64, ptr %[[VAL_99]], align 4
+// CHECK:         %[[VAL_101:.*]] = getelementptr { i64, i64, i64, ptr }, ptr 
%[[VAL_93]], i32 0, i32 3
+// CHECK:         %[[VAL_102:.*]] = load ptr, ptr %[[VAL_101]], align 8, 
!align !1
+// CHECK:         %[[VAL_103:.*]] = alloca i32, align 4
+// CHECK:         br label %[[VAL_104:.*]]
+// CHECK:       taskloop.body:                                    ; preds = 
%[[VAL_105:.*]]
+// CHECK:         %[[VAL_106:.*]] = getelementptr { i32 }, ptr %[[VAL_102]], 
i32 0, i32 0
+// CHECK:         br label %[[VAL_107:.*]]
+// CHECK:       omp.taskloop.region:                              ; preds = 
%[[VAL_104]]
+// CHECK:         br label %[[VAL_108:.*]]
+// CHECK:       omp_loop.preheader:                               ; preds = 
%[[VAL_107]]
+// CHECK:         %[[VAL_109:.*]] = sub i64 %[[VAL_98]], %[[VAL_96]]
+// CHECK:         %[[VAL_110:.*]] = sdiv i64 %[[VAL_109]], 1
+// CHECK:         %[[VAL_111:.*]] = add i64 %[[VAL_110]], 1
+// CHECK:         %[[VAL_112:.*]] = trunc i64 %[[VAL_111]] to i32
+// CHECK:         %[[VAL_113:.*]] = trunc i64 %[[VAL_96]] to i32
+// CHECK:         br label %[[VAL_114:.*]]
+// CHECK:       omp_loop.header:                                  ; preds = 
%[[VAL_115:.*]], %[[VAL_108]]
+// CHECK:         %[[VAL_116:.*]] = phi i32 [ 0, %[[VAL_108]] ], [ 
%[[VAL_117:.*]], %[[VAL_115]] ]
+// CHECK:         br label %[[VAL_118:.*]]
+// CHECK:       omp_loop.cond:                                    ; preds = 
%[[VAL_114]]
+// CHECK:         %[[VAL_119:.*]] = icmp ult i32 %[[VAL_116]], %[[VAL_112]]
+// CHECK:         br i1 %[[VAL_119]], label %[[VAL_120:.*]], label 
%[[VAL_121:.*]]
+// CHECK:       omp_loop.exit:                                    ; preds = 
%[[VAL_118]]
+// CHECK:         br label %[[VAL_122:.*]]
+// CHECK:       omp_loop.after:                                   ; preds = 
%[[VAL_121]]
+// CHECK:         br label %[[VAL_123:omp.region.cont2]]
+// CHECK:       omp.region.cont2:                                 ; preds = 
%[[VAL_124:.fini]], %[[VAL_122]]
+// CHECK:         call void @_dealloc(ptr %[[VAL_106]])
+// CHECK:         tail call void @free(ptr %[[VAL_102]])
+// CHECK:         br label %[[VAL_125:.*]]
+// CHECK:       omp_loop.body:                                    ; preds = 
%[[VAL_118]]
+// CHECK:         %[[VAL_126:.*]] = mul i32 %[[VAL_116]], 1
+// CHECK:         %[[VAL_127:.*]] = add i32 %[[VAL_126]], %[[VAL_113]]
+// CHECK:         br label %[[VAL_128:.*]]
+// CHECK:       omp.loop_nest.region:                             ; preds = 
%[[VAL_120]]
+// CHECK:         store i32 %[[VAL_127]], ptr %[[VAL_103]], align 4
+// CHECK:         call void @_QPbefore(ptr %[[VAL_106]])
+// CHECK:         %[[VAL_129:.*]] = call i32 @__kmpc_global_thread_num(ptr @1)
+// CHECK:         %[[VAL_130:.*]] = call i32 @__kmpc_cancellationpoint(ptr @1, 
i32 %[[VAL_129]], i32 4)
+// CHECK:         %[[VAL_131:.*]] = icmp eq i32 %[[VAL_130]], 0
+// CHECK:         br i1 %[[VAL_131]], label 
%[[VAL_132:omp.loop_nest.region.split]], label 
%[[VAL_133:omp.loop_nest.region.cncl]]
+// CHECK:       omp.loop_nest.region.cncl:                        ; preds = 
%[[VAL_128]]
+// CHECK:         br label %[[VAL_124]]
+// CHECK:       .fini:                                            ; preds = 
%[[VAL_133]]
+// CHECK:         br label %[[VAL_123]]
+// CHECK:       omp.loop_nest.region.split:                       ; preds = 
%[[VAL_128]]
+// CHECK:         call void @_QPafter(ptr %[[VAL_106]])
+// CHECK:         br label %[[VAL_134:.*]]
+// CHECK:       omp.region.cont3:                                 ; preds = 
%[[VAL_132]]
+// CHECK:         br label %[[VAL_115]]
+// CHECK:       omp_loop.inc:                                     ; preds = 
%[[VAL_134]]
+// CHECK:         %[[VAL_117]] = add nuw i32 %[[VAL_116]], 1
+// CHECK:         br label %[[VAL_114]]
+// CHECK:       taskloop.exit.exitStub:                           ; preds = 
%[[VAL_123]]
+// CHECK:         ret void
+
+llvm.func @_QPbefore(!llvm.ptr) attributes {sym_visibility = "private"}
+llvm.func @_QPafter(!llvm.ptr) attributes {sym_visibility = "private"}
+llvm.func @_init(!llvm.ptr, !llvm.ptr) attributes {sym_visibility = "private"}
+llvm.func @_copy(!llvm.ptr, !llvm.ptr) attributes {sym_visibility = "private"}
+llvm.func @_dealloc(!llvm.ptr) attributes {sym_visibility = "private"}

_______________________________________________
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits

Reply via email to