[flang-commits] [flang] [mlir] Fixing miscompilation with OMP synchronization at higher optimizations (PR #202258)

via flang-commits flang-commits at lists.llvm.org
Thu Jul 30 07:17:51 PDT 2026


https://github.com/Ritanya-B-Bharadwaj updated https://github.com/llvm/llvm-project/pull/202258

>From a4605305fbea9b7a54a2d72562e9053dfa79380b Mon Sep 17 00:00:00 2001
From: Ritanya B Bharadwaj <ritanya.b.bharadwaj at gmail.com>
Date: Mon, 8 Jun 2026 00:01:03 -0500
Subject: [PATCH 1/4] Fixing miscompilation with OMP synchronization at higher
 optimizations

---
 .../lib/Optimizer/Transforms/FunctionAttr.cpp | 23 +++++++-
 .../Transforms/function-attrs-noalias-omp.fir | 55 +++++++++++++++++++
 2 files changed, 75 insertions(+), 3 deletions(-)
 create mode 100644 flang/test/Transforms/function-attrs-noalias-omp.fir

diff --git a/flang/lib/Optimizer/Transforms/FunctionAttr.cpp b/flang/lib/Optimizer/Transforms/FunctionAttr.cpp
index b49803e989265..94f5cf898d529 100644
--- a/flang/lib/Optimizer/Transforms/FunctionAttr.cpp
+++ b/flang/lib/Optimizer/Transforms/FunctionAttr.cpp
@@ -15,6 +15,7 @@
 #include "flang/Optimizer/Transforms/Passes.h"
 #include "mlir/Dialect/LLVMIR/LLVMAttrs.h"
 #include "mlir/Dialect/LLVMIR/LLVMDialect.h"
+#include "mlir/Dialect/OpenMP/OpenMPDialect.h"
 #include "llvm/ADT/Twine.h"
 #include <string>
 
@@ -42,6 +43,21 @@ class FunctionAttrPass : public fir::impl::FunctionAttrBase<FunctionAttrPass> {
   void runOnOperation() override;
 };
 
+/// Return true if the function body contains any OpenMP synchronization or
+/// work-sharing constructs.
+static bool containsOpenMPSyncOrWorkshare(mlir::func::FuncOp func) {
+  bool found = false;
+  func.walk([&](mlir::Operation *op) {
+    if (mlir::isa<mlir::omp::SingleOp, mlir::omp::MasterOp,
+                  mlir::omp::BarrierOp, mlir::omp::CriticalOp,
+                  mlir::omp::OrderedOp, mlir::omp::ParallelOp>(op)) {
+      found = true;
+      return mlir::WalkResult::interrupt();
+    }
+    return mlir::WalkResult::advance();
+  });
+  return found;
+}
 } // namespace
 
 void FunctionAttrPass::runOnOperation() {
@@ -59,7 +75,7 @@ void FunctionAttrPass::runOnOperation() {
     llvm::StringRef nocapture = mlir::LLVM::LLVMDialect::getNoCaptureAttrName();
     llvm::StringRef noalias = mlir::LLVM::LLVMDialect::getNoAliasAttrName();
     mlir::UnitAttr unitAttr = mlir::UnitAttr::get(func.getContext());
-
+    bool hasOmpSync = containsOpenMPSyncOrWorkshare(func);
     for (auto [index, argType] : llvm::enumerate(func.getArgumentTypes())) {
       bool isNoCapture = false;
       bool isNoAlias = false;
@@ -68,12 +84,13 @@ void FunctionAttrPass::runOnOperation() {
           !func.getArgAttr(index, fir::getAsynchronousAttrName()) &&
           !func.getArgAttr(index, fir::getVolatileAttrName())) {
         isNoCapture = true;
-        isNoAlias = !fir::isPointerType(argType);
+        isNoAlias = !fir::isPointerType(argType) && !hasOmpSync;
       } else if (mlir::isa<fir::BaseBoxType>(argType)) {
         // !fir.box arguments will be passed as descriptor pointers
         // at LLVM IR dialect level - they cannot be captured,
         // and cannot alias with anything within the function.
-        isNoCapture = isNoAlias = true;
+        isNoCapture = true;
+        isNoAlias = !hasOmpSync;
       }
       if (isNoCapture && setNoCapture)
         func.setArgAttr(index, nocapture, unitAttr);
diff --git a/flang/test/Transforms/function-attrs-noalias-omp.fir b/flang/test/Transforms/function-attrs-noalias-omp.fir
new file mode 100644
index 0000000000000..7cb2fcdeb9f08
--- /dev/null
+++ b/flang/test/Transforms/function-attrs-noalias-omp.fir
@@ -0,0 +1,55 @@
+// RUN: fir-opt --function-attr="set-noalias=true" %s | FileCheck %s
+
+// Test that noalias is not set on arguments of functions containing
+// OpenMP synchronization or work-sharing constructs, because shared
+// variables may cause multiple threads to pass the same address.
+
+// CHECK-LABEL:   func.func @test_omp_single(
+// CHECK-SAME:      %[[ARG0:.*]]: !fir.ref<f64> {fir.bindc_name = "tmp"}) {
+func.func @test_omp_single(%arg0: !fir.ref<f64> {fir.bindc_name = "tmp"}) {
+  omp.single {
+    omp.terminator
+  }
+  return
+}
+
+// CHECK-LABEL:   func.func @test_omp_critical(
+// CHECK-SAME:      %[[ARG0:.*]]: !fir.ref<f64> {fir.bindc_name = "tmp"}) {
+func.func @test_omp_critical(%arg0: !fir.ref<f64> {fir.bindc_name = "tmp"}) {
+  omp.critical {
+    omp.terminator
+  }
+  return
+}
+
+// CHECK-LABEL:   func.func @test_omp_barrier(
+// CHECK-SAME:      %[[ARG0:.*]]: !fir.ref<f64> {fir.bindc_name = "tmp"}) {
+func.func @test_omp_barrier(%arg0: !fir.ref<f64> {fir.bindc_name = "tmp"}) {
+  omp.barrier
+  return
+}
+
+// CHECK-LABEL:   func.func @test_omp_master(
+// CHECK-SAME:      %[[ARG0:.*]]: !fir.ref<f64> {fir.bindc_name = "tmp"}) {
+func.func @test_omp_master(%arg0: !fir.ref<f64> {fir.bindc_name = "tmp"}) {
+  omp.master {
+    omp.terminator
+  }
+  return
+}
+
+// CHECK-LABEL:   func.func @test_omp_parallel(
+// CHECK-SAME:      %[[ARG0:.*]]: !fir.ref<f64> {fir.bindc_name = "tmp"}) {
+func.func @test_omp_parallel(%arg0: !fir.ref<f64> {fir.bindc_name = "tmp"}) {
+  omp.parallel {
+    omp.terminator
+  }
+  return
+}
+
+// A function without OMP constructs should still get noalias.
+// CHECK-LABEL:   func.func @test_no_omp(
+// CHECK-SAME:      %[[ARG0:.*]]: !fir.ref<f64> {fir.bindc_name = "tmp", llvm.noalias}) {
+func.func @test_no_omp(%arg0: !fir.ref<f64> {fir.bindc_name = "tmp"}) {
+  return
+}

>From af2f1010a125c33425bba32bed612d3930054385 Mon Sep 17 00:00:00 2001
From: Ritanya B Bharadwaj <ritanya.b.bharadwaj at gmail.com>
Date: Wed, 1 Jul 2026 05:45:56 -0500
Subject: [PATCH 2/4] Removing masterop

---
 flang/lib/Optimizer/Transforms/FunctionAttr.cpp      | 8 +++++---
 flang/test/Transforms/function-attrs-noalias-omp.fir | 2 +-
 2 files changed, 6 insertions(+), 4 deletions(-)

diff --git a/flang/lib/Optimizer/Transforms/FunctionAttr.cpp b/flang/lib/Optimizer/Transforms/FunctionAttr.cpp
index 94f5cf898d529..2e6bb364ee0d2 100644
--- a/flang/lib/Optimizer/Transforms/FunctionAttr.cpp
+++ b/flang/lib/Optimizer/Transforms/FunctionAttr.cpp
@@ -48,9 +48,11 @@ class FunctionAttrPass : public fir::impl::FunctionAttrBase<FunctionAttrPass> {
 static bool containsOpenMPSyncOrWorkshare(mlir::func::FuncOp func) {
   bool found = false;
   func.walk([&](mlir::Operation *op) {
-    if (mlir::isa<mlir::omp::SingleOp, mlir::omp::MasterOp,
-                  mlir::omp::BarrierOp, mlir::omp::CriticalOp,
-                  mlir::omp::OrderedOp, mlir::omp::ParallelOp>(op)) {
+    // Note: omp.master (and omp.masked) are intentionally excluded here. They
+    // are neither work-sharing nor synchronizing constructs.
+    if (mlir::isa<mlir::omp::SingleOp, mlir::omp::BarrierOp,
+                  mlir::omp::CriticalOp, mlir::omp::OrderedOp,
+                  mlir::omp::ParallelOp>(op)) {
       found = true;
       return mlir::WalkResult::interrupt();
     }
diff --git a/flang/test/Transforms/function-attrs-noalias-omp.fir b/flang/test/Transforms/function-attrs-noalias-omp.fir
index 7cb2fcdeb9f08..5f68ce47c6a35 100644
--- a/flang/test/Transforms/function-attrs-noalias-omp.fir
+++ b/flang/test/Transforms/function-attrs-noalias-omp.fir
@@ -30,7 +30,7 @@ func.func @test_omp_barrier(%arg0: !fir.ref<f64> {fir.bindc_name = "tmp"}) {
 }
 
 // CHECK-LABEL:   func.func @test_omp_master(
-// CHECK-SAME:      %[[ARG0:.*]]: !fir.ref<f64> {fir.bindc_name = "tmp"}) {
+// CHECK-SAME:      %[[ARG0:.*]]: !fir.ref<f64> {fir.bindc_name = "tmp", llvm.noalias}) {
 func.func @test_omp_master(%arg0: !fir.ref<f64> {fir.bindc_name = "tmp"}) {
   omp.master {
     omp.terminator

>From c47ca21368ae61d427ec26c112916f5796698e1b Mon Sep 17 00:00:00 2001
From: Ritanya-B-Bharadwaj <ritanya.b.bharadwaj at gmail.com>
Date: Mon, 27 Jul 2026 21:35:00 +0530
Subject: [PATCH 3/4] [MLIR][OpenMP] Preserve flush(list) ordering under
 noalias

---
 .../OpenMP/OpenMPToLLVMIRTranslation.cpp      | 31 ++++++++++++++-----
 mlir/test/Target/LLVMIR/openmp-llvm.mlir      |  2 ++
 2 files changed, 25 insertions(+), 8 deletions(-)

diff --git a/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp b/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp
index 8614aed1ab80c..ee0552f716d18 100644
--- a/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp
+++ b/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp
@@ -31,6 +31,7 @@
 #include "llvm/IR/DebugInfoMetadata.h"
 #include "llvm/IR/DerivedTypes.h"
 #include "llvm/IR/IRBuilder.h"
+#include "llvm/IR/InlineAsm.h"
 #include "llvm/IR/MDBuilder.h"
 #include "llvm/IR/ReplaceConstant.h"
 #include "llvm/Support/FileSystem.h"
@@ -7922,14 +7923,28 @@ LogicalResult OpenMPDialectLLVMIRTranslationInterface::convertOperation(
             if (failed(checkImplementationStatus(*op)))
               return failure();
 
-            // No support in Openmp runtime function (__kmpc_flush) to accept
-            // the argument list.
-            // OpenMP standard states the following:
-            //  "An implementation may implement a flush with a list by ignoring
-            //   the list, and treating it the same as a flush without a list."
-            //
-            // The argument list is discarded so that, flush with a list is
-            // treated same as a flush without a list.
+            // __kmpc_flush ignores the list, so emit a compiler memory barrier
+            // over the listed pointers to keep their accesses ordered across the
+            // flush even when they carry the Fortran-implied `noalias`.
+            llvm::SmallVector<llvm::Value *> flushPtrs;
+            llvm::SmallVector<llvm::Type *> flushPtrTypes;
+            for (mlir::Value flushVar : op.getVarList()) {
+              llvm::Value *ptr = moduleTranslation.lookupValue(flushVar);
+              flushPtrs.push_back(ptr);
+              flushPtrTypes.push_back(ptr->getType());
+            }
+            if (!flushPtrs.empty()) {
+              std::string constraints;
+              for (size_t i = 0, e = flushPtrs.size(); i != e; ++i)
+                constraints += "r,";
+              constraints += "~{memory}";
+              llvm::FunctionType *asmFTy = llvm::FunctionType::get(
+                  builder.getVoidTy(), flushPtrTypes, /*isVarArg=*/false);
+              llvm::InlineAsm *barrier = llvm::InlineAsm::get(
+                  asmFTy, /*AsmString=*/"", constraints,
+                  /*hasSideEffects=*/true);
+              builder.CreateCall(barrier, flushPtrs);
+            }
             ompBuilder->createFlush(builder.saveIP());
             return success();
           })
diff --git a/mlir/test/Target/LLVMIR/openmp-llvm.mlir b/mlir/test/Target/LLVMIR/openmp-llvm.mlir
index 66909072a420c..020118474328a 100644
--- a/mlir/test/Target/LLVMIR/openmp-llvm.mlir
+++ b/mlir/test/Target/LLVMIR/openmp-llvm.mlir
@@ -23,9 +23,11 @@ llvm.func @test_flush_construct(%arg0: !llvm.ptr) {
   // CHECK: call void @__kmpc_flush(ptr @{{[0-9]+}}
   omp.flush
 
+  // CHECK: call void asm sideeffect "", "r,~{memory}"(ptr %{{[0-9]+}})
   // CHECK: call void @__kmpc_flush(ptr @{{[0-9]+}}
   omp.flush (%arg0 : !llvm.ptr)
 
+  // CHECK: call void asm sideeffect "", "r,r,~{memory}"(ptr %{{[0-9]+}}, ptr %{{[0-9]+}})
   // CHECK: call void @__kmpc_flush(ptr @{{[0-9]+}}
   omp.flush (%arg0, %arg0 : !llvm.ptr, !llvm.ptr)
 

>From 6741056cc1eb893bad725b20e634a79bba88d0d3 Mon Sep 17 00:00:00 2001
From: Ritanya-B-Bharadwaj <ritanya.b.bharadwaj at gmail.com>
Date: Thu, 30 Jul 2026 19:46:51 +0530
Subject: [PATCH 4/4] [flang][OpenMP] Keep noalias; enforce flush ordering via
 barriers

---
 .../lib/Optimizer/Transforms/FunctionAttr.cpp | 23 +-----
 .../Transforms/function-attrs-noalias-omp.fir | 15 ++--
 .../OpenMP/OpenMPToLLVMIRTranslation.cpp      | 71 ++++++++++++++-----
 mlir/test/Target/LLVMIR/openmp-llvm.mlir      | 28 ++++++++
 4 files changed, 91 insertions(+), 46 deletions(-)

diff --git a/flang/lib/Optimizer/Transforms/FunctionAttr.cpp b/flang/lib/Optimizer/Transforms/FunctionAttr.cpp
index 2e6bb364ee0d2..35952adf2ca76 100644
--- a/flang/lib/Optimizer/Transforms/FunctionAttr.cpp
+++ b/flang/lib/Optimizer/Transforms/FunctionAttr.cpp
@@ -15,7 +15,6 @@
 #include "flang/Optimizer/Transforms/Passes.h"
 #include "mlir/Dialect/LLVMIR/LLVMAttrs.h"
 #include "mlir/Dialect/LLVMIR/LLVMDialect.h"
-#include "mlir/Dialect/OpenMP/OpenMPDialect.h"
 #include "llvm/ADT/Twine.h"
 #include <string>
 
@@ -43,23 +42,6 @@ class FunctionAttrPass : public fir::impl::FunctionAttrBase<FunctionAttrPass> {
   void runOnOperation() override;
 };
 
-/// Return true if the function body contains any OpenMP synchronization or
-/// work-sharing constructs.
-static bool containsOpenMPSyncOrWorkshare(mlir::func::FuncOp func) {
-  bool found = false;
-  func.walk([&](mlir::Operation *op) {
-    // Note: omp.master (and omp.masked) are intentionally excluded here. They
-    // are neither work-sharing nor synchronizing constructs.
-    if (mlir::isa<mlir::omp::SingleOp, mlir::omp::BarrierOp,
-                  mlir::omp::CriticalOp, mlir::omp::OrderedOp,
-                  mlir::omp::ParallelOp>(op)) {
-      found = true;
-      return mlir::WalkResult::interrupt();
-    }
-    return mlir::WalkResult::advance();
-  });
-  return found;
-}
 } // namespace
 
 void FunctionAttrPass::runOnOperation() {
@@ -77,7 +59,6 @@ void FunctionAttrPass::runOnOperation() {
     llvm::StringRef nocapture = mlir::LLVM::LLVMDialect::getNoCaptureAttrName();
     llvm::StringRef noalias = mlir::LLVM::LLVMDialect::getNoAliasAttrName();
     mlir::UnitAttr unitAttr = mlir::UnitAttr::get(func.getContext());
-    bool hasOmpSync = containsOpenMPSyncOrWorkshare(func);
     for (auto [index, argType] : llvm::enumerate(func.getArgumentTypes())) {
       bool isNoCapture = false;
       bool isNoAlias = false;
@@ -86,13 +67,13 @@ void FunctionAttrPass::runOnOperation() {
           !func.getArgAttr(index, fir::getAsynchronousAttrName()) &&
           !func.getArgAttr(index, fir::getVolatileAttrName())) {
         isNoCapture = true;
-        isNoAlias = !fir::isPointerType(argType) && !hasOmpSync;
+        isNoAlias = !fir::isPointerType(argType);
       } else if (mlir::isa<fir::BaseBoxType>(argType)) {
         // !fir.box arguments will be passed as descriptor pointers
         // at LLVM IR dialect level - they cannot be captured,
         // and cannot alias with anything within the function.
         isNoCapture = true;
-        isNoAlias = !hasOmpSync;
+        isNoAlias = true;
       }
       if (isNoCapture && setNoCapture)
         func.setArgAttr(index, nocapture, unitAttr);
diff --git a/flang/test/Transforms/function-attrs-noalias-omp.fir b/flang/test/Transforms/function-attrs-noalias-omp.fir
index 5f68ce47c6a35..35edb6e753c0d 100644
--- a/flang/test/Transforms/function-attrs-noalias-omp.fir
+++ b/flang/test/Transforms/function-attrs-noalias-omp.fir
@@ -1,11 +1,12 @@
 // RUN: fir-opt --function-attr="set-noalias=true" %s | FileCheck %s
 
-// Test that noalias is not set on arguments of functions containing
-// OpenMP synchronization or work-sharing constructs, because shared
-// variables may cause multiple threads to pass the same address.
+// Test that noalias is still set on arguments of functions containing OpenMP
+// synchronization or work-sharing constructs. The memory ordering these
+// constructs require is enforced when they are lowered, so noalias can be
+// preserved here.
 
 // CHECK-LABEL:   func.func @test_omp_single(
-// CHECK-SAME:      %[[ARG0:.*]]: !fir.ref<f64> {fir.bindc_name = "tmp"}) {
+// CHECK-SAME:      %[[ARG0:.*]]: !fir.ref<f64> {fir.bindc_name = "tmp", llvm.noalias}) {
 func.func @test_omp_single(%arg0: !fir.ref<f64> {fir.bindc_name = "tmp"}) {
   omp.single {
     omp.terminator
@@ -14,7 +15,7 @@ func.func @test_omp_single(%arg0: !fir.ref<f64> {fir.bindc_name = "tmp"}) {
 }
 
 // CHECK-LABEL:   func.func @test_omp_critical(
-// CHECK-SAME:      %[[ARG0:.*]]: !fir.ref<f64> {fir.bindc_name = "tmp"}) {
+// CHECK-SAME:      %[[ARG0:.*]]: !fir.ref<f64> {fir.bindc_name = "tmp", llvm.noalias}) {
 func.func @test_omp_critical(%arg0: !fir.ref<f64> {fir.bindc_name = "tmp"}) {
   omp.critical {
     omp.terminator
@@ -23,7 +24,7 @@ func.func @test_omp_critical(%arg0: !fir.ref<f64> {fir.bindc_name = "tmp"}) {
 }
 
 // CHECK-LABEL:   func.func @test_omp_barrier(
-// CHECK-SAME:      %[[ARG0:.*]]: !fir.ref<f64> {fir.bindc_name = "tmp"}) {
+// CHECK-SAME:      %[[ARG0:.*]]: !fir.ref<f64> {fir.bindc_name = "tmp", llvm.noalias}) {
 func.func @test_omp_barrier(%arg0: !fir.ref<f64> {fir.bindc_name = "tmp"}) {
   omp.barrier
   return
@@ -39,7 +40,7 @@ func.func @test_omp_master(%arg0: !fir.ref<f64> {fir.bindc_name = "tmp"}) {
 }
 
 // CHECK-LABEL:   func.func @test_omp_parallel(
-// CHECK-SAME:      %[[ARG0:.*]]: !fir.ref<f64> {fir.bindc_name = "tmp"}) {
+// CHECK-SAME:      %[[ARG0:.*]]: !fir.ref<f64> {fir.bindc_name = "tmp", llvm.noalias}) {
 func.func @test_omp_parallel(%arg0: !fir.ref<f64> {fir.bindc_name = "tmp"}) {
   omp.parallel {
     omp.terminator
diff --git a/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp b/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp
index ee0552f716d18..85b61cdcbaf1c 100644
--- a/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp
+++ b/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp
@@ -755,6 +755,51 @@ convertOmpMaster(Operation &opInst, llvm::IRBuilderBase &builder,
   return success();
 }
 
+/// Emits an empty side-effecting inline-asm barrier with a "memory" clobber
+/// over \p ptrs, pinning their accesses at this point even under `noalias`.
+static void emitNoAliasFlushBarrier(llvm::IRBuilderBase &builder,
+                                    llvm::ArrayRef<llvm::Value *> ptrs) {
+  if (ptrs.empty())
+    return;
+  llvm::SmallVector<llvm::Type *> ptrTypes;
+  for (llvm::Value *ptr : ptrs)
+    ptrTypes.push_back(ptr->getType());
+  std::string constraints;
+  for (size_t i = 0, e = ptrs.size(); i != e; ++i)
+    constraints += "r,";
+  constraints += "~{memory}";
+  llvm::FunctionType *asmFTy =
+      llvm::FunctionType::get(builder.getVoidTy(), ptrTypes, /*isVarArg=*/false);
+  llvm::InlineAsm *barrier = llvm::InlineAsm::get(
+      asmFTy, /*AsmString=*/"", constraints, /*hasSideEffects=*/true);
+  builder.CreateCall(barrier, ptrs);
+}
+
+/// Collects the `noalias` pointer arguments of the function currently being
+/// built; these are the dummy arguments an implicit flush must keep ordered.
+static llvm::SmallVector<llvm::Value *>
+collectNoAliasPointerArgs(llvm::IRBuilderBase &builder) {
+  llvm::SmallVector<llvm::Value *> ptrs;
+  llvm::BasicBlock *insertBB = builder.GetInsertBlock();
+  if (!insertBB)
+    return ptrs;
+  if (llvm::Function *fn = insertBB->getParent())
+    for (llvm::Argument &arg : fn->args())
+      if (arg.getType()->isPointerTy() && arg.hasNoAliasAttr())
+        ptrs.push_back(&arg);
+  return ptrs;
+}
+
+/// Returns true if translating \p op emits a construct that implies a flush of
+/// all thread-visible variables. Explicit `omp.flush` with a list is handled
+/// separately, pinning only the listed variables.
+static bool impliesFlushAll(mlir::Operation *op) {
+  return mlir::isa<mlir::omp::BarrierOp, mlir::omp::CriticalOp,
+                   mlir::omp::SingleOp, mlir::omp::SectionsOp,
+                   mlir::omp::WsloopOp, mlir::omp::OrderedOp,
+                   mlir::omp::OrderedRegionOp>(op);
+}
+
 /// Converts an OpenMP 'critical' operation into LLVM IR using OpenMPIRBuilder.
 static LogicalResult
 convertOmpCritical(Operation &opInst, llvm::IRBuilderBase &builder,
@@ -7895,6 +7940,11 @@ LogicalResult OpenMPDialectLLVMIRTranslationInterface::convertOperation(
   if (isOutermostLoopWrapper)
     moduleTranslation.stackPush<OpenMPLoopInfoStackFrame>();
 
+  // A flush-implying construct must not let accesses to the function's noalias
+  // dummy arguments move across it; pin them here while keeping `noalias`.
+  if (impliesFlushAll(op))
+    emitNoAliasFlushBarrier(builder, collectNoAliasPointerArgs(builder));
+
   auto result =
       llvm::TypeSwitch<Operation *, LogicalResult>(op)
           .Case([&](omp::BarrierOp op) -> LogicalResult {
@@ -7927,24 +7977,9 @@ LogicalResult OpenMPDialectLLVMIRTranslationInterface::convertOperation(
             // over the listed pointers to keep their accesses ordered across the
             // flush even when they carry the Fortran-implied `noalias`.
             llvm::SmallVector<llvm::Value *> flushPtrs;
-            llvm::SmallVector<llvm::Type *> flushPtrTypes;
-            for (mlir::Value flushVar : op.getVarList()) {
-              llvm::Value *ptr = moduleTranslation.lookupValue(flushVar);
-              flushPtrs.push_back(ptr);
-              flushPtrTypes.push_back(ptr->getType());
-            }
-            if (!flushPtrs.empty()) {
-              std::string constraints;
-              for (size_t i = 0, e = flushPtrs.size(); i != e; ++i)
-                constraints += "r,";
-              constraints += "~{memory}";
-              llvm::FunctionType *asmFTy = llvm::FunctionType::get(
-                  builder.getVoidTy(), flushPtrTypes, /*isVarArg=*/false);
-              llvm::InlineAsm *barrier = llvm::InlineAsm::get(
-                  asmFTy, /*AsmString=*/"", constraints,
-                  /*hasSideEffects=*/true);
-              builder.CreateCall(barrier, flushPtrs);
-            }
+            for (mlir::Value flushVar : op.getVarList())
+              flushPtrs.push_back(moduleTranslation.lookupValue(flushVar));
+            emitNoAliasFlushBarrier(builder, flushPtrs);
             ompBuilder->createFlush(builder.saveIP());
             return success();
           })
diff --git a/mlir/test/Target/LLVMIR/openmp-llvm.mlir b/mlir/test/Target/LLVMIR/openmp-llvm.mlir
index 020118474328a..005388d554b7e 100644
--- a/mlir/test/Target/LLVMIR/openmp-llvm.mlir
+++ b/mlir/test/Target/LLVMIR/openmp-llvm.mlir
@@ -43,6 +43,34 @@ llvm.func @test_flush_construct(%arg0: !llvm.ptr) {
   llvm.return
 }
 
+// CHECK-LABEL: define void @test_barrier_noalias(ptr noalias %{{[0-9]+}})
+llvm.func @test_barrier_noalias(%arg0: !llvm.ptr {llvm.noalias}) {
+  // CHECK: call void asm sideeffect "", "r,~{memory}"(ptr %{{[0-9]+}})
+  // CHECK: call void @__kmpc_barrier
+  omp.barrier
+  llvm.return
+}
+
+// CHECK-LABEL: define void @test_critical_noalias(ptr noalias %{{[0-9]+}})
+llvm.func @test_critical_noalias(%arg0: !llvm.ptr {llvm.noalias}) {
+  // CHECK: call void asm sideeffect "", "r,~{memory}"(ptr %{{[0-9]+}})
+  // CHECK: call void @__kmpc_critical
+  omp.critical {
+    omp.terminator
+  }
+  llvm.return
+}
+
+// CHECK-LABEL: define void @test_single_noalias(ptr noalias %{{[0-9]+}})
+llvm.func @test_single_noalias(%arg0: !llvm.ptr {llvm.noalias}) {
+  // CHECK: call void asm sideeffect "", "r,~{memory}"(ptr %{{[0-9]+}})
+  // CHECK: call i32 @__kmpc_single
+  omp.single {
+    omp.terminator
+  }
+  llvm.return
+}
+
 // CHECK-LABEL: define void @test_omp_parallel_1()
 llvm.func @test_omp_parallel_1() -> () {
   // CHECK: call void{{.*}}@__kmpc_fork_call{{.*}}@[[OMP_OUTLINED_FN_1:.*]])



More information about the flang-commits mailing list