[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