forked from OSchip/llvm-project
Add a new ObjC ARC optimization pass to eliminate unneeded
autorelease push+pop pairs. llvm-svn: 148330
This commit is contained in:
parent
b9936296d3
commit
e7a243fea5
|
@ -168,6 +168,7 @@ void initializeNoAAPass(PassRegistry&);
|
||||||
void initializeNoProfileInfoPass(PassRegistry&);
|
void initializeNoProfileInfoPass(PassRegistry&);
|
||||||
void initializeNoPathProfileInfoPass(PassRegistry&);
|
void initializeNoPathProfileInfoPass(PassRegistry&);
|
||||||
void initializeObjCARCAliasAnalysisPass(PassRegistry&);
|
void initializeObjCARCAliasAnalysisPass(PassRegistry&);
|
||||||
|
void initializeObjCARCAPElimPass(PassRegistry&);
|
||||||
void initializeObjCARCExpandPass(PassRegistry&);
|
void initializeObjCARCExpandPass(PassRegistry&);
|
||||||
void initializeObjCARCContractPass(PassRegistry&);
|
void initializeObjCARCContractPass(PassRegistry&);
|
||||||
void initializeObjCARCOptPass(PassRegistry&);
|
void initializeObjCARCOptPass(PassRegistry&);
|
||||||
|
|
|
@ -97,6 +97,7 @@ namespace {
|
||||||
(void) llvm::createNoAAPass();
|
(void) llvm::createNoAAPass();
|
||||||
(void) llvm::createNoProfileInfoPass();
|
(void) llvm::createNoProfileInfoPass();
|
||||||
(void) llvm::createObjCARCAliasAnalysisPass();
|
(void) llvm::createObjCARCAliasAnalysisPass();
|
||||||
|
(void) llvm::createObjCARCAPElimPass();
|
||||||
(void) llvm::createObjCARCExpandPass();
|
(void) llvm::createObjCARCExpandPass();
|
||||||
(void) llvm::createObjCARCContractPass();
|
(void) llvm::createObjCARCContractPass();
|
||||||
(void) llvm::createObjCARCOptPass();
|
(void) llvm::createObjCARCOptPass();
|
||||||
|
|
|
@ -325,6 +325,12 @@ Pass *createLowerAtomicPass();
|
||||||
//
|
//
|
||||||
Pass *createCorrelatedValuePropagationPass();
|
Pass *createCorrelatedValuePropagationPass();
|
||||||
|
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
//
|
||||||
|
// ObjCARCAPElim - ObjC ARC autorelease pool elimination.
|
||||||
|
//
|
||||||
|
Pass *createObjCARCAPElimPass();
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
//
|
//
|
||||||
// ObjCARCExpand - ObjC ARC preliminary simplifications.
|
// ObjCARCExpand - ObjC ARC preliminary simplifications.
|
||||||
|
|
|
@ -375,7 +375,7 @@ static InstructionClass GetBasicInstructionClass(const Value *V) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Otherwise, be conservative.
|
// Otherwise, be conservative.
|
||||||
return IC_User;
|
return isa<InvokeInst>(V) ? IC_CallOrUser : IC_User;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// IsRetain - Test if the the given class is objc_retain or
|
/// IsRetain - Test if the the given class is objc_retain or
|
||||||
|
@ -883,6 +883,122 @@ bool ObjCARCExpand::runOnFunction(Function &F) {
|
||||||
return Changed;
|
return Changed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
// ARC autorelease pool elimination.
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
/// ObjCARCAPElim - Autorelease pool elimination.
|
||||||
|
class ObjCARCAPElim : public ModulePass {
|
||||||
|
virtual void getAnalysisUsage(AnalysisUsage &AU) const;
|
||||||
|
virtual bool runOnModule(Module &M);
|
||||||
|
|
||||||
|
bool MayAutorelease(CallSite CS);
|
||||||
|
bool OptimizeBB(BasicBlock *BB);
|
||||||
|
|
||||||
|
public:
|
||||||
|
static char ID;
|
||||||
|
ObjCARCAPElim() : ModulePass(ID) {
|
||||||
|
initializeObjCARCAPElimPass(*PassRegistry::getPassRegistry());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
char ObjCARCAPElim::ID = 0;
|
||||||
|
INITIALIZE_PASS(ObjCARCAPElim,
|
||||||
|
"objc-arc-apelim",
|
||||||
|
"ObjC ARC autorelease pool elimination",
|
||||||
|
false, false)
|
||||||
|
|
||||||
|
Pass *llvm::createObjCARCAPElimPass() {
|
||||||
|
return new ObjCARCAPElim();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ObjCARCAPElim::getAnalysisUsage(AnalysisUsage &AU) const {
|
||||||
|
AU.setPreservesCFG();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// MayAutorelease - Interprocedurally determine if calls made by the
|
||||||
|
/// given call site can possibly produce autoreleases.
|
||||||
|
bool ObjCARCAPElim::MayAutorelease(CallSite CS) {
|
||||||
|
if (Function *Callee = CS.getCalledFunction()) {
|
||||||
|
if (Callee->isDeclaration() || Callee->mayBeOverridden())
|
||||||
|
return true;
|
||||||
|
for (Function::iterator I = Callee->begin(), E = Callee->end();
|
||||||
|
I != E; ++I) {
|
||||||
|
BasicBlock *BB = I;
|
||||||
|
for (BasicBlock::iterator J = BB->begin(), F = BB->end(); J != F; ++J)
|
||||||
|
if (CallSite JCS = CallSite(J))
|
||||||
|
if (!JCS.onlyReadsMemory() && MayAutorelease(JCS))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ObjCARCAPElim::OptimizeBB(BasicBlock *BB) {
|
||||||
|
bool Changed = false;
|
||||||
|
|
||||||
|
Instruction *Push = 0;
|
||||||
|
for (BasicBlock::iterator I = BB->begin(), E = BB->end(); I != E; ) {
|
||||||
|
Instruction *Inst = I++;
|
||||||
|
switch (GetBasicInstructionClass(Inst)) {
|
||||||
|
case IC_AutoreleasepoolPush:
|
||||||
|
Push = Inst;
|
||||||
|
break;
|
||||||
|
case IC_AutoreleasepoolPop:
|
||||||
|
// If this pop matches a push and nothing in between can autorelease,
|
||||||
|
// zap the pair.
|
||||||
|
if (Push && cast<CallInst>(Inst)->getArgOperand(0) == Push) {
|
||||||
|
Changed = true;
|
||||||
|
Inst->eraseFromParent();
|
||||||
|
Push->eraseFromParent();
|
||||||
|
}
|
||||||
|
Push = 0;
|
||||||
|
break;
|
||||||
|
case IC_CallOrUser:
|
||||||
|
if (MayAutorelease(CallSite(Inst)))
|
||||||
|
Push = 0;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Changed;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ObjCARCAPElim::runOnModule(Module &M) {
|
||||||
|
if (!EnableARCOpts)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// If nothing in the Module uses ARC, don't do anything.
|
||||||
|
if (!ModuleHasARC(M))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
bool Changed = false;
|
||||||
|
|
||||||
|
for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I) {
|
||||||
|
Function *F = I;
|
||||||
|
// Only look at function definitions.
|
||||||
|
if (F->isDeclaration())
|
||||||
|
continue;
|
||||||
|
// Only look at global constructor functions. Unfortunately,
|
||||||
|
// the name is the most convenient way to recognize them.
|
||||||
|
if (!F->getName().startswith("_GLOBAL__I_"))
|
||||||
|
continue;
|
||||||
|
// Only look at functions with one basic block.
|
||||||
|
if (llvm::next(F->begin()) != F->end())
|
||||||
|
continue;
|
||||||
|
// Ok, a single-block constructor function definition. Try to optimize it.
|
||||||
|
Changed |= OptimizeBB(F->begin());
|
||||||
|
}
|
||||||
|
|
||||||
|
return Changed;
|
||||||
|
}
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
// ARC optimization.
|
// ARC optimization.
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
|
@ -51,6 +51,7 @@ void llvm::initializeScalarOpts(PassRegistry &Registry) {
|
||||||
initializeLowerExpectIntrinsicPass(Registry);
|
initializeLowerExpectIntrinsicPass(Registry);
|
||||||
initializeMemCpyOptPass(Registry);
|
initializeMemCpyOptPass(Registry);
|
||||||
initializeObjCARCAliasAnalysisPass(Registry);
|
initializeObjCARCAliasAnalysisPass(Registry);
|
||||||
|
initializeObjCARCAPElimPass(Registry);
|
||||||
initializeObjCARCExpandPass(Registry);
|
initializeObjCARCExpandPass(Registry);
|
||||||
initializeObjCARCContractPass(Registry);
|
initializeObjCARCContractPass(Registry);
|
||||||
initializeObjCARCOptPass(Registry);
|
initializeObjCARCOptPass(Registry);
|
||||||
|
|
|
@ -0,0 +1,51 @@
|
||||||
|
; RUN: opt -S -objc-arc-apelim < %s | FileCheck %s
|
||||||
|
; rdar://10227311
|
||||||
|
|
||||||
|
@x = global i32 0
|
||||||
|
|
||||||
|
declare i32 @bar() nounwind
|
||||||
|
|
||||||
|
define i32 @foo() nounwind {
|
||||||
|
entry:
|
||||||
|
ret i32 5
|
||||||
|
}
|
||||||
|
|
||||||
|
define internal void @__cxx_global_var_init() {
|
||||||
|
entry:
|
||||||
|
%call = call i32 @foo()
|
||||||
|
store i32 %call, i32* @x, align 4
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
|
define internal void @__dxx_global_var_init() {
|
||||||
|
entry:
|
||||||
|
%call = call i32 @bar()
|
||||||
|
store i32 %call, i32* @x, align 4
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
|
; CHECK: define internal void @_GLOBAL__I_x()
|
||||||
|
; CHECK-NOT: @objc
|
||||||
|
; CHECK: }
|
||||||
|
define internal void @_GLOBAL__I_x() {
|
||||||
|
entry:
|
||||||
|
%0 = call i8* @objc_autoreleasePoolPush() nounwind
|
||||||
|
call void @__cxx_global_var_init()
|
||||||
|
call void @objc_autoreleasePoolPop(i8* %0) nounwind
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
|
; CHECK: define internal void @_GLOBAL__I_y()
|
||||||
|
; CHECK: %0 = call i8* @objc_autoreleasePoolPush() nounwind
|
||||||
|
; CHECK: call void @objc_autoreleasePoolPop(i8* %0) nounwind
|
||||||
|
; CHECK: }
|
||||||
|
define internal void @_GLOBAL__I_y() {
|
||||||
|
entry:
|
||||||
|
%0 = call i8* @objc_autoreleasePoolPush() nounwind
|
||||||
|
call void @__dxx_global_var_init()
|
||||||
|
call void @objc_autoreleasePoolPop(i8* %0) nounwind
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
|
declare i8* @objc_autoreleasePoolPush()
|
||||||
|
declare void @objc_autoreleasePoolPop(i8*)
|
Loading…
Reference in New Issue