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

via flang-commits flang-commits at lists.llvm.org
Sun Jun 7 22:37:33 PDT 2026


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

None

>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] 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
+}



More information about the flang-commits mailing list