[llvm] 41ef6d0 - [IR] Add Instruction::maySynchronize() method (NFC) (#196052)
via llvm-commits
llvm-commits at lists.llvm.org
Wed May 6 09:26:26 PDT 2026
Author: Nikita Popov
Date: 2026-05-06T18:26:21+02:00
New Revision: 41ef6d0982f88c09336d6a836dc1e7b8354563ce
URL: https://github.com/llvm/llvm-project/commit/41ef6d0982f88c09336d6a836dc1e7b8354563ce
DIFF: https://github.com/llvm/llvm-project/commit/41ef6d0982f88c09336d6a836dc1e7b8354563ce.diff
LOG: [IR] Add Instruction::maySynchronize() method (NFC) (#196052)
Extract the logic from FunctionAttrs into a generic API on Instruction,
which will check the nosync flag on calls and ordering for atomic
instructions.
For now, I've retained the previous implementation which considers
monotonic ordering to be synchronizing, which is unnecessarily
conservative and doesn't match LangRef (or the Attributor
implementation).
This is to make it easier to reuse this logic in more places.
Added:
Modified:
llvm/include/llvm/IR/Instruction.h
llvm/lib/IR/Instruction.cpp
llvm/lib/Transforms/IPO/FunctionAttrs.cpp
Removed:
################################################################################
diff --git a/llvm/include/llvm/IR/Instruction.h b/llvm/include/llvm/IR/Instruction.h
index 0e6c122a4e2ef..e08021d330d09 100644
--- a/llvm/include/llvm/IR/Instruction.h
+++ b/llvm/include/llvm/IR/Instruction.h
@@ -859,6 +859,10 @@ class Instruction : public User,
/// Return true if this instruction has a volatile memory access.
LLVM_ABI bool isVolatile() const LLVM_READONLY;
+ /// Return true if this instruction may synchronize, in the sense that it
+ /// may introduce a synchronizes-with edge.
+ LLVM_ABI bool maySynchronize() const LLVM_READONLY;
+
/// Return the type this instruction accesses in memory, if any.
LLVM_ABI Type *getAccessType() const LLVM_READONLY;
diff --git a/llvm/lib/IR/Instruction.cpp b/llvm/lib/IR/Instruction.cpp
index 34861c5817d61..ac209ffa72aae 100644
--- a/llvm/lib/IR/Instruction.cpp
+++ b/llvm/lib/IR/Instruction.cpp
@@ -1170,6 +1170,33 @@ bool Instruction::isVolatile() const {
}
}
+bool Instruction::maySynchronize() const {
+ // FIXME: This currently treats atomics with monotonic ordering as
+ // synchronizing. This is unnecessarily conservative and does not match
+ // our LangRef definition of the property.
+ switch (getOpcode()) {
+ default:
+ assert(!isAtomic() && "Unhandled atomic instruction");
+ return false;
+ case Instruction::Fence: {
+ // All legal orderings for fence are stronger than monotonic.
+ auto *FI = cast<FenceInst>(this);
+ return FI->getSyncScopeID() != SyncScope::SingleThread;
+ }
+ case Instruction::AtomicRMW:
+ case Instruction::AtomicCmpXchg:
+ return true;
+ case Instruction::Store:
+ return isStrongerThanUnordered(cast<StoreInst>(this)->getOrdering());
+ case Instruction::Load:
+ return isStrongerThanUnordered(cast<LoadInst>(this)->getOrdering());
+ case Instruction::Call:
+ case Instruction::Invoke:
+ case Instruction::CallBr:
+ return !cast<CallBase>(this)->hasFnAttr(Attribute::NoSync);
+ }
+}
+
Type *Instruction::getAccessType() const {
switch (getOpcode()) {
case Instruction::Store:
diff --git a/llvm/lib/Transforms/IPO/FunctionAttrs.cpp b/llvm/lib/Transforms/IPO/FunctionAttrs.cpp
index 3dc0cc6bdaf46..c6113fbb96b3f 100644
--- a/llvm/lib/Transforms/IPO/FunctionAttrs.cpp
+++ b/llvm/lib/Transforms/IPO/FunctionAttrs.cpp
@@ -1933,46 +1933,16 @@ static bool InstrBreaksNoFree(Instruction &I, const SCCNodeSet &SCCNodes) {
return true;
}
-// Return true if this is an atomic which has an ordering stronger than
-// unordered. Note that this is
diff erent than the predicate we use in
-// Attributor. Here we chose to be conservative and consider monotonic
-// operations potentially synchronizing. We generally don't do much with
-// monotonic operations, so this is simply risk reduction.
-static bool isOrderedAtomic(Instruction *I) {
- if (!I->isAtomic())
- return false;
-
- if (auto *FI = dyn_cast<FenceInst>(I))
- // All legal orderings for fence are stronger than monotonic.
- return FI->getSyncScopeID() != SyncScope::SingleThread;
- else if (isa<AtomicCmpXchgInst>(I) || isa<AtomicRMWInst>(I))
- return true;
- else if (auto *SI = dyn_cast<StoreInst>(I))
- return !SI->isUnordered();
- else if (auto *LI = dyn_cast<LoadInst>(I))
- return !LI->isUnordered();
- else {
- llvm_unreachable("unknown atomic instruction?");
- }
-}
-
static bool InstrBreaksNoSync(Instruction &I, const SCCNodeSet &SCCNodes) {
- // An ordered atomic may synchronize. (See comment about on monotonic.)
- if (isOrderedAtomic(&I))
- return true;
-
- auto *CB = dyn_cast<CallBase>(&I);
- if (!CB)
- // Non call site cases covered by the two checks above
+ if (!I.maySynchronize())
return false;
- if (CB->hasFnAttr(Attribute::NoSync))
- return false;
-
- // Speculatively assume in SCC.
- if (Function *Callee = CB->getCalledFunction())
- if (SCCNodes.contains(Callee))
- return false;
+ // Optimistically assume calls within the SCC are nosync: if nothing else in
+ // the SCC synchronizes, the assumption holds.
+ if (auto *CB = dyn_cast<CallBase>(&I))
+ if (Function *Callee = CB->getCalledFunction())
+ if (SCCNodes.contains(Callee))
+ return false;
return true;
}
More information about the llvm-commits
mailing list