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

via flang-commits flang-commits at lists.llvm.org
Wed Jul 1 03:47:30 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/2] 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/2] 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



More information about the flang-commits mailing list