[Mlir-commits] [mlir] [mlir][OpenMP] Avoid privatization barriers in partial-team regions (PR #229413)

Tom Eccles llvmlistbot at llvm.org
Tue Oct 6 08:09:42 PDT 2026


https://github.com/tblah updated https://github.com/llvm/llvm-project/pull/229413

>From 97d7f39f32968f350fe82e8c8da0aefe5d042f7e Mon Sep 17 00:00:00 2001
From: Tom Eccles <tom.eccles at arm.com>
Date: Tue, 29 Sep 2026 12:08:55 +0100
Subject: [PATCH 1/3] [mlir][OpenMP] Avoid privatization barriers in
 partial-team regions

A compiler-generated privatization barrier under masked, master,
critical, single, or section can wait for team threads that never
reach it.

Check whether the current operation might safely reach a barrier
with its whole team, stopping at the nearest parallel region.

Assisted-by: Codex
---
 .../OpenMP/OpenMPToLLVMIRTranslation.cpp      |  26 ++-
 .../openmp-private-barrier-participation.mlir | 190 ++++++++++++++++++
 2 files changed, 202 insertions(+), 14 deletions(-)
 create mode 100644 mlir/test/Target/LLVMIR/openmp-private-barrier-participation.mlir

diff --git a/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp b/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp
index 3e970ab01dd1b..f9c20c7fa3457 100644
--- a/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp
+++ b/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp
@@ -2131,30 +2131,28 @@ static llvm::Expected<llvm::BasicBlock *> allocatePrivateVars(
   return afterAllocatorAllocations ? afterAllocatorAllocations : afterAllocas;
 }
 
-/// This can't always be determined statically, but when we can, it is good to
-/// avoid generating compiler-added barriers which will deadlock the program.
-static bool opIsInSingleThread(mlir::Operation *op) {
-  for (mlir::Operation *parent = op->getParentOp(); parent != nullptr;
+/// A compiler-generated barrier is unsafe when only part of the current team
+/// can reach it. This cannot always be determined statically (e.g. across a
+/// function call), but the enclosing OpenMP constructs can rule it out.
+static bool opMightBeSafeForBarriers(mlir::Operation *op) {
+  for (mlir::Operation *parent = op; parent != nullptr;
        parent = parent->getParentOp()) {
-    if (mlir::isa<omp::SingleOp, omp::CriticalOp>(parent))
+    // An inner parallel construct creates a new team, even when it is nested
+    // inside a construct that only some threads of the outer team encounter.
+    if (mlir::isa<omp::ParallelOp>(parent))
       return true;
 
-    // e.g.
-    // omp.single {
-    //   omp.parallel {
-    //     op
-    //   }
-    // }
-    if (mlir::isa<omp::ParallelOp>(parent))
+    if (mlir::isa<omp::SingleOp, omp::CriticalOp, omp::MaskedOp, omp::MasterOp,
+                  omp::SectionOp>(parent))
       return false;
   }
-  return false;
+  return true;
 }
 
 static LogicalResult
 emitPrivatizationBarrier(mlir::Operation *op, llvm::IRBuilderBase &builder,
                          LLVM::ModuleTranslation &moduleTranslation) {
-  if (opIsInSingleThread(op))
+  if (!opMightBeSafeForBarriers(op))
     return success();
 
   llvm::OpenMPIRBuilder *ompBuilder = moduleTranslation.getOpenMPBuilder();
diff --git a/mlir/test/Target/LLVMIR/openmp-private-barrier-participation.mlir b/mlir/test/Target/LLVMIR/openmp-private-barrier-participation.mlir
new file mode 100644
index 0000000000000..481e58fb260d0
--- /dev/null
+++ b/mlir/test/Target/LLVMIR/openmp-private-barrier-participation.mlir
@@ -0,0 +1,190 @@
+// RUN: mlir-translate -mlir-to-llvmir %s | FileCheck %s
+
+// A privatization barrier needs every thread in its team to reach it. These
+// constructs select or serialize threads, even when more than one thread can
+// execute the region over time.
+
+omp.private {type = private} @private_i32 : i32
+omp.private {type = firstprivate} @firstprivate_i32 : i32 copy {
+^bb0(%from: !llvm.ptr, %to: !llvm.ptr):
+  %value = llvm.load %from : !llvm.ptr -> i32
+  llvm.store %value, %to : i32, !llvm.ptr
+  omp.yield(%to : !llvm.ptr)
+}
+
+// CHECK-LABEL: define void @masked_private(
+llvm.func @masked_private(%ptr: !llvm.ptr, %filter: i32) {
+  %lo = llvm.mlir.constant(1 : i32) : i32
+  %hi = llvm.mlir.constant(2 : i32) : i32
+  %step = llvm.mlir.constant(1 : i32) : i32
+  omp.parallel {
+    omp.masked filter(%filter : i32) {
+      omp.taskloop.context private(@private_i32 %ptr -> %arg0 : !llvm.ptr) private_barrier {
+        omp.taskloop.wrapper {
+          omp.loop_nest (%i) : i32 = (%lo) to (%hi) inclusive step (%step) {
+            llvm.store %i, %arg0 : i32, !llvm.ptr
+            omp.yield
+          }
+        }
+        omp.terminator
+      } {omp.combined}
+      omp.terminator
+    }
+    omp.terminator
+  }
+  llvm.return
+}
+// CHECK: omp.private.copy:
+// CHECK-NOT: call void @__kmpc_barrier
+// CHECK: br label %omp.taskloop.wrapper.start
+
+// The old firstprivate path needs the same protection.
+// CHECK-LABEL: define void @masked_firstprivate(
+llvm.func @masked_firstprivate(%ptr: !llvm.ptr, %filter: i32) {
+  %lo = llvm.mlir.constant(1 : i32) : i32
+  %hi = llvm.mlir.constant(2 : i32) : i32
+  %step = llvm.mlir.constant(1 : i32) : i32
+  omp.parallel {
+    omp.masked filter(%filter : i32) {
+      omp.taskloop.context private(@firstprivate_i32 %ptr -> %arg0 : !llvm.ptr) private_barrier {
+        omp.taskloop.wrapper {
+          omp.loop_nest (%i) : i32 = (%lo) to (%hi) inclusive step (%step) {
+            llvm.store %i, %arg0 : i32, !llvm.ptr
+            omp.yield
+          }
+        }
+        omp.terminator
+      } {omp.combined}
+      omp.terminator
+    }
+    omp.terminator
+  }
+  llvm.return
+}
+// CHECK: omp.private.copy{{[0-9]*}}:
+// CHECK-NOT: call void @__kmpc_barrier
+// CHECK: br label %omp.taskloop.wrapper.start
+
+// CHECK-LABEL: define void @master_private(
+llvm.func @master_private(%ptr: !llvm.ptr) {
+  %lo = llvm.mlir.constant(1 : i32) : i32
+  %hi = llvm.mlir.constant(2 : i32) : i32
+  %step = llvm.mlir.constant(1 : i32) : i32
+  omp.parallel {
+    omp.master {
+      omp.taskloop.context private(@private_i32 %ptr -> %arg0 : !llvm.ptr) private_barrier {
+        omp.taskloop.wrapper {
+          omp.loop_nest (%i) : i32 = (%lo) to (%hi) inclusive step (%step) {
+            llvm.store %i, %arg0 : i32, !llvm.ptr
+            omp.yield
+          }
+        }
+        omp.terminator
+      } {omp.combined}
+      omp.terminator
+    }
+    omp.terminator
+  }
+  llvm.return
+}
+// CHECK: omp.private.copy:
+// CHECK-NOT: call void @__kmpc_barrier
+// CHECK: br label %omp.taskloop.wrapper.start
+
+// CHECK-LABEL: define void @critical_private(
+llvm.func @critical_private(%ptr: !llvm.ptr) {
+  %lo = llvm.mlir.constant(1 : i32) : i32
+  %hi = llvm.mlir.constant(2 : i32) : i32
+  %step = llvm.mlir.constant(1 : i32) : i32
+  omp.parallel {
+    omp.critical {
+      omp.taskloop.context private(@private_i32 %ptr -> %arg0 : !llvm.ptr) private_barrier {
+        omp.taskloop.wrapper {
+          omp.loop_nest (%i) : i32 = (%lo) to (%hi) inclusive step (%step) {
+            llvm.store %i, %arg0 : i32, !llvm.ptr
+            omp.yield
+          }
+        }
+        omp.terminator
+      } {omp.combined}
+      omp.terminator
+    }
+    omp.terminator
+  }
+  llvm.return
+}
+// CHECK: omp.private.copy:
+// CHECK-NOT: call void @__kmpc_barrier
+// CHECK: br label %omp.taskloop.wrapper.start
+
+// CHECK-LABEL: define void @single_private(
+llvm.func @single_private(%ptr: !llvm.ptr) {
+  %lo = llvm.mlir.constant(1 : i32) : i32
+  %hi = llvm.mlir.constant(2 : i32) : i32
+  %step = llvm.mlir.constant(1 : i32) : i32
+  omp.parallel {
+    omp.single {
+      omp.taskloop.context private(@private_i32 %ptr -> %arg0 : !llvm.ptr) private_barrier {
+        omp.taskloop.wrapper {
+          omp.loop_nest (%i) : i32 = (%lo) to (%hi) inclusive step (%step) {
+            llvm.store %i, %arg0 : i32, !llvm.ptr
+            omp.yield
+          }
+        }
+        omp.terminator
+      } {omp.combined}
+      omp.terminator
+    }
+    omp.terminator
+  }
+  llvm.return
+}
+// CHECK: omp.private.copy:
+// CHECK-NOT: call void @__kmpc_barrier
+// CHECK: br label %omp.taskloop.wrapper.start
+
+// CHECK-LABEL: define void @section_private(
+llvm.func @section_private(%ptr: !llvm.ptr) {
+  %lo = llvm.mlir.constant(1 : i32) : i32
+  %hi = llvm.mlir.constant(2 : i32) : i32
+  %step = llvm.mlir.constant(1 : i32) : i32
+  omp.parallel {
+    omp.sections {
+      omp.section {
+        omp.taskloop.context private(@private_i32 %ptr -> %arg0 : !llvm.ptr) private_barrier {
+          omp.taskloop.wrapper {
+            omp.loop_nest (%i) : i32 = (%lo) to (%hi) inclusive step (%step) {
+              llvm.store %i, %arg0 : i32, !llvm.ptr
+              omp.yield
+            }
+          }
+          omp.terminator
+        } {omp.combined}
+        omp.terminator
+      }
+      omp.terminator
+    }
+    omp.terminator
+  }
+  llvm.return
+}
+// CHECK: omp.private.copy:
+// CHECK-NOT: call void @__kmpc_barrier
+// CHECK: br label %omp.taskloop.wrapper.start
+
+// A nested parallel region creates a new team whose members all enter its
+// privatization code, even when only one outer-team thread launches it.
+// CHECK-LABEL: define void @nested_parallel_private(
+llvm.func @nested_parallel_private(%ptr: !llvm.ptr, %filter: i32) {
+  omp.parallel {
+    omp.masked filter(%filter : i32) {
+      omp.parallel private(@private_i32 %ptr -> %arg0 : !llvm.ptr) private_barrier {
+        omp.terminator
+      }
+      omp.terminator
+    }
+    omp.terminator
+  }
+  llvm.return
+}
+// CHECK: call void @__kmpc_barrier

>From 73af46b1a0784d53b230a2ff9541aa5397684573 Mon Sep 17 00:00:00 2001
From: Tom Eccles <tom.eccles at arm.com>
Date: Tue, 6 Oct 2026 15:39:05 +0100
Subject: [PATCH 2/3] Fix test nits

Assisted-by: Codex
---
 .../Target/LLVMIR/openmp-private-barrier-participation.mlir  | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/mlir/test/Target/LLVMIR/openmp-private-barrier-participation.mlir b/mlir/test/Target/LLVMIR/openmp-private-barrier-participation.mlir
index 481e58fb260d0..f107eae33ad53 100644
--- a/mlir/test/Target/LLVMIR/openmp-private-barrier-participation.mlir
+++ b/mlir/test/Target/LLVMIR/openmp-private-barrier-participation.mlir
@@ -38,7 +38,7 @@ llvm.func @masked_private(%ptr: !llvm.ptr, %filter: i32) {
 // CHECK-NOT: call void @__kmpc_barrier
 // CHECK: br label %omp.taskloop.wrapper.start
 
-// The old firstprivate path needs the same protection.
+// A firstprivate copy must also avoid a barrier inside a masked region.
 // CHECK-LABEL: define void @masked_firstprivate(
 llvm.func @masked_firstprivate(%ptr: !llvm.ptr, %filter: i32) {
   %lo = llvm.mlir.constant(1 : i32) : i32
@@ -187,4 +187,7 @@ llvm.func @nested_parallel_private(%ptr: !llvm.ptr, %filter: i32) {
   }
   llvm.return
 }
+// CHECK-LABEL: define internal void @nested_parallel_private..omp_par(
+// CHECK: omp.private.init:
+// CHECK-NOT: br{{[[:space:]]}}
 // CHECK: call void @__kmpc_barrier

>From 90ce78e9754bf08b0d0a6a1fd38e853aa53933af Mon Sep 17 00:00:00 2001
From: Tom Eccles <tom.eccles at arm.com>
Date: Tue, 6 Oct 2026 15:59:07 +0100
Subject: [PATCH 3/3] Merge privatization barrier tests

Rename the combined file to reflect its broader coverage.

Assisted-by: Codex
---
 .../LLVMIR/openmp-private-barrier-single.mlir | 88 -------------------
 ...ation.mlir => openmp-private-barrier.mlir} | 87 ++++++++++++++++++
 2 files changed, 87 insertions(+), 88 deletions(-)
 delete mode 100644 mlir/test/Target/LLVMIR/openmp-private-barrier-single.mlir
 rename mlir/test/Target/LLVMIR/{openmp-private-barrier-participation.mlir => openmp-private-barrier.mlir} (64%)

diff --git a/mlir/test/Target/LLVMIR/openmp-private-barrier-single.mlir b/mlir/test/Target/LLVMIR/openmp-private-barrier-single.mlir
deleted file mode 100644
index 0c003db0903da..0000000000000
--- a/mlir/test/Target/LLVMIR/openmp-private-barrier-single.mlir
+++ /dev/null
@@ -1,88 +0,0 @@
-// RUN: mlir-translate -mlir-to-llvmir %s | FileCheck %s
-
-// Tests that no privatization barrier is added for operations inside of SINGLE.
-// The specific combination here (wsloop inside of single) may not be valid
-// OpenMP. This combination was chosen so that this patch did not have to wait
-// for taskloop support. If it ever becomes a problem having a wsloop inside
-// of single, this can be updated to use taskloop.
-
-omp.private {type = private} @_QFwsloop_privateEi_private_ref_i32 : i32
-
-llvm.func @foo_free(!llvm.ptr)
-
-omp.private {type = firstprivate} @_QFwsloop_privateEc_firstprivate_ref_c8 : !llvm.array<1 x i8> copy {
-^bb0(%arg0: !llvm.ptr, %arg1: !llvm.ptr):
-  %0 = llvm.load %arg0 : !llvm.ptr -> !llvm.array<1 x i8>
-  llvm.store %0, %arg1 : !llvm.array<1 x i8>, !llvm.ptr
-  omp.yield(%arg1 : !llvm.ptr)
-} dealloc {
-^bb0(%arg0: !llvm.ptr):
-  llvm.call @foo_free(%arg0) : (!llvm.ptr) -> ()
-  omp.yield
-}
-
-// CHECK-LABEL wsloop_private_
-llvm.func @wsloop_private_(%arg0: !llvm.ptr {fir.bindc_name = "y"}) attributes {fir.internal_name = "_QPwsloop_private", frame_pointer = #llvm.framePointerKind<all>, target_cpu = "x86-64"} {
-  %0 = llvm.mlir.constant(1 : i64) : i64
-  %1 = llvm.alloca %0 x f32 {bindc_name = "x"} : (i64) -> !llvm.ptr
-  %3 = llvm.alloca %0 x i32 {bindc_name = "i"} : (i64) -> !llvm.ptr
-  %5 = llvm.alloca %0 x !llvm.array<1 x i8> {bindc_name = "c"} : (i64) -> !llvm.ptr
-  %6 = llvm.mlir.constant(1 : i32) : i32
-  %7 = llvm.mlir.constant(10 : i32) : i32
-  %8 = llvm.mlir.constant(0 : i32) : i32
-  omp.parallel {
-    omp.single {
-      omp.wsloop private(@_QFwsloop_privateEc_firstprivate_ref_c8 %5 -> %arg1, @_QFwsloop_privateEi_private_ref_i32 %3 -> %arg2 : !llvm.ptr, !llvm.ptr) private_barrier {
-  // CHECK: omp.private.copy:
-  // CHECK-NOT: __kmpc_barrier
-  // CHECK: br label
-        omp.loop_nest (%arg4) : i32 = (%8) to (%7) inclusive step (%6) {
-          omp.yield
-        }
-      }
-      omp.terminator
-    }
-    omp.terminator
-  }
-  llvm.return
-}
-
-
-// Check for a case where  the barrier should be applied. Regression check for
-// infinite loop.
-omp.private {type = private} @_QFsubEi_private_i32 : i32
-omp.private {type = firstprivate} @_QFsubEp_firstprivate_i32 : i32 copy {
-^bb0(%arg0: !llvm.ptr, %arg1: !llvm.ptr):
-  %0 = llvm.load %arg0 : !llvm.ptr -> i32
-  llvm.store %0, %arg1 : i32, !llvm.ptr
-  omp.yield(%arg1 : !llvm.ptr)
-}
-
-// CHECK-LABEL: _QPsub
-llvm.func @_QPsub() {
-  %0 = llvm.mlir.constant(100 : i32) : i32
-  %1 = llvm.mlir.constant(1 : i32) : i32
-  %2 = llvm.mlir.constant(1 : i64) : i64
-  %3 = llvm.alloca %2 x i32 {bindc_name = "p"} : (i64) -> !llvm.ptr
-  %4 = llvm.alloca %2 x i32 {bindc_name = "i"} : (i64) -> !llvm.ptr
-  llvm.store %0, %3 : i32, !llvm.ptr
-  omp.wsloop private(@_QFsubEp_firstprivate_i32 %3 -> %arg0, @_QFsubEi_private_i32 %4 -> %arg1 : !llvm.ptr, !llvm.ptr) private_barrier {
-  // CHECK: omp.private.copy:
-  // CHECK: __kmpc_barrier
-  // CHECK: br label
-    omp.loop_nest (%arg2) : i32 = (%1) to (%1) inclusive step (%1) {
-      llvm.store %arg2, %arg1 : i32, !llvm.ptr
-      %5 = llvm.add %arg2, %1 : i32
-      %6 = llvm.icmp "sgt" %5, %1 : i32
-      llvm.cond_br %6, ^bb1, ^bb2
-    ^bb1:  // pred: ^bb0
-      llvm.store %5, %arg1 : i32, !llvm.ptr
-      %7 = llvm.load %arg0 : !llvm.ptr -> i32
-      llvm.store %7, %3 : i32, !llvm.ptr
-      llvm.br ^bb2
-    ^bb2:  // 2 preds: ^bb0, ^bb1
-      omp.yield
-    }
-  }
-  llvm.return
-}
diff --git a/mlir/test/Target/LLVMIR/openmp-private-barrier-participation.mlir b/mlir/test/Target/LLVMIR/openmp-private-barrier.mlir
similarity index 64%
rename from mlir/test/Target/LLVMIR/openmp-private-barrier-participation.mlir
rename to mlir/test/Target/LLVMIR/openmp-private-barrier.mlir
index f107eae33ad53..d51443c856d84 100644
--- a/mlir/test/Target/LLVMIR/openmp-private-barrier-participation.mlir
+++ b/mlir/test/Target/LLVMIR/openmp-private-barrier.mlir
@@ -1,5 +1,92 @@
 // RUN: mlir-translate -mlir-to-llvmir %s | FileCheck %s
 
+// Tests that no privatization barrier is added for operations inside of SINGLE.
+// The specific combination here (wsloop inside of single) may not be valid
+// OpenMP. This combination was chosen so that this patch did not have to wait
+// for taskloop support. If it ever becomes a problem having a wsloop inside
+// of single, this can be updated to use taskloop.
+
+omp.private {type = private} @_QFwsloop_privateEi_private_ref_i32 : i32
+
+llvm.func @foo_free(!llvm.ptr)
+
+omp.private {type = firstprivate} @_QFwsloop_privateEc_firstprivate_ref_c8 : !llvm.array<1 x i8> copy {
+^bb0(%arg0: !llvm.ptr, %arg1: !llvm.ptr):
+  %0 = llvm.load %arg0 : !llvm.ptr -> !llvm.array<1 x i8>
+  llvm.store %0, %arg1 : !llvm.array<1 x i8>, !llvm.ptr
+  omp.yield(%arg1 : !llvm.ptr)
+} dealloc {
+^bb0(%arg0: !llvm.ptr):
+  llvm.call @foo_free(%arg0) : (!llvm.ptr) -> ()
+  omp.yield
+}
+
+// CHECK-LABEL wsloop_private_
+llvm.func @wsloop_private_(%arg0: !llvm.ptr {fir.bindc_name = "y"}) attributes {fir.internal_name = "_QPwsloop_private", frame_pointer = #llvm.framePointerKind<all>, target_cpu = "x86-64"} {
+  %0 = llvm.mlir.constant(1 : i64) : i64
+  %1 = llvm.alloca %0 x f32 {bindc_name = "x"} : (i64) -> !llvm.ptr
+  %3 = llvm.alloca %0 x i32 {bindc_name = "i"} : (i64) -> !llvm.ptr
+  %5 = llvm.alloca %0 x !llvm.array<1 x i8> {bindc_name = "c"} : (i64) -> !llvm.ptr
+  %6 = llvm.mlir.constant(1 : i32) : i32
+  %7 = llvm.mlir.constant(10 : i32) : i32
+  %8 = llvm.mlir.constant(0 : i32) : i32
+  omp.parallel {
+    omp.single {
+      omp.wsloop private(@_QFwsloop_privateEc_firstprivate_ref_c8 %5 -> %arg1, @_QFwsloop_privateEi_private_ref_i32 %3 -> %arg2 : !llvm.ptr, !llvm.ptr) private_barrier {
+  // CHECK: omp.private.copy:
+  // CHECK-NOT: __kmpc_barrier
+  // CHECK: br label
+        omp.loop_nest (%arg4) : i32 = (%8) to (%7) inclusive step (%6) {
+          omp.yield
+        }
+      }
+      omp.terminator
+    }
+    omp.terminator
+  }
+  llvm.return
+}
+
+
+// Check for a case where  the barrier should be applied. Regression check for
+// infinite loop.
+omp.private {type = private} @_QFsubEi_private_i32 : i32
+omp.private {type = firstprivate} @_QFsubEp_firstprivate_i32 : i32 copy {
+^bb0(%arg0: !llvm.ptr, %arg1: !llvm.ptr):
+  %0 = llvm.load %arg0 : !llvm.ptr -> i32
+  llvm.store %0, %arg1 : i32, !llvm.ptr
+  omp.yield(%arg1 : !llvm.ptr)
+}
+
+// CHECK-LABEL: _QPsub
+llvm.func @_QPsub() {
+  %0 = llvm.mlir.constant(100 : i32) : i32
+  %1 = llvm.mlir.constant(1 : i32) : i32
+  %2 = llvm.mlir.constant(1 : i64) : i64
+  %3 = llvm.alloca %2 x i32 {bindc_name = "p"} : (i64) -> !llvm.ptr
+  %4 = llvm.alloca %2 x i32 {bindc_name = "i"} : (i64) -> !llvm.ptr
+  llvm.store %0, %3 : i32, !llvm.ptr
+  omp.wsloop private(@_QFsubEp_firstprivate_i32 %3 -> %arg0, @_QFsubEi_private_i32 %4 -> %arg1 : !llvm.ptr, !llvm.ptr) private_barrier {
+  // CHECK: omp.private.copy:
+  // CHECK: __kmpc_barrier
+  // CHECK: br label
+    omp.loop_nest (%arg2) : i32 = (%1) to (%1) inclusive step (%1) {
+      llvm.store %arg2, %arg1 : i32, !llvm.ptr
+      %5 = llvm.add %arg2, %1 : i32
+      %6 = llvm.icmp "sgt" %5, %1 : i32
+      llvm.cond_br %6, ^bb1, ^bb2
+    ^bb1:  // pred: ^bb0
+      llvm.store %5, %arg1 : i32, !llvm.ptr
+      %7 = llvm.load %arg0 : !llvm.ptr -> i32
+      llvm.store %7, %3 : i32, !llvm.ptr
+      llvm.br ^bb2
+    ^bb2:  // 2 preds: ^bb0, ^bb1
+      omp.yield
+    }
+  }
+  llvm.return
+}
+
 // A privatization barrier needs every thread in its team to reach it. These
 // constructs select or serialize threads, even when more than one thread can
 // execute the region over time.



More information about the Mlir-commits mailing list