#include "llvm/ADT/StringSwitch.h"
#include "llvm/Analysis/ValueTracking.h"
-#include "llvm/Intrinsics.h"
-#include "llvm/Module.h"
+#include "llvm/IR/Intrinsics.h"
+#include "llvm/IR/Module.h"
#include "llvm/Support/CallSite.h"
#include "llvm/Transforms/Utils/Local.h"
}
}
- DEBUG(dbgs() << "ObjCARCExpand: Finished Queue.\n\n");
+ DEBUG(dbgs() << "ObjCARCExpand: Finished List.\n\n");
return Changed;
}
//===----------------------------------------------------------------------===//
#include "llvm/ADT/STLExtras.h"
-#include "llvm/Constants.h"
+#include "llvm/IR/Constants.h"
namespace {
/// ObjCARCAPElim - Autorelease pool elimination.
// zap the pair.
if (Push && cast<CallInst>(Inst)->getArgOperand(0) == Push) {
Changed = true;
+ DEBUG(dbgs() << "ObjCARCAPElim::OptimizeBB: Zapping push pop autorelease pair:\n"
+ << " Pop: " << *Inst << "\n"
+ << " Push: " << *Push << "\n");
Inst->eraseFromParent();
Push->eraseFromParent();
}
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/Statistic.h"
-#include "llvm/LLVMContext.h"
+#include "llvm/IR/LLVMContext.h"
#include "llvm/Support/CFG.h"
STATISTIC(NumNoops, "Number of no-op objc calls eliminated");
// Turn it to an objc_retainAutoreleasedReturnValue..
Changed = true;
++NumPeeps;
+
+ DEBUG(dbgs() << "ObjCARCOpt::OptimizeRetainCall: Transforming "
+ "objc_retainAutoreleasedReturnValue => "
+ "objc_retain since the operand is not a return value.\n"
+ " Old: "
+ << *Retain << "\n");
+
cast<CallInst>(Retain)->setCalledFunction(getRetainRVCallee(F.getParent()));
+
+ DEBUG(dbgs() << " New: "
+ << *Retain << "\n");
}
/// OptimizeRetainRVCall - Turn objc_retainAutoreleasedReturnValue into
GetObjCArg(I) == Arg) {
Changed = true;
++NumPeeps;
+
+ DEBUG(dbgs() << "ObjCARCOpt::OptimizeRetainRVCall: Erasing " << *I << "\n"
+ << " Erasing " << *RetainRV
+ << "\n");
+
EraseInstruction(I);
EraseInstruction(RetainRV);
return true;
// Turn it to a plain objc_retain.
Changed = true;
++NumPeeps;
+
+ DEBUG(dbgs() << "ObjCARCOpt::OptimizeRetainRVCall: Transforming "
+ "objc_retainAutoreleasedReturnValue => "
+ "objc_retain since the operand is not a return value.\n"
+ " Old: "
+ << *RetainRV << "\n");
+
cast<CallInst>(RetainRV)->setCalledFunction(getRetainCallee(F.getParent()));
+
+ DEBUG(dbgs() << " New: "
+ << *RetainRV << "\n");
+
return false;
}
Changed = true;
++NumPeeps;
+
+ DEBUG(dbgs() << "ObjCARCOpt::OptimizeAutoreleaseRVCall: Transforming "
+ "objc_autoreleaseReturnValue => "
+ "objc_autorelease since its operand is not used as a return "
+ "value.\n"
+ " Old: "
+ << *AutoreleaseRV << "\n");
+
cast<CallInst>(AutoreleaseRV)->
setCalledFunction(getAutoreleaseCallee(F.getParent()));
+
+ DEBUG(dbgs() << " New: "
+ << *AutoreleaseRV << "\n");
+
}
/// OptimizeIndividualCalls - Visit each call, one at a time, and make
for (inst_iterator I = inst_begin(&F), E = inst_end(&F); I != E; ) {
Instruction *Inst = &*I++;
- DEBUG(dbgs() << "ObjCARCOpt: OptimizeIndividualCalls: Visiting: " <<
+ DEBUG(dbgs() << "ObjCARCOpt::OptimizeIndividualCalls: Visiting: " <<
*Inst << "\n");
InstructionClass Class = GetBasicInstructionClass(Inst);
case IC_NoopCast:
Changed = true;
++NumNoops;
+ DEBUG(dbgs() << "ObjCARCOpt::OptimizeIndividualCalls: Erasing no-op cast:"
+ " " << *Inst << "\n");
EraseInstruction(Inst);
continue;
new StoreInst(UndefValue::get(cast<PointerType>(Ty)->getElementType()),
Constant::getNullValue(Ty),
CI);
- CI->replaceAllUsesWith(UndefValue::get(CI->getType()));
+ llvm::Value *NewValue = UndefValue::get(CI->getType());
+ DEBUG(dbgs() << "ObjCARCOpt::OptimizeIndividualCalls: A null "
+ "pointer-to-weak-pointer is undefined behavior.\n"
+ " Old = " << *CI <<
+ "\n New = " <<
+ *NewValue << "\n");
+ CI->replaceAllUsesWith(NewValue);
CI->eraseFromParent();
continue;
}
new StoreInst(UndefValue::get(cast<PointerType>(Ty)->getElementType()),
Constant::getNullValue(Ty),
CI);
- CI->replaceAllUsesWith(UndefValue::get(CI->getType()));
+
+ llvm::Value *NewValue = UndefValue::get(CI->getType());
+ DEBUG(dbgs() << "ObjCARCOpt::OptimizeIndividualCalls: A null "
+ "pointer-to-weak-pointer is undefined behavior.\n"
+ " Old = " << *CI <<
+ "\n New = " <<
+ *NewValue << "\n");
+
+ CI->replaceAllUsesWith(NewValue);
CI->eraseFromParent();
continue;
}
Call->getArgOperand(0), "", Call);
NewCall->setMetadata(ImpreciseReleaseMDKind,
MDNode::get(C, ArrayRef<Value *>()));
+
+ DEBUG(dbgs() << "ObjCARCOpt::OptimizeIndividualCalls: Replacing "
+ "objc_autorelease(x) with objc_release(x) since x is "
+ "otherwise unused.\n"
+ " Old: " << *Call <<
+ "\n New: " <<
+ *NewCall << "\n");
+
EraseInstruction(Call);
Inst = NewCall;
Class = IC_Release;
// a tail keyword.
if (IsAlwaysTail(Class)) {
Changed = true;
+ DEBUG(dbgs() << "ObjCARCOpt::OptimizeIndividualCalls: Adding tail keyword"
+ " to function since it can never be passed stack args: " << *Inst <<
+ "\n");
cast<CallInst>(Inst)->setTailCall();
}
// Set nounwind as needed.
if (IsNoThrow(Class)) {
Changed = true;
+ DEBUG(dbgs() << "ObjCARCOpt::OptimizeIndividualCalls: Found no throw"
+ " class. Setting nounwind on: " << *Inst << "\n");
cast<CallInst>(Inst)->setDoesNotThrow();
}
if (isNullOrUndef(Arg)) {
Changed = true;
++NumNoops;
+ DEBUG(dbgs() << "ObjCARCOpt::OptimizeIndividualCalls: ARC calls with "
+ " null are no-ops. Erasing: " << *Inst << "\n");
EraseInstruction(Inst);
continue;
}
}
} while (!Worklist.empty());
- DEBUG(dbgs() << "ObjCARCOpt: Finished Individual Call Queue.\n\n");
+ DEBUG(dbgs() << "ObjCARCOpt::OptimizeIndividualCalls: Finished Queue.\n\n");
}
}
for (inst_iterator I = inst_begin(&F), E = inst_end(&F); I != E; ) {
Instruction *Inst = &*I++;
- DEBUG(dbgs() << "ObjCARCOpt: OptimizeWeakCalls: Visiting: " << *Inst <<
+ DEBUG(dbgs() << "ObjCARCOpt::OptimizeWeakCalls: Visiting: " << *Inst <<
"\n");
InstructionClass Class = GetBasicInstructionClass(Inst);
}
}
- DEBUG(dbgs() << "ObjCARCOpt: Finished visiting weak calls.\n\n");
+ DEBUG(dbgs() << "ObjCARCOpt::OptimizeWeakCalls: Finished List.\n\n");
}
BasicBlock *BB = FI;
ReturnInst *Ret = dyn_cast<ReturnInst>(&BB->back());
- DEBUG(dbgs() << "ObjCARCOpt: OptimizeReturns: Visiting: " << *Ret << "\n");
+ DEBUG(dbgs() << "ObjCARCOpt::OptimizeReturns: Visiting: " << *Ret << "\n");
if (!Ret) continue;
Visited.clear();
}
- DEBUG(dbgs() << "ObjCARCOpt: OptimizeReturns: Finished visiting returns.\n\n");
+ DEBUG(dbgs() << "ObjCARCOpt::OptimizeReturns: Finished List.\n\n");
}
// dominated by single calls.
#include "llvm/Analysis/Dominators.h"
-#include "llvm/InlineAsm.h"
-#include "llvm/Operator.h"
+#include "llvm/IR/InlineAsm.h"
+#include "llvm/IR/Operator.h"
STATISTIC(NumStoreStrongs, "Number objc_storeStrong calls formed");
} while (isNoopInstruction(BBI));
if (&*BBI == GetObjCArg(Inst)) {
+ DEBUG(dbgs() << "ObjCARCContract: Adding inline asm marker for "
+ "retainAutoreleasedReturnValue optimization.\n");
Changed = true;
InlineAsm *IA =
InlineAsm::get(FunctionType::get(Type::getVoidTy(Inst->getContext()),
ConstantPointerNull::get(cast<PointerType>(CI->getType()));
Changed = true;
new StoreInst(Null, CI->getArgOperand(0), CI);
+
+ DEBUG(dbgs() << "OBJCARCContract: Old = " << *CI << "\n"
+ << " New = " << *Null << "\n");
+
CI->replaceAllUsesWith(Null);
CI->eraseFromParent();
}
continue;
}
- DEBUG(dbgs() << "ObjCARCContract: Finished Queue.\n\n");
+ DEBUG(dbgs() << "ObjCARCContract: Finished List.\n\n");
// 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*.