[llvm] [Loads] Migrate isDereferenceable APIs to SimplifyQuery (NFC) (PR #202553)
via llvm-commits
llvm-commits at lists.llvm.org
Tue Jun 9 02:17:44 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-llvm-transforms
Author: Nikita Popov (nikic)
<details>
<summary>Changes</summary>
These take the usual set of analysis parameters, so we can encapsulate them using SimplifyQuery.
---
Patch is 24.99 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/202553.diff
11 Files Affected:
- (modified) llvm/include/llvm/Analysis/Loads.h (+9-13)
- (modified) llvm/lib/Analysis/Loads.cpp (+56-78)
- (modified) llvm/lib/Analysis/MemDerefPrinter.cpp (+2-2)
- (modified) llvm/lib/Analysis/ValueTracking.cpp (+3-3)
- (modified) llvm/lib/CodeGen/MachineOperand.cpp (+2-2)
- (modified) llvm/lib/CodeGen/TargetLoweringBase.cpp (+3-3)
- (modified) llvm/lib/Transforms/IPO/ArgumentPromotion.cpp (+5-3)
- (modified) llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp (+1-1)
- (modified) llvm/lib/Transforms/Scalar/LICM.cpp (+2-1)
- (modified) llvm/lib/Transforms/Scalar/MemCpyOptimizer.cpp (+1-1)
- (modified) llvm/lib/Transforms/Utils/LoopPeel.cpp (+2-1)
``````````diff
diff --git a/llvm/include/llvm/Analysis/Loads.h b/llvm/include/llvm/Analysis/Loads.h
index 275dc2c5db847..00510c11632b9 100644
--- a/llvm/include/llvm/Analysis/Loads.h
+++ b/llvm/include/llvm/Analysis/Loads.h
@@ -14,6 +14,7 @@
#define LLVM_ANALYSIS_LOADS_H
#include "llvm/ADT/APInt.h"
+#include "llvm/Analysis/SimplifyQuery.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/GEPNoWrapFlags.h"
#include "llvm/Support/CommandLine.h"
@@ -39,29 +40,24 @@ class TargetLibraryInfo;
/// instruction is specified perform context-sensitive analysis and return true
/// if the pointer is dereferenceable at the specified instruction.
LLVM_ABI bool isDereferenceablePointer(const Value *V, Type *Ty,
- const DataLayout &DL,
- const Instruction *CtxI = nullptr,
- AssumptionCache *AC = nullptr,
- const DominatorTree *DT = nullptr,
- const TargetLibraryInfo *TLI = nullptr);
+ const SimplifyQuery &Q);
/// Returns true if V is always a dereferenceable pointer with alignment
/// greater or equal than requested. If the context instruction is specified
/// performs context-sensitive analysis and returns true if the pointer is
/// dereferenceable at the specified instruction.
-LLVM_ABI bool isDereferenceableAndAlignedPointer(
- const Value *V, Type *Ty, Align Alignment, const DataLayout &DL,
- const Instruction *CtxI = nullptr, AssumptionCache *AC = nullptr,
- const DominatorTree *DT = nullptr, const TargetLibraryInfo *TLI = nullptr);
+LLVM_ABI bool isDereferenceableAndAlignedPointer(const Value *V, Type *Ty,
+ Align Alignment,
+ const SimplifyQuery &Q);
/// Returns true if V is always dereferenceable for Size byte with alignment
/// greater or equal than requested. If the context instruction is specified
/// performs context-sensitive analysis and returns true if the pointer is
/// dereferenceable at the specified instruction.
-LLVM_ABI bool isDereferenceableAndAlignedPointer(
- const Value *V, Align Alignment, const APInt &Size, const DataLayout &DL,
- const Instruction *CtxI = nullptr, AssumptionCache *AC = nullptr,
- const DominatorTree *DT = nullptr, const TargetLibraryInfo *TLI = nullptr);
+LLVM_ABI bool isDereferenceableAndAlignedPointer(const Value *V,
+ Align Alignment,
+ const APInt &Size,
+ const SimplifyQuery &Q);
/// Return true if we know that executing a load from this value cannot trap.
///
diff --git a/llvm/lib/Analysis/Loads.cpp b/llvm/lib/Analysis/Loads.cpp
index ab27da6317bd7..647078849048e 100644
--- a/llvm/lib/Analysis/Loads.cpp
+++ b/llvm/lib/Analysis/Loads.cpp
@@ -33,29 +33,27 @@ static bool isAligned(const Value *Base, Align Alignment,
}
static bool isDereferenceableAndAlignedPointerViaAssumption(
- const Value *Ptr, Align Alignment,
- function_ref<bool(const RetainedKnowledge &RK)> CheckSize,
- const DataLayout &DL, const Instruction *CtxI, AssumptionCache *AC,
- const DominatorTree *DT) {
- if (!CtxI)
+ const Value *Ptr, Align Alignment, const SimplifyQuery &SQ,
+ function_ref<bool(const RetainedKnowledge &RK)> CheckSize) {
+ if (!SQ.CxtI)
return false;
/// Look through assumes to see if both dereferencability and alignment can
/// be proven by an assume if needed.
RetainedKnowledge AlignRK;
RetainedKnowledge DerefRK;
bool PtrCanBeFreed = Ptr->canBeFreed();
- bool IsAligned = Ptr->getPointerAlignment(DL) >= Alignment;
+ bool IsAligned = Ptr->getPointerAlignment(SQ.DL) >= Alignment;
return getKnowledgeForValue(
- Ptr, {Attribute::Dereferenceable, Attribute::Alignment}, *AC,
+ Ptr, {Attribute::Dereferenceable, Attribute::Alignment}, *SQ.AC,
[&](RetainedKnowledge RK, Instruction *Assume, auto) {
- if (!isValidAssumeForContext(Assume, CtxI, DT))
+ if (!isValidAssumeForContext(Assume, SQ.CxtI, SQ.DT))
return false;
if (RK.AttrKind == Attribute::Alignment)
AlignRK = std::max(AlignRK, RK);
// Dereferenceable information from assumptions is only valid if the
// value cannot be freed between the assumption and use.
- if ((!PtrCanBeFreed || willNotFreeBetween(Assume, CtxI)) &&
+ if ((!PtrCanBeFreed || willNotFreeBetween(Assume, SQ.CxtI)) &&
RK.AttrKind == Attribute::Dereferenceable)
DerefRK = std::max(DerefRK, RK);
IsAligned |= AlignRK && AlignRK.ArgValue >= Alignment.value();
@@ -69,10 +67,8 @@ static bool isDereferenceableAndAlignedPointerViaAssumption(
/// Test if V is always a pointer to allocated and suitably aligned memory for
/// a simple load or store.
static bool isDereferenceableAndAlignedPointer(
- const Value *V, Align Alignment, const APInt &Size, const DataLayout &DL,
- const Instruction *CtxI, AssumptionCache *AC, const DominatorTree *DT,
- const TargetLibraryInfo *TLI, SmallPtrSetImpl<const Value *> &Visited,
- unsigned MaxDepth) {
+ const Value *V, Align Alignment, const APInt &Size, const SimplifyQuery &SQ,
+ SmallPtrSetImpl<const Value *> &Visited, unsigned MaxDepth) {
assert(V->getType()->isPointerTy() && "Base must be pointer");
// Recursion limit.
@@ -90,8 +86,8 @@ static bool isDereferenceableAndAlignedPointer(
if (const GEPOperator *GEP = dyn_cast<GEPOperator>(V)) {
const Value *Base = GEP->getPointerOperand();
- APInt Offset(DL.getIndexTypeSizeInBits(GEP->getType()), 0);
- if (!GEP->accumulateConstantOffset(DL, Offset) || Offset.isNegative() ||
+ APInt Offset(SQ.DL.getIndexTypeSizeInBits(GEP->getType()), 0);
+ if (!GEP->accumulateConstantOffset(SQ.DL, Offset) || Offset.isNegative() ||
!Offset.urem(APInt(Offset.getBitWidth(), Alignment.value()))
.isMinValue())
return false;
@@ -105,35 +101,31 @@ static bool isDereferenceableAndAlignedPointer(
// Offset and Size may have different bit widths if we have visited an
// addrspacecast, so we can't do arithmetic directly on the APInt values.
return isDereferenceableAndAlignedPointer(
- Base, Alignment, Offset + Size.sextOrTrunc(Offset.getBitWidth()), DL,
- CtxI, AC, DT, TLI, Visited, MaxDepth);
+ Base, Alignment, Offset + Size.sextOrTrunc(Offset.getBitWidth()), SQ,
+ Visited, MaxDepth);
}
// bitcast instructions are no-ops as far as dereferenceability is concerned.
if (const BitCastOperator *BC = dyn_cast<BitCastOperator>(V)) {
if (BC->getSrcTy()->isPointerTy())
- return isDereferenceableAndAlignedPointer(
- BC->getOperand(0), Alignment, Size, DL, CtxI, AC, DT, TLI,
- Visited, MaxDepth);
+ return isDereferenceableAndAlignedPointer(BC->getOperand(0), Alignment,
+ Size, SQ, Visited, MaxDepth);
}
// Recurse into both hands of select.
if (const SelectInst *Sel = dyn_cast<SelectInst>(V)) {
return isDereferenceableAndAlignedPointer(Sel->getTrueValue(), Alignment,
- Size, DL, CtxI, AC, DT, TLI,
- Visited, MaxDepth) &&
+ Size, SQ, Visited, MaxDepth) &&
isDereferenceableAndAlignedPointer(Sel->getFalseValue(), Alignment,
- Size, DL, CtxI, AC, DT, TLI,
- Visited, MaxDepth);
+ Size, SQ, Visited, MaxDepth);
}
auto IsKnownDeref = [&]() {
bool CheckForNonNull, CheckForFreed;
- if (!Size.ule(V->getPointerDereferenceableBytes(DL, CheckForNonNull,
+ if (!Size.ule(V->getPointerDereferenceableBytes(SQ.DL, CheckForNonNull,
CheckForFreed)))
return false;
- if (CheckForNonNull &&
- !isKnownNonZero(V, SimplifyQuery(DL, DT, AC, CtxI)))
+ if (CheckForNonNull && !isKnownNonZero(V, SQ))
return false;
auto *I = dyn_cast<Instruction>(V);
@@ -154,7 +146,7 @@ static bool isDereferenceableAndAlignedPointer(
DefI = &cast<Argument>(V)->getParent()->getEntryBlock().front();
}
- if (!CtxI || !willNotFreeBetween(DefI, CtxI))
+ if (!SQ.CxtI || !willNotFreeBetween(DefI, SQ.CxtI))
return false;
}
@@ -167,14 +159,14 @@ static bool isDereferenceableAndAlignedPointer(
// We don't bother handling allocas here, as they aren't speculatable
// anyway.
if (I && !isa<AllocaInst>(I))
- return CtxI && isValidAssumeForContext(I, CtxI, DT);
+ return SQ.CxtI && isValidAssumeForContext(I, SQ.CxtI, SQ.DT);
return true;
};
if (IsKnownDeref()) {
// As we recursed through GEPs to get here, we've incrementally checked
// that each step advanced by a multiple of the alignment. If our base is
// properly aligned, then the original offset accessed must also be.
- return isAligned(V, Alignment, DL);
+ return isAligned(V, Alignment, SQ.DL);
}
/// TODO refactor this function to be able to search independently for
@@ -184,8 +176,8 @@ static bool isDereferenceableAndAlignedPointer(
if (const auto *Call = dyn_cast<CallBase>(V)) {
if (auto *RP = getArgumentAliasingToReturnedPointer(
Call, /*MustPreserveOffset=*/true))
- return isDereferenceableAndAlignedPointer(RP, Alignment, Size, DL, CtxI,
- AC, DT, TLI, Visited, MaxDepth);
+ return isDereferenceableAndAlignedPointer(RP, Alignment, Size, SQ,
+ Visited, MaxDepth);
// If we have a call we can't recurse through, check to see if this is an
// allocation function for which we can establish an minimum object size.
@@ -201,57 +193,50 @@ static bool isDereferenceableAndAlignedPointer(
Opts.RoundToAlign = false;
Opts.NullIsUnknownSize = true;
uint64_t ObjSize;
- if (getObjectSize(V, ObjSize, DL, TLI, Opts)) {
+ if (getObjectSize(V, ObjSize, SQ.DL, SQ.TLI, Opts)) {
APInt KnownDerefBytes(Size.getBitWidth(), ObjSize);
if (KnownDerefBytes.getBoolValue() && KnownDerefBytes.uge(Size) &&
- isKnownNonZero(V, SimplifyQuery(DL, DT, AC, CtxI)) &&
- !V->canBeFreed()) {
+ isKnownNonZero(V, SQ) && !V->canBeFreed()) {
// As we recursed through GEPs to get here, we've incrementally
// checked that each step advanced by a multiple of the alignment. If
// our base is properly aligned, then the original offset accessed
// must also be.
- return isAligned(V, Alignment, DL);
+ return isAligned(V, Alignment, SQ.DL);
}
}
}
// For gc.relocate, look through relocations
if (const GCRelocateInst *RelocateInst = dyn_cast<GCRelocateInst>(V))
- return isDereferenceableAndAlignedPointer(RelocateInst->getDerivedPtr(),
- Alignment, Size, DL, CtxI, AC, DT,
- TLI, Visited, MaxDepth);
+ return isDereferenceableAndAlignedPointer(
+ RelocateInst->getDerivedPtr(), Alignment, Size, SQ, Visited, MaxDepth);
if (const AddrSpaceCastOperator *ASC = dyn_cast<AddrSpaceCastOperator>(V))
return isDereferenceableAndAlignedPointer(ASC->getOperand(0), Alignment,
- Size, DL, CtxI, AC, DT, TLI,
- Visited, MaxDepth);
-
- return AC && isDereferenceableAndAlignedPointerViaAssumption(
- V, Alignment,
- [Size](const RetainedKnowledge &RK) {
- return RK.ArgValue >= Size.getZExtValue();
- },
- DL, CtxI, AC, DT);
+ Size, SQ, Visited, MaxDepth);
+
+ return SQ.AC && isDereferenceableAndAlignedPointerViaAssumption(
+ V, Alignment, SQ, [Size](const RetainedKnowledge &RK) {
+ return RK.ArgValue >= Size.getZExtValue();
+ });
}
-bool llvm::isDereferenceableAndAlignedPointer(
- const Value *V, Align Alignment, const APInt &Size, const DataLayout &DL,
- const Instruction *CtxI, AssumptionCache *AC, const DominatorTree *DT,
- const TargetLibraryInfo *TLI) {
+bool llvm::isDereferenceableAndAlignedPointer(const Value *V, Align Alignment,
+ const APInt &Size,
+ const SimplifyQuery &SQ) {
// Note: At the moment, Size can be zero. This ends up being interpreted as
// a query of whether [Base, V] is dereferenceable and V is aligned (since
// that's what the implementation happened to do). It's unclear if this is
// the desired semantic, but at least SelectionDAG does exercise this case.
SmallPtrSet<const Value *, 32> Visited;
- return ::isDereferenceableAndAlignedPointer(V, Alignment, Size, DL, CtxI, AC,
- DT, TLI, Visited, 16);
+ return ::isDereferenceableAndAlignedPointer(V, Alignment, Size, SQ, Visited,
+ /*MaxDepth=*/16);
}
-bool llvm::isDereferenceableAndAlignedPointer(
- const Value *V, Type *Ty, Align Alignment, const DataLayout &DL,
- const Instruction *CtxI, AssumptionCache *AC, const DominatorTree *DT,
- const TargetLibraryInfo *TLI) {
+bool llvm::isDereferenceableAndAlignedPointer(const Value *V, Type *Ty,
+ Align Alignment,
+ const SimplifyQuery &SQ) {
// For unsized types or scalable vectors we don't know exactly how many bytes
// are dereferenced, so bail out.
if (!Ty->isSized() || Ty->isScalableTy())
@@ -262,20 +247,14 @@ bool llvm::isDereferenceableAndAlignedPointer(
// determine the exact offset to the attributed variable, we can use that
// information here.
- APInt AccessSize(DL.getPointerTypeSizeInBits(V->getType()),
- DL.getTypeStoreSize(Ty));
- return isDereferenceableAndAlignedPointer(V, Alignment, AccessSize, DL, CtxI,
- AC, DT, TLI);
+ APInt AccessSize(SQ.DL.getPointerTypeSizeInBits(V->getType()),
+ SQ.DL.getTypeStoreSize(Ty));
+ return isDereferenceableAndAlignedPointer(V, Alignment, AccessSize, SQ);
}
bool llvm::isDereferenceablePointer(const Value *V, Type *Ty,
- const DataLayout &DL,
- const Instruction *CtxI,
- AssumptionCache *AC,
- const DominatorTree *DT,
- const TargetLibraryInfo *TLI) {
- return isDereferenceableAndAlignedPointer(V, Ty, Align(1), DL, CtxI, AC, DT,
- TLI);
+ const SimplifyQuery &SQ) {
+ return isDereferenceableAndAlignedPointer(V, Ty, Align(1), SQ);
}
/// Test if A and B will obviously have the same value.
@@ -321,8 +300,8 @@ bool llvm::isDereferenceableAndAlignedInLoop(
// access is safe within the loop w/o needing predication.
if (L->isLoopInvariant(Ptr))
return isDereferenceableAndAlignedPointer(
- Ptr, LI->getAlign(), EltSize, DL, &*L->getHeader()->getFirstNonPHIIt(),
- AC, &DT);
+ Ptr, LI->getAlign(), EltSize,
+ SimplifyQuery(DL, &DT, AC, &*L->getHeader()->getFirstNonPHIIt()));
const SCEV *EltSizeSCEV = SE.getConstant(EltSize);
return isDereferenceableAndAlignedInLoop(PtrSCEV, LI->getAlign(), EltSizeSCEV,
@@ -428,17 +407,16 @@ bool llvm::isDereferenceableAndAlignedInLoop(
if (isa<UncondBrInst, CondBrInst>(LoopPred->getTerminator()))
CtxI = LoopPred->getTerminator();
}
+ SimplifyQuery SQ(DL, &DT, AC, CtxI);
return isDereferenceableAndAlignedPointerViaAssumption(
- Base, Alignment,
+ Base, Alignment, SQ,
[&SE, AccessSizeSCEV, &LoopGuards](const RetainedKnowledge &RK) {
return SE.isKnownPredicate(
CmpInst::ICMP_ULE,
SE.applyLoopGuards(AccessSizeSCEV, *LoopGuards),
SE.applyLoopGuards(SE.getSCEV(RK.IRArgValue), *LoopGuards));
- },
- DL, CtxI, AC, &DT) ||
- isDereferenceableAndAlignedPointer(Base, Alignment, AccessSize, DL,
- CtxI, AC, &DT);
+ }) ||
+ isDereferenceableAndAlignedPointer(Base, Alignment, AccessSize, SQ);
}
static bool suppressSpeculativeLoadForSanitizers(const Instruction &CtxI) {
@@ -460,8 +438,8 @@ bool llvm::isSafeToLoadUnconditionally(Value *V, Align Alignment, const APInt &S
AssumptionCache *AC,
const DominatorTree *DT,
const TargetLibraryInfo *TLI) {
- if (isDereferenceableAndAlignedPointer(V, Alignment, Size, DL, ScanFrom, AC,
- DT, TLI)) {
+ if (isDereferenceableAndAlignedPointer(
+ V, Alignment, Size, SimplifyQuery(DL, TLI, DT, AC, ScanFrom, AC))) {
// With sanitizers `Dereferenceable` is not always enough for unconditional
// load.
if (!ScanFrom || !suppressSpeculativeLoadForSanitizers(*ScanFrom))
diff --git a/llvm/lib/Analysis/MemDerefPrinter.cpp b/llvm/lib/Analysis/MemDerefPrinter.cpp
index e1245e2ed44c0..2b157cf06dc05 100644
--- a/llvm/lib/Analysis/MemDerefPrinter.cpp
+++ b/llvm/lib/Analysis/MemDerefPrinter.cpp
@@ -27,10 +27,10 @@ PreservedAnalyses MemDerefPrinterPass::run(Function &F,
for (auto &I : instructions(F)) {
if (LoadInst *LI = dyn_cast<LoadInst>(&I)) {
Value *PO = LI->getPointerOperand();
- if (isDereferenceablePointer(PO, LI->getType(), DL, LI))
+ if (isDereferenceablePointer(PO, LI->getType(), SimplifyQuery(DL, LI)))
Deref.push_back(PO);
if (isDereferenceableAndAlignedPointer(PO, LI->getType(), LI->getAlign(),
- DL, LI))
+ SimplifyQuery(DL, LI)))
DerefAndAligned.insert(PO);
}
}
diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index 04def11136d35..96a7a10675d89 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -7303,9 +7303,9 @@ bool llvm::isSafeToSpeculativelyExecuteWithOpcode(
if (mustSuppressSpeculation(*LI))
return false;
const DataLayout &DL = LI->getDataLayout();
- return isDereferenceableAndAlignedPointer(LI->getPointerOperand(),
- LI->getType(), LI->getAlign(), DL,
- CtxI, AC, DT, TLI);
+ return isDereferenceableAndAlignedPointer(
+ LI->getPointerOperand(), LI->getType(), LI->getAlign(),
+ SimplifyQuery(DL, TLI, DT, AC, CtxI));
}
case Instruction::Call: {
auto *CI = dyn_cast<const CallInst>(Inst);
diff --git a/llvm/lib/CodeGen/MachineOperand.cpp b/llvm/lib/CodeGen/MachineOperand.cpp
index 4185035b79337..96aac20610ff7 100644
--- a/llvm/lib/CodeGen/MachineOperand.cpp
+++ b/llvm/lib/CodeGen/MachineOperand.cpp
@@ -1135,8 +1135,8 @@ bool MachinePointerInfo::isDereferenceable(unsigned Size, LLVMContext &C,
return false;
return isDereferenceableAndAlignedPointer(
- BasePtr, Align(1), APInt(DL.getPointerSizeInBits(), Offset + Size), DL,
- dyn_cast<Instruction>(BasePtr));
+ BasePtr, Align(1), APInt(DL.getPointerSizeInBits(), Offset + Size),
+ SimplifyQuery(DL, dyn_cast<Instruction>(BasePtr)));
}
/// getConstantPool - Return a MachinePointerInfo record that refers to the
diff --git a/llvm/lib/CodeGen/TargetLoweringBase.cpp b/llvm/lib/CodeGen/TargetLoweringBase.cpp
index 1f4842fb3df15..83ad156e770f4 100644
--- a/llvm/lib/CodeGen/TargetLoweringBase.cpp
+++ b/llvm/lib/CodeGen/Targ...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/202553
More information about the llvm-commits
mailing list