/// allocates memory (either malloc, calloc, or strdup like).
bool isAllocLikeFn(const Value *V, const TargetLibraryInfo *TLI);
-/// Tests if a value is a call or invoke to a library function that
-/// reallocates memory (e.g., realloc).
-bool isReallocLikeFn(const Value *V, const TargetLibraryInfo *TLI);
-
/// Tests if a function is a call or invoke to a library function that
/// reallocates memory (e.g., realloc).
bool isReallocLikeFn(const Function *F, const TargetLibraryInfo *TLI);
+/// If this is a call to a realloc function, return the reallocated operand.
+Value *getReallocatedOperand(const CallBase *CB, const TargetLibraryInfo *TLI);
+
//===----------------------------------------------------------------------===//
// free Call Utility Functions.
//
return getAllocationData(V, AllocLike, TLI).has_value();
}
-/// Tests if a value is a call or invoke to a library function that
-/// reallocates memory (e.g., realloc).
-bool llvm::isReallocLikeFn(const Value *V, const TargetLibraryInfo *TLI) {
- return getAllocationData(V, ReallocLike, TLI).has_value();
-}
-
/// Tests if a functions is a call or invoke to a library function that
/// reallocates memory (e.g., realloc).
bool llvm::isReallocLikeFn(const Function *F, const TargetLibraryInfo *TLI) {
return getAllocationDataForFunction(F, ReallocLike, TLI).has_value();
}
+Value *llvm::getReallocatedOperand(const CallBase *CB,
+ const TargetLibraryInfo *TLI) {
+ if (getAllocationData(CB, ReallocLike, TLI).has_value()) {
+ // All currently supported realloc functions reallocate the first argument.
+ return CB->getArgOperand(0);
+ }
+ return nullptr;
+}
+
bool llvm::isRemovableAlloc(const CallBase *CB, const TargetLibraryInfo *TLI) {
// Note: Removability is highly dependent on the source language. For
// example, recent C++ requires direct calls to the global allocation
continue;
}
- if (isReallocLikeFn(I, &TLI) &&
+ if (getReallocatedOperand(cast<CallBase>(I), &TLI) == PI &&
getAllocationFamily(I, &TLI) == Family) {
assert(Family);
Users.emplace_back(I);
// If we had free(realloc(...)) with no intervening uses, then eliminate the
// realloc() entirely.
- if (CallInst *CI = dyn_cast<CallInst>(Op)) {
- if (CI->hasOneUse() && isReallocLikeFn(CI, &TLI)) {
- return eraseInstFromFunction(
- *replaceInstUsesWith(*CI, CI->getOperand(0)));
- }
- }
+ CallInst *CI = dyn_cast<CallInst>(Op);
+ if (CI && CI->hasOneUse())
+ if (Value *ReallocatedOp = getReallocatedOperand(CI, &TLI))
+ return eraseInstFromFunction(*replaceInstUsesWith(*CI, ReallocatedOp));
// If we optimize for code size, try to move the call to free before the null
// test so that simplify cfg can remove the empty block and dead code