case IC_Retain:
case IC_RetainRV:
// Check for a retain of the same pointer for merging.
- return GetObjCArg(Inst) == Arg;
+ return GetArgRCIdentityRoot(Inst) == Arg;
default:
// Nothing else matters for objc_retainAutorelease formation.
return false;
case IC_Retain:
case IC_RetainRV:
// Check for a retain of the same pointer for merging.
- return GetObjCArg(Inst) == Arg;
+ return GetArgRCIdentityRoot(Inst) == Arg;
default:
// Anything that can autorelease interrupts
// retainAutoreleaseReturnValue formation.
return V;
}
-/// \brief This is a wrapper around Value::stripPointerCasts which also knows
-/// how to look through objc_retain and objc_autorelease calls, which we know to
-/// return their argument verbatim.
-static inline const Value *StripPointerCastsAndObjCCalls(const Value *V) {
+/// The RCIdentity root of a value \p V is a dominating value U for which
+/// retaining or releasing U is equivalent to retaining or releasing V. In other
+/// words, ARC operations on \p V are equivalent to ARC operations on \p U.
+///
+/// We use this in the ARC optimizer to make it easier to match up ARC
+/// operations by always mapping ARC operations to RCIdentityRoots instead of
+/// pointers themselves.
+///
+/// The two ways that we see RCIdentical values in ObjC are via:
+///
+/// 1. PointerCasts
+/// 2. Forwarding Calls that return their argument verbatim.
+///
+/// Thus this function strips off pointer casts and forwarding calls. *NOTE*
+/// This implies that two RCIdentical values must alias.
+static inline const Value *GetRCIdentityRoot(const Value *V) {
for (;;) {
V = V->stripPointerCasts();
if (!IsForwarding(GetBasicInstructionClass(V)))
return V;
}
-/// \brief This is a wrapper around Value::stripPointerCasts which also knows
-/// how to look through objc_retain and objc_autorelease calls, which we know to
-/// return their argument verbatim.
-static inline Value *StripPointerCastsAndObjCCalls(Value *V) {
- for (;;) {
- V = V->stripPointerCasts();
- if (!IsForwarding(GetBasicInstructionClass(V)))
- break;
- V = cast<CallInst>(V)->getArgOperand(0);
- }
- return V;
+/// Helper which calls const Value *GetRCIdentityRoot(const Value *V) and just
+/// casts away the const of the result. For documentation about what an
+/// RCIdentityRoot (and by extension GetRCIdentityRoot is) look at that
+/// function.
+static inline Value *GetRCIdentityRoot(Value *V) {
+ return const_cast<Value *>(GetRCIdentityRoot((const Value *)V));
}
/// \brief Assuming the given instruction is one of the special calls such as
-/// objc_retain or objc_release, return the argument value, stripped of no-op
-/// casts and forwarding calls.
-static inline Value *GetObjCArg(Value *Inst) {
- return StripPointerCastsAndObjCCalls(cast<CallInst>(Inst)->getArgOperand(0));
+/// objc_retain or objc_release, return the RCIdentity root of the argument of
+/// the call.
+static inline Value *GetArgRCIdentityRoot(Value *Inst) {
+ return GetRCIdentityRoot(cast<CallInst>(Inst)->getArgOperand(0));
}
static inline bool IsNullOrUndef(const Value *V) {
if (const LoadInst *LI = dyn_cast<LoadInst>(V)) {
const Value *Pointer =
- StripPointerCastsAndObjCCalls(LI->getPointerOperand());
+ GetRCIdentityRoot(LI->getPointerOperand());
if (const GlobalVariable *GV = dyn_cast<GlobalVariable>(Pointer)) {
// A constant pointer can't be pointing to an object on the heap. It may
// be reference-counted, but it won't be deleted.
// First, strip off no-ops, including ObjC-specific no-ops, and try making a
// precise alias query.
- const Value *SA = StripPointerCastsAndObjCCalls(LocA.Ptr);
- const Value *SB = StripPointerCastsAndObjCCalls(LocB.Ptr);
+ const Value *SA = GetRCIdentityRoot(LocA.Ptr);
+ const Value *SB = GetRCIdentityRoot(LocB.Ptr);
AliasResult Result =
AliasAnalysis::alias(Location(SA, LocA.Size, LocA.AATags),
Location(SB, LocB.Size, LocB.AATags));
// First, strip off no-ops, including ObjC-specific no-ops, and try making
// a precise alias query.
- const Value *S = StripPointerCastsAndObjCCalls(Loc.Ptr);
+ const Value *S = GetRCIdentityRoot(Loc.Ptr);
if (AliasAnalysis::pointsToConstantMemory(Location(S, Loc.Size, Loc.AATags),
OrLocal))
return true;
/// return value. We do this late so we do not disrupt the dataflow analysis in
/// ObjCARCOpt.
bool ObjCARCContract::optimizeRetainCall(Function &F, Instruction *Retain) {
- ImmutableCallSite CS(GetObjCArg(Retain));
+ ImmutableCallSite CS(GetArgRCIdentityRoot(Retain));
const Instruction *Call = CS.getInstruction();
if (!Call)
return false;
Function &F, Instruction *Autorelease, InstructionClass Class,
SmallPtrSetImpl<Instruction *> &DependingInstructions,
SmallPtrSetImpl<const BasicBlock *> &Visited) {
- const Value *Arg = GetObjCArg(Autorelease);
+ const Value *Arg = GetArgRCIdentityRoot(Autorelease);
// Check that there are no instructions between the retain and the autorelease
// (such as an autorelease_pop) which may change the count.
if (!Retain ||
GetBasicInstructionClass(Retain) != IC_Retain ||
- GetObjCArg(Retain) != Arg)
+ GetArgRCIdentityRoot(Retain) != Arg)
return false;
Changed = true;
void
ObjCARCContract::
tryToContractReleaseIntoStoreStrong(Instruction *Release, inst_iterator &Iter) {
- LoadInst *Load = dyn_cast<LoadInst>(GetObjCArg(Release));
+ LoadInst *Load = dyn_cast<LoadInst>(GetArgRCIdentityRoot(Release));
if (!Load || !Load->isSimple()) return;
// For now, require everything to be in one basic block.
}
}
- Value *New = StripPointerCastsAndObjCCalls(Store->getValueOperand());
+ Value *New = GetRCIdentityRoot(Store->getValueOperand());
// Walk up to find the retain.
I = Store;
--I;
Instruction *Retain = I;
if (GetBasicInstructionClass(Retain) != IC_Retain) return;
- if (GetObjCArg(Retain) != New) return;
+ if (GetArgRCIdentityRoot(Retain) != New) return;
Changed = true;
++NumStoreStrongs;
--BBI;
} while (IsNoopInstruction(BBI));
- if (&*BBI == GetObjCArg(Inst)) {
+ if (&*BBI == GetArgRCIdentityRoot(Inst)) {
DEBUG(dbgs() << "Adding inline asm marker for "
"retainAutoreleasedReturnValue optimization.\n");
Changed = true;
// Otherwise, try to undo objc-arc-expand.
- // Don't use GetObjCArg because we don't want to look through bitcasts
+ // Don't use GetArgRCIdentityRoot because we don't want to look through bitcasts
// and such; to do the replacement, the argument must have type i8*.
Value *Arg = cast<CallInst>(Inst)->getArgOperand(0);
// reachability here because an unreachable call is considered to
// trivially dominate itself, which would lead us to rewriting its
// argument in terms of its return value, which would lead to
- // infinite loops in GetObjCArg.
+ // infinite loops in GetArgRCIdentityRoot.
if (DT->isReachableFromEntry(U) && DT->dominates(Inst, U)) {
Changed = true;
Instruction *Replacement = Inst;
/// \defgroup ARCUtilities Utility declarations/definitions specific to ARC.
/// @{
-/// \brief This is similar to StripPointerCastsAndObjCCalls but it stops as soon
+/// \brief This is similar to GetRCIdentityRoot but it stops as soon
/// as it finds a value with multiple uses.
static const Value *FindSingleUseIdentifiedObject(const Value *Arg) {
if (Arg->hasOneUse()) {
// trivial uses, we can still consider this to be a single-use value.
if (IsObjCIdentifiedObject(Arg)) {
for (const User *U : Arg->users())
- if (!U->use_empty() || StripPointerCastsAndObjCCalls(U) != Arg)
+ if (!U->use_empty() || GetRCIdentityRoot(U) != Arg)
return nullptr;
return Arg;
bool
ObjCARCOpt::OptimizeRetainRVCall(Function &F, Instruction *RetainRV) {
// Check for the argument being from an immediately preceding call or invoke.
- const Value *Arg = GetObjCArg(RetainRV);
+ const Value *Arg = GetArgRCIdentityRoot(RetainRV);
ImmutableCallSite CS(Arg);
if (const Instruction *Call = CS.getInstruction()) {
if (Call->getParent() == RetainRV->getParent()) {
if (I != Begin) {
do --I; while (I != Begin && IsNoopInstruction(I));
if (GetBasicInstructionClass(I) == IC_AutoreleaseRV &&
- GetObjCArg(I) == Arg) {
+ GetArgRCIdentityRoot(I) == Arg) {
Changed = true;
++NumPeeps;
ObjCARCOpt::OptimizeAutoreleaseRVCall(Function &F, Instruction *AutoreleaseRV,
InstructionClass &Class) {
// Check for a return of the pointer value.
- const Value *Ptr = GetObjCArg(AutoreleaseRV);
+ const Value *Ptr = GetArgRCIdentityRoot(AutoreleaseRV);
SmallVector<const Value *, 2> Users;
Users.push_back(Ptr);
do {
continue;
}
- const Value *Arg = GetObjCArg(Inst);
+ const Value *Arg = GetArgRCIdentityRoot(Inst);
// ARC calls with null are no-ops. Delete them.
if (IsNullOrUndef(Arg)) {
bool HasCriticalEdges = false;
for (unsigned i = 0, e = PN->getNumIncomingValues(); i != e; ++i) {
Value *Incoming =
- StripPointerCastsAndObjCCalls(PN->getIncomingValue(i));
+ GetRCIdentityRoot(PN->getIncomingValue(i));
if (IsNullOrUndef(Incoming))
HasNull = true;
else if (cast<TerminatorInst>(PN->getIncomingBlock(i)->back())
Type *ParamTy = CInst->getArgOperand(0)->getType();
for (unsigned i = 0, e = PN->getNumIncomingValues(); i != e; ++i) {
Value *Incoming =
- StripPointerCastsAndObjCCalls(PN->getIncomingValue(i));
+ GetRCIdentityRoot(PN->getIncomingValue(i));
if (!IsNullOrUndef(Incoming)) {
CallInst *Clone = cast<CallInst>(CInst->clone());
Value *Op = PN->getIncomingValue(i);
switch (Class) {
case IC_Release: {
- Arg = GetObjCArg(Inst);
+ Arg = GetArgRCIdentityRoot(Inst);
PtrState &S = MyStates.getPtrBottomUpState(Arg);
break;
case IC_Retain:
case IC_RetainRV: {
- Arg = GetObjCArg(Inst);
+ Arg = GetArgRCIdentityRoot(Inst);
PtrState &S = MyStates.getPtrBottomUpState(Arg);
S.SetKnownPositiveRefCount();
if (StoreInst *SI = dyn_cast<StoreInst>(Inst)) {
if (AreAnyUnderlyingObjectsAnAlloca(SI->getPointerOperand())) {
BBState::ptr_iterator I = MyStates.findPtrBottomUpState(
- StripPointerCastsAndObjCCalls(SI->getValueOperand()));
+ GetRCIdentityRoot(SI->getValueOperand()));
if (I != MyStates.bottom_up_ptr_end())
MultiOwnersSet.insert(I->first);
}
break;
case IC_Retain:
case IC_RetainRV: {
- Arg = GetObjCArg(Inst);
+ Arg = GetArgRCIdentityRoot(Inst);
PtrState &S = MyStates.getPtrTopDownState(Arg);
break;
}
case IC_Release: {
- Arg = GetObjCArg(Inst);
+ Arg = GetArgRCIdentityRoot(Inst);
PtrState &S = MyStates.getPtrTopDownState(Arg);
S.ClearKnownPositiveRefCount();
const RRInfo &NewRetainRRI = It->second;
KnownSafeTD &= NewRetainRRI.KnownSafe;
MultipleOwners =
- MultipleOwners || MultiOwnersSet.count(GetObjCArg(NewRetain));
+ MultipleOwners || MultiOwnersSet.count(GetArgRCIdentityRoot(NewRetain));
for (Instruction *NewRetainRelease : NewRetainRRI.Calls) {
DenseMap<Value *, RRInfo>::const_iterator Jt =
Releases.find(NewRetainRelease);
DEBUG(dbgs() << "Visiting: " << *Retain << "\n");
- Value *Arg = GetObjCArg(Retain);
+ Value *Arg = GetArgRCIdentityRoot(Retain);
// If the object being released is in static or stack storage, we know it's
// not being managed by ObjC reference counting, so we can delete pairs
if (const LoadInst *LI = dyn_cast<LoadInst>(Arg))
if (const GlobalVariable *GV =
dyn_cast<GlobalVariable>(
- StripPointerCastsAndObjCCalls(LI->getPointerOperand())))
+ GetRCIdentityRoot(LI->getPointerOperand())))
if (GV->isConstant())
KnownSafe = true;
// Check that we found a retain with the same argument.
if (!Retain ||
!IsRetain(GetBasicInstructionClass(Retain)) ||
- GetObjCArg(Retain) != Arg) {
+ GetArgRCIdentityRoot(Retain) != Arg) {
return nullptr;
}
InstructionClass AutoreleaseClass = GetBasicInstructionClass(Autorelease);
if (!IsAutorelease(AutoreleaseClass))
return nullptr;
- if (GetObjCArg(Autorelease) != Arg)
+ if (GetArgRCIdentityRoot(Autorelease) != Arg)
return nullptr;
return Autorelease;
if (!Ret)
continue;
- const Value *Arg = StripPointerCastsAndObjCCalls(Ret->getOperand(0));
+ const Value *Arg = GetRCIdentityRoot(Ret->getOperand(0));
// Look for an ``autorelease'' instruction that is a predecessor of Ret and
// dependent on Arg such that there are no instructions dependent on Arg