mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-07-17 18:24:34 +00:00
[objc-arc-contract] Refactor out tryToPeepholeInstruction into its own method. NFC.
The main method of ObjCARCContract is really large and busy. By refactoring this out, it becomes easier to reason about. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@229794 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
@@ -72,6 +72,13 @@ namespace {
|
|||||||
/// "tail".
|
/// "tail".
|
||||||
SmallPtrSet<CallInst *, 8> StoreStrongCalls;
|
SmallPtrSet<CallInst *, 8> StoreStrongCalls;
|
||||||
|
|
||||||
|
/// Returns true if we eliminated Inst.
|
||||||
|
bool tryToPeepholeInstruction(Function &F, Instruction *Inst,
|
||||||
|
inst_iterator &Iter,
|
||||||
|
SmallPtrSetImpl<Instruction *> &DepInsts,
|
||||||
|
SmallPtrSetImpl<const BasicBlock *> &Visited,
|
||||||
|
bool &TailOkForStoreStrong);
|
||||||
|
|
||||||
bool optimizeRetainCall(Function &F, Instruction *Retain);
|
bool optimizeRetainCall(Function &F, Instruction *Retain);
|
||||||
|
|
||||||
bool
|
bool
|
||||||
@@ -169,18 +176,16 @@ bool ObjCARCContract::contractAutorelease(
|
|||||||
Changed = true;
|
Changed = true;
|
||||||
++NumPeeps;
|
++NumPeeps;
|
||||||
|
|
||||||
DEBUG(dbgs() << "ObjCARCContract::ContractAutorelease: Fusing "
|
DEBUG(dbgs() << " Fusing retain/autorelease!\n"
|
||||||
"retain/autorelease. Erasing: " << *Autorelease << "\n"
|
" Autorelease:" << *Autorelease << "\n"
|
||||||
" Old Retain: "
|
" Retain: " << *Retain << "\n");
|
||||||
<< *Retain << "\n");
|
|
||||||
|
|
||||||
Constant *Decl = EP.get(Class == IC_AutoreleaseRV ?
|
Constant *Decl = EP.get(Class == IC_AutoreleaseRV ?
|
||||||
ARCRuntimeEntryPoints::EPT_RetainAutoreleaseRV :
|
ARCRuntimeEntryPoints::EPT_RetainAutoreleaseRV :
|
||||||
ARCRuntimeEntryPoints::EPT_RetainAutorelease);
|
ARCRuntimeEntryPoints::EPT_RetainAutorelease);
|
||||||
Retain->setCalledFunction(Decl);
|
Retain->setCalledFunction(Decl);
|
||||||
|
|
||||||
DEBUG(dbgs() << " New Retain: "
|
DEBUG(dbgs() << " New RetainAutorelease: " << *Retain << "\n");
|
||||||
<< *Retain << "\n");
|
|
||||||
|
|
||||||
EraseInstruction(Autorelease);
|
EraseInstruction(Autorelease);
|
||||||
return true;
|
return true;
|
||||||
@@ -249,6 +254,14 @@ void ObjCARCContract::contractRelease(Instruction *Release,
|
|||||||
Changed = true;
|
Changed = true;
|
||||||
++NumStoreStrongs;
|
++NumStoreStrongs;
|
||||||
|
|
||||||
|
DEBUG(
|
||||||
|
llvm::dbgs() << " Contracting retain, release into objc_storeStrong.\n"
|
||||||
|
<< " Old:\n"
|
||||||
|
<< " Store: " << *Store << "\n"
|
||||||
|
<< " Release: " << *Release << "\n"
|
||||||
|
<< " Retain: " << *Retain << "\n"
|
||||||
|
<< " Load: " << *Load << "\n");
|
||||||
|
|
||||||
LLVMContext &C = Release->getContext();
|
LLVMContext &C = Release->getContext();
|
||||||
Type *I8X = PointerType::getUnqual(Type::getInt8Ty(C));
|
Type *I8X = PointerType::getUnqual(Type::getInt8Ty(C));
|
||||||
Type *I8XX = PointerType::getUnqual(I8X);
|
Type *I8XX = PointerType::getUnqual(I8X);
|
||||||
@@ -268,6 +281,8 @@ void ObjCARCContract::contractRelease(Instruction *Release,
|
|||||||
// we can set the tail flag once we know it's safe.
|
// we can set the tail flag once we know it's safe.
|
||||||
StoreStrongCalls.insert(StoreStrong);
|
StoreStrongCalls.insert(StoreStrong);
|
||||||
|
|
||||||
|
DEBUG(llvm::dbgs() << " New Store Strong: " << *StoreStrong << "\n");
|
||||||
|
|
||||||
if (&*Iter == Store) ++Iter;
|
if (&*Iter == Store) ++Iter;
|
||||||
Store->eraseFromParent();
|
Store->eraseFromParent();
|
||||||
Release->eraseFromParent();
|
Release->eraseFromParent();
|
||||||
@@ -276,61 +291,26 @@ void ObjCARCContract::contractRelease(Instruction *Release,
|
|||||||
Load->eraseFromParent();
|
Load->eraseFromParent();
|
||||||
}
|
}
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
bool ObjCARCContract::tryToPeepholeInstruction(
|
||||||
// Top Level Driver
|
Function &F, Instruction *Inst, inst_iterator &Iter,
|
||||||
//===----------------------------------------------------------------------===//
|
SmallPtrSetImpl<Instruction *> &DependingInsts,
|
||||||
|
SmallPtrSetImpl<const BasicBlock *> &Visited,
|
||||||
bool ObjCARCContract::runOnFunction(Function &F) {
|
bool &TailOkForStoreStrongs) {
|
||||||
if (!EnableARCOpts)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// If nothing in the Module uses ARC, don't do anything.
|
|
||||||
if (!Run)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
Changed = false;
|
|
||||||
AA = &getAnalysis<AliasAnalysis>();
|
|
||||||
DT = &getAnalysis<DominatorTreeWrapperPass>().getDomTree();
|
|
||||||
|
|
||||||
PA.setAA(&getAnalysis<AliasAnalysis>());
|
|
||||||
|
|
||||||
DEBUG(llvm::dbgs() << "**** ObjCARC Contract ****\n");
|
|
||||||
|
|
||||||
// Track whether it's ok to mark objc_storeStrong calls with the "tail"
|
|
||||||
// keyword. Be conservative if the function has variadic arguments.
|
|
||||||
// It seems that functions which "return twice" are also unsafe for the
|
|
||||||
// "tail" argument, because they are setjmp, which could need to
|
|
||||||
// return to an earlier stack state.
|
|
||||||
bool TailOkForStoreStrongs = !F.isVarArg() &&
|
|
||||||
!F.callsFunctionThatReturnsTwice();
|
|
||||||
|
|
||||||
// For ObjC library calls which return their argument, replace uses of the
|
|
||||||
// argument with uses of the call return value, if it dominates the use. This
|
|
||||||
// reduces register pressure.
|
|
||||||
SmallPtrSet<Instruction *, 4> DependingInstructions;
|
|
||||||
SmallPtrSet<const BasicBlock *, 4> Visited;
|
|
||||||
for (inst_iterator I = inst_begin(&F), E = inst_end(&F); I != E; ) {
|
|
||||||
Instruction *Inst = &*I++;
|
|
||||||
|
|
||||||
DEBUG(dbgs() << "Visiting: " << *Inst << "\n");
|
|
||||||
|
|
||||||
// Only these library routines return their argument. In particular,
|
// Only these library routines return their argument. In particular,
|
||||||
// objc_retainBlock does not necessarily return its argument.
|
// objc_retainBlock does not necessarily return its argument.
|
||||||
InstructionClass Class = GetBasicInstructionClass(Inst);
|
InstructionClass Class = GetBasicInstructionClass(Inst);
|
||||||
switch (Class) {
|
switch (Class) {
|
||||||
case IC_FusedRetainAutorelease:
|
case IC_FusedRetainAutorelease:
|
||||||
case IC_FusedRetainAutoreleaseRV:
|
case IC_FusedRetainAutoreleaseRV:
|
||||||
break;
|
return false;
|
||||||
case IC_Autorelease:
|
case IC_Autorelease:
|
||||||
case IC_AutoreleaseRV:
|
case IC_AutoreleaseRV:
|
||||||
if (contractAutorelease(F, Inst, Class, DependingInstructions, Visited))
|
return contractAutorelease(F, Inst, Class, DependingInsts, Visited);
|
||||||
continue;
|
|
||||||
break;
|
|
||||||
case IC_Retain:
|
case IC_Retain:
|
||||||
// Attempt to convert retains to retainrvs if they are next to function
|
// Attempt to convert retains to retainrvs if they are next to function
|
||||||
// calls.
|
// calls.
|
||||||
if (!optimizeRetainCall(F, Inst))
|
if (!optimizeRetainCall(F, Inst))
|
||||||
break;
|
return false;
|
||||||
// If we succeed in our optimization, fall through.
|
// If we succeed in our optimization, fall through.
|
||||||
// FALLTHROUGH
|
// FALLTHROUGH
|
||||||
case IC_RetainRV: {
|
case IC_RetainRV: {
|
||||||
@@ -338,7 +318,7 @@ bool ObjCARCContract::runOnFunction(Function &F) {
|
|||||||
// marker to do the retainAutoreleasedReturnValue optimization,
|
// marker to do the retainAutoreleasedReturnValue optimization,
|
||||||
// insert it now.
|
// insert it now.
|
||||||
if (!RetainRVMarker)
|
if (!RetainRVMarker)
|
||||||
break;
|
return false;
|
||||||
BasicBlock::iterator BBI = Inst;
|
BasicBlock::iterator BBI = Inst;
|
||||||
BasicBlock *InstParent = Inst->getParent();
|
BasicBlock *InstParent = Inst->getParent();
|
||||||
|
|
||||||
@@ -368,7 +348,7 @@ bool ObjCARCContract::runOnFunction(Function &F) {
|
|||||||
CallInst::Create(IA, "", Inst);
|
CallInst::Create(IA, "", Inst);
|
||||||
}
|
}
|
||||||
decline_rv_optimization:
|
decline_rv_optimization:
|
||||||
break;
|
return false;
|
||||||
}
|
}
|
||||||
case IC_InitWeak: {
|
case IC_InitWeak: {
|
||||||
// objc_initWeak(p, null) => *p = null
|
// objc_initWeak(p, null) => *p = null
|
||||||
@@ -385,31 +365,78 @@ bool ObjCARCContract::runOnFunction(Function &F) {
|
|||||||
CI->replaceAllUsesWith(Null);
|
CI->replaceAllUsesWith(Null);
|
||||||
CI->eraseFromParent();
|
CI->eraseFromParent();
|
||||||
}
|
}
|
||||||
continue;
|
return true;
|
||||||
}
|
}
|
||||||
case IC_Release:
|
case IC_Release:
|
||||||
contractRelease(Inst, I);
|
contractRelease(Inst, Iter);
|
||||||
continue;
|
return true;
|
||||||
case IC_User:
|
case IC_User:
|
||||||
// Be conservative if the function has any alloca instructions.
|
// Be conservative if the function has any alloca instructions.
|
||||||
// Technically we only care about escaping alloca instructions,
|
// Technically we only care about escaping alloca instructions,
|
||||||
// but this is sufficient to handle some interesting cases.
|
// but this is sufficient to handle some interesting cases.
|
||||||
if (isa<AllocaInst>(Inst))
|
if (isa<AllocaInst>(Inst))
|
||||||
TailOkForStoreStrongs = false;
|
TailOkForStoreStrongs = false;
|
||||||
continue;
|
return true;
|
||||||
case IC_IntrinsicUser:
|
case IC_IntrinsicUser:
|
||||||
// Remove calls to @clang.arc.use(...).
|
// Remove calls to @clang.arc.use(...).
|
||||||
Inst->eraseFromParent();
|
Inst->eraseFromParent();
|
||||||
continue;
|
return true;
|
||||||
default:
|
default:
|
||||||
continue;
|
return true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
DEBUG(dbgs() << "Finished List.\n\n");
|
//===----------------------------------------------------------------------===//
|
||||||
|
// Top Level Driver
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
bool ObjCARCContract::runOnFunction(Function &F) {
|
||||||
|
if (!EnableARCOpts)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// If nothing in the Module uses ARC, don't do anything.
|
||||||
|
if (!Run)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Changed = false;
|
||||||
|
AA = &getAnalysis<AliasAnalysis>();
|
||||||
|
DT = &getAnalysis<DominatorTreeWrapperPass>().getDomTree();
|
||||||
|
|
||||||
|
PA.setAA(&getAnalysis<AliasAnalysis>());
|
||||||
|
|
||||||
|
DEBUG(llvm::dbgs() << "**** ObjCARC Contract ****\n");
|
||||||
|
|
||||||
|
// Track whether it's ok to mark objc_storeStrong calls with the "tail"
|
||||||
|
// keyword. Be conservative if the function has variadic arguments.
|
||||||
|
// It seems that functions which "return twice" are also unsafe for the
|
||||||
|
// "tail" argument, because they are setjmp, which could need to
|
||||||
|
// return to an earlier stack state.
|
||||||
|
bool TailOkForStoreStrongs =
|
||||||
|
!F.isVarArg() && !F.callsFunctionThatReturnsTwice();
|
||||||
|
|
||||||
|
// For ObjC library calls which return their argument, replace uses of the
|
||||||
|
// argument with uses of the call return value, if it dominates the use. This
|
||||||
|
// reduces register pressure.
|
||||||
|
SmallPtrSet<Instruction *, 4> DependingInstructions;
|
||||||
|
SmallPtrSet<const BasicBlock *, 4> Visited;
|
||||||
|
for (inst_iterator I = inst_begin(&F), E = inst_end(&F); I != E;) {
|
||||||
|
Instruction *Inst = &*I++;
|
||||||
|
|
||||||
|
DEBUG(dbgs() << "Visiting: " << *Inst << "\n");
|
||||||
|
|
||||||
|
// First try to peephole Inst. If there is nothing further we can do in
|
||||||
|
// terms of undoing objc-arc-expand, process the next inst.
|
||||||
|
if (tryToPeepholeInstruction(F, Inst, I, DependingInstructions, Visited,
|
||||||
|
TailOkForStoreStrongs))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Otherwise, try to undo objc-arc-expand.
|
||||||
|
|
||||||
// Don't use GetObjCArg because we don't want to look through bitcasts
|
// Don't use GetObjCArg because we don't want to look through bitcasts
|
||||||
// and such; to do the replacement, the argument must have type i8*.
|
// and such; to do the replacement, the argument must have type i8*.
|
||||||
Value *Arg = cast<CallInst>(Inst)->getArgOperand(0);
|
Value *Arg = cast<CallInst>(Inst)->getArgOperand(0);
|
||||||
|
|
||||||
|
// TODO: Change this to a do-while.
|
||||||
for (;;) {
|
for (;;) {
|
||||||
// If we're compiling bugpointed code, don't get in trouble.
|
// If we're compiling bugpointed code, don't get in trouble.
|
||||||
if (!isa<Instruction>(Arg) && !isa<Argument>(Arg))
|
if (!isa<Instruction>(Arg) && !isa<Argument>(Arg))
|
||||||
|
Reference in New Issue
Block a user