[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