[llvm] c81dff3 - [MemoryBuiltins] Add getFreedOperand() function (NFCI)
Nikita Popov via llvm-commits
llvm-commits at lists.llvm.org
Thu Jul 21 03:39:43 PDT 2022
Author: Nikita Popov
Date: 2022-07-21T12:39:35+02:00
New Revision: c81dff3c306dd1a26e5f6377a040f811c325ba76
URL: https://github.com/llvm/llvm-project/commit/c81dff3c306dd1a26e5f6377a040f811c325ba76
DIFF: https://github.com/llvm/llvm-project/commit/c81dff3c306dd1a26e5f6377a040f811c325ba76.diff
LOG: [MemoryBuiltins] Add getFreedOperand() function (NFCI)
We currently assume in a number of places that free-like functions
free their first argument. This is true for all hardcoded free-like
functions, but with the new attribute-based design, the freed
argument is supposed to be indicated by the allocptr attribute.
To make sure we handle this correctly once allockind(free) is
respected, add a getFreedOperand() helper which returns the freed
argument, rather than just indicating whether the call frees *some*
argument.
This migrates most but not all users of isFreeCall() to the new
API. The remaining users are a bit more tricky.
Added:
Modified:
llvm/include/llvm/Analysis/MemoryBuiltins.h
llvm/lib/Analysis/GlobalsModRef.cpp
llvm/lib/Analysis/MemoryBuiltins.cpp
llvm/lib/Analysis/MemoryDependenceAnalysis.cpp
llvm/lib/Transforms/IPO/AttributorAttributes.cpp
llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
llvm/lib/Transforms/InstCombine/InstCombineInternal.h
llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp
llvm/lib/Transforms/Utils/Local.cpp
Removed:
################################################################################
diff --git a/llvm/include/llvm/Analysis/MemoryBuiltins.h b/llvm/include/llvm/Analysis/MemoryBuiltins.h
index 457a9d330ae24..81591e653363b 100644
--- a/llvm/include/llvm/Analysis/MemoryBuiltins.h
+++ b/llvm/include/llvm/Analysis/MemoryBuiltins.h
@@ -80,12 +80,11 @@ bool isReallocLikeFn(const Function *F, const TargetLibraryInfo *TLI);
/// isLibFreeFunction - Returns true if the function is a builtin free()
bool isLibFreeFunction(const Function *F, const LibFunc TLIFn);
-/// isFreeCall - Returns non-null if the value is a call to the builtin free()
-const CallInst *isFreeCall(const Value *I, const TargetLibraryInfo *TLI);
+/// Returns true if the value is a call to a free function.
+bool isFreeCall(const Value *I, const TargetLibraryInfo *TLI);
-inline CallInst *isFreeCall(Value *I, const TargetLibraryInfo *TLI) {
- return const_cast<CallInst*>(isFreeCall((const Value*)I, TLI));
-}
+/// If this if a call to a free function, return the freed operand.
+Value *getFreedOperand(const CallBase *CB, const TargetLibraryInfo *TLI);
//===----------------------------------------------------------------------===//
// Properties of allocation functions
diff --git a/llvm/lib/Analysis/GlobalsModRef.cpp b/llvm/lib/Analysis/GlobalsModRef.cpp
index 563a84ed3f5ba..e6ef1c78a628f 100644
--- a/llvm/lib/Analysis/GlobalsModRef.cpp
+++ b/llvm/lib/Analysis/GlobalsModRef.cpp
@@ -361,7 +361,7 @@ bool GlobalsAAResult::AnalyzeUsesOfPointer(Value *V,
if (Call->isDataOperand(&U)) {
// Detect calls to free.
if (Call->isArgOperand(&U) &&
- isFreeCall(I, &GetTLI(*Call->getFunction()))) {
+ getFreedOperand(Call, &GetTLI(*Call->getFunction())) == U) {
if (Writers)
Writers->insert(Call->getParent()->getParent());
} else {
diff --git a/llvm/lib/Analysis/MemoryBuiltins.cpp b/llvm/lib/Analysis/MemoryBuiltins.cpp
index bf81d3b4dbe1f..0ea0b9fe8b1cc 100644
--- a/llvm/lib/Analysis/MemoryBuiltins.cpp
+++ b/llvm/lib/Analysis/MemoryBuiltins.cpp
@@ -531,20 +531,25 @@ bool llvm::isLibFreeFunction(const Function *F, const LibFunc TLIFn) {
return true;
}
-/// isFreeCall - Returns non-null if the value is a call to the builtin free()
-const CallInst *llvm::isFreeCall(const Value *I, const TargetLibraryInfo *TLI) {
+bool llvm::isFreeCall(const Value *I, const TargetLibraryInfo *TLI) {
bool IsNoBuiltinCall;
const Function *Callee = getCalledFunction(I, IsNoBuiltinCall);
if (Callee == nullptr || IsNoBuiltinCall)
- return nullptr;
+ return false;
LibFunc TLIFn;
if (!TLI || !TLI->getLibFunc(*Callee, TLIFn) || !TLI->has(TLIFn))
- return nullptr;
+ return false;
- return isLibFreeFunction(Callee, TLIFn) ? dyn_cast<CallInst>(I) : nullptr;
+ return isLibFreeFunction(Callee, TLIFn);
}
+Value *llvm::getFreedOperand(const CallBase *CB, const TargetLibraryInfo *TLI) {
+ // All currently supported free functions free the first argument.
+ if (isFreeCall(CB, TLI))
+ return CB->getArgOperand(0);
+ return nullptr;
+}
//===----------------------------------------------------------------------===//
// Utility functions to compute size of objects.
diff --git a/llvm/lib/Analysis/MemoryDependenceAnalysis.cpp b/llvm/lib/Analysis/MemoryDependenceAnalysis.cpp
index 690d575ef9790..fce9d5b24faf7 100644
--- a/llvm/lib/Analysis/MemoryDependenceAnalysis.cpp
+++ b/llvm/lib/Analysis/MemoryDependenceAnalysis.cpp
@@ -139,10 +139,12 @@ static ModRefInfo GetLocation(const Instruction *Inst, MemoryLocation &Loc,
return ModRefInfo::ModRef;
}
- if (const CallInst *CI = isFreeCall(Inst, &TLI)) {
- // calls to free() deallocate the entire structure
- Loc = MemoryLocation::getAfter(CI->getArgOperand(0));
- return ModRefInfo::Mod;
+ if (const CallBase *CB = dyn_cast<CallBase>(Inst)) {
+ if (Value *FreedOp = getFreedOperand(CB, &TLI)) {
+ // calls to free() deallocate the entire structure
+ Loc = MemoryLocation::getAfter(FreedOp);
+ return ModRefInfo::Mod;
+ }
}
if (const IntrinsicInst *II = dyn_cast<IntrinsicInst>(Inst)) {
diff --git a/llvm/lib/Transforms/IPO/AttributorAttributes.cpp b/llvm/lib/Transforms/IPO/AttributorAttributes.cpp
index af515c9fe34a1..0f87d101ae09c 100644
--- a/llvm/lib/Transforms/IPO/AttributorAttributes.cpp
+++ b/llvm/lib/Transforms/IPO/AttributorAttributes.cpp
@@ -1372,7 +1372,7 @@ struct AAPointerInfoFloating : public AAPointerInfoImpl {
if (auto *CB = dyn_cast<CallBase>(Usr)) {
if (CB->isLifetimeStartOrEnd())
return true;
- if (TLI && isFreeCall(CB, TLI))
+ if (getFreedOperand(CB, TLI) == U)
return true;
if (CB->isArgOperand(&U)) {
unsigned ArgNo = CB->getArgOperandNo(&U);
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
index 8ac9be5e00e26..33ee905e149c3 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
@@ -1140,8 +1140,8 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
if (Value *V = simplifyCall(&CI, SQ.getWithInstruction(&CI)))
return replaceInstUsesWith(CI, V);
- if (isFreeCall(&CI, &TLI))
- return visitFree(CI);
+ if (Value *FreedOp = getFreedOperand(&CI, &TLI))
+ return visitFree(CI, FreedOp);
// If the caller function (i.e. us, the function that contains this CallInst)
// is nounwind, mark the call as nounwind, even if the callee isn't.
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineInternal.h b/llvm/lib/Transforms/InstCombine/InstCombineInternal.h
index 271154bb3f5a9..827b25533513d 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineInternal.h
+++ b/llvm/lib/Transforms/InstCombine/InstCombineInternal.h
@@ -152,7 +152,7 @@ class LLVM_LIBRARY_VISIBILITY InstCombinerImpl final
Instruction *visitGEPOfBitcast(BitCastInst *BCI, GetElementPtrInst &GEP);
Instruction *visitAllocaInst(AllocaInst &AI);
Instruction *visitAllocSite(Instruction &FI);
- Instruction *visitFree(CallInst &FI);
+ Instruction *visitFree(CallInst &FI, Value *FreedOp);
Instruction *visitLoadInst(LoadInst &LI);
Instruction *visitStoreInst(StoreInst &SI);
Instruction *visitAtomicRMWInst(AtomicRMWInst &SI);
diff --git a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
index 98292c49e714c..cae73589b59a7 100644
--- a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
@@ -3034,9 +3034,7 @@ static Instruction *tryToMoveFreeBeforeNullTest(CallInst &FI,
return &FI;
}
-Instruction *InstCombinerImpl::visitFree(CallInst &FI) {
- Value *Op = FI.getArgOperand(0);
-
+Instruction *InstCombinerImpl::visitFree(CallInst &FI, Value *Op) {
// free undef -> unreachable.
if (isa<UndefValue>(Op)) {
// Leave a marker since we can't modify the CFG here.
diff --git a/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp b/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp
index 9095ca7e4e7c1..c675291688aab 100644
--- a/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp
+++ b/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp
@@ -1108,9 +1108,8 @@ struct DSEState {
return {std::make_pair(MemoryLocation(Ptr, Len), false)};
if (auto *CB = dyn_cast<CallBase>(I)) {
- if (isFreeCall(I, &TLI))
- return {std::make_pair(MemoryLocation::getAfter(CB->getArgOperand(0)),
- true)};
+ if (Value *FreedOp = getFreedOperand(CB, &TLI))
+ return {std::make_pair(MemoryLocation::getAfter(FreedOp), true)};
}
return None;
diff --git a/llvm/lib/Transforms/Utils/Local.cpp b/llvm/lib/Transforms/Utils/Local.cpp
index 83e67b108ed9f..c1cf1f10c4100 100644
--- a/llvm/lib/Transforms/Utils/Local.cpp
+++ b/llvm/lib/Transforms/Utils/Local.cpp
@@ -493,13 +493,13 @@ bool llvm::wouldInstructionBeTriviallyDead(Instruction *I,
}
}
- if (CallInst *CI = isFreeCall(I, TLI))
- if (Constant *C = dyn_cast<Constant>(CI->getArgOperand(0)))
- return C->isNullValue() || isa<UndefValue>(C);
-
- if (auto *Call = dyn_cast<CallBase>(I))
+ if (auto *Call = dyn_cast<CallBase>(I)) {
+ if (Value *FreedOp = getFreedOperand(Call, TLI))
+ if (Constant *C = dyn_cast<Constant>(FreedOp))
+ return C->isNullValue() || isa<UndefValue>(C);
if (isMathLibCallNoop(Call, TLI))
return true;
+ }
// Non-volatile atomic loads from constants can be removed.
if (auto *LI = dyn_cast<LoadInst>(I))
More information about the llvm-commits
mailing list