#ifndef LLVM_LIB_TRANSFORMS_OBJCARC_OBJCARC_H
#define LLVM_LIB_TRANSFORMS_OBJCARC_OBJCARC_H
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Analysis/AliasAnalysis.h"
#include "llvm/Analysis/Passes.h"
#include "llvm/Analysis/ValueTracking.h"
#include "llvm/IR/CallSite.h"
#include "llvm/IR/InstIterator.h"
#include "llvm/IR/Module.h"
#include "llvm/Pass.h"
#include "llvm/Transforms/ObjCARC.h"
#include "llvm/Transforms/Utils/Local.h"
namespace llvm {
class raw_ostream;
}
namespace llvm {
namespace objcarc {
extern bool EnableARCOpts;
static inline bool ModuleHasARC(const Module &M) {
return
M.getNamedValue("objc_retain") ||
M.getNamedValue("objc_release") ||
M.getNamedValue("objc_autorelease") ||
M.getNamedValue("objc_retainAutoreleasedReturnValue") ||
M.getNamedValue("objc_retainBlock") ||
M.getNamedValue("objc_autoreleaseReturnValue") ||
M.getNamedValue("objc_autoreleasePoolPush") ||
M.getNamedValue("objc_loadWeakRetained") ||
M.getNamedValue("objc_loadWeak") ||
M.getNamedValue("objc_destroyWeak") ||
M.getNamedValue("objc_storeWeak") ||
M.getNamedValue("objc_initWeak") ||
M.getNamedValue("objc_moveWeak") ||
M.getNamedValue("objc_copyWeak") ||
M.getNamedValue("objc_retainedObject") ||
M.getNamedValue("objc_unretainedObject") ||
M.getNamedValue("objc_unretainedPointer") ||
M.getNamedValue("clang.arc.use");
}
enum InstructionClass {
IC_Retain, IC_RetainRV, IC_RetainBlock, IC_Release, IC_Autorelease, IC_AutoreleaseRV, IC_AutoreleasepoolPush, IC_AutoreleasepoolPop, IC_NoopCast, IC_FusedRetainAutorelease, IC_FusedRetainAutoreleaseRV, IC_LoadWeakRetained, IC_StoreWeak, IC_InitWeak, IC_LoadWeak, IC_MoveWeak, IC_CopyWeak, IC_DestroyWeak, IC_StoreStrong, IC_IntrinsicUser, IC_CallOrUser, IC_Call, IC_User, IC_None };
raw_ostream &operator<<(raw_ostream &OS, const InstructionClass Class);
inline static bool IsUser(InstructionClass Class) {
return Class == IC_User ||
Class == IC_CallOrUser ||
Class == IC_IntrinsicUser;
}
static inline bool IsRetain(InstructionClass Class) {
return Class == IC_Retain ||
Class == IC_RetainRV;
}
static inline bool IsAutorelease(InstructionClass Class) {
return Class == IC_Autorelease ||
Class == IC_AutoreleaseRV;
}
static inline bool IsForwarding(InstructionClass Class) {
return Class == IC_Retain ||
Class == IC_RetainRV ||
Class == IC_Autorelease ||
Class == IC_AutoreleaseRV ||
Class == IC_NoopCast;
}
static inline bool IsNoopOnNull(InstructionClass Class) {
return Class == IC_Retain ||
Class == IC_RetainRV ||
Class == IC_Release ||
Class == IC_Autorelease ||
Class == IC_AutoreleaseRV ||
Class == IC_RetainBlock;
}
static inline bool IsAlwaysTail(InstructionClass Class) {
return Class == IC_Retain ||
Class == IC_RetainRV ||
Class == IC_AutoreleaseRV;
}
static inline bool IsNeverTail(InstructionClass Class) {
return Class == IC_Autorelease;
}
static inline bool IsNoThrow(InstructionClass Class) {
return Class == IC_Retain ||
Class == IC_RetainRV ||
Class == IC_Release ||
Class == IC_Autorelease ||
Class == IC_AutoreleaseRV ||
Class == IC_AutoreleasepoolPush ||
Class == IC_AutoreleasepoolPop;
}
static inline bool
CanInterruptRV(InstructionClass Class) {
switch (Class) {
case IC_AutoreleasepoolPop:
case IC_CallOrUser:
case IC_Call:
case IC_Autorelease:
case IC_AutoreleaseRV:
case IC_FusedRetainAutorelease:
case IC_FusedRetainAutoreleaseRV:
return true;
default:
return false;
}
}
InstructionClass GetFunctionClass(const Function *F);
static inline InstructionClass GetBasicInstructionClass(const Value *V) {
if (const CallInst *CI = dyn_cast<CallInst>(V)) {
if (const Function *F = CI->getCalledFunction())
return GetFunctionClass(F);
return IC_CallOrUser;
}
return isa<InvokeInst>(V) ? IC_CallOrUser : IC_User;
}
InstructionClass GetInstructionClass(const Value *V);
static inline const Value *GetUnderlyingObjCPtr(const Value *V) {
for (;;) {
V = GetUnderlyingObject(V);
if (!IsForwarding(GetBasicInstructionClass(V)))
break;
V = cast<CallInst>(V)->getArgOperand(0);
}
return V;
}
static inline const Value *StripPointerCastsAndObjCCalls(const Value *V) {
for (;;) {
V = V->stripPointerCasts();
if (!IsForwarding(GetBasicInstructionClass(V)))
break;
V = cast<CallInst>(V)->getArgOperand(0);
}
return V;
}
static inline Value *StripPointerCastsAndObjCCalls(Value *V) {
for (;;) {
V = V->stripPointerCasts();
if (!IsForwarding(GetBasicInstructionClass(V)))
break;
V = cast<CallInst>(V)->getArgOperand(0);
}
return V;
}
static inline Value *GetObjCArg(Value *Inst) {
return StripPointerCastsAndObjCCalls(cast<CallInst>(Inst)->getArgOperand(0));
}
static inline bool IsNullOrUndef(const Value *V) {
return isa<ConstantPointerNull>(V) || isa<UndefValue>(V);
}
static inline bool IsNoopInstruction(const Instruction *I) {
return isa<BitCastInst>(I) ||
(isa<GetElementPtrInst>(I) &&
cast<GetElementPtrInst>(I)->hasAllZeroIndices());
}
static inline void EraseInstruction(Instruction *CI) {
Value *OldArg = cast<CallInst>(CI)->getArgOperand(0);
bool Unused = CI->use_empty();
if (!Unused) {
assert((IsForwarding(GetBasicInstructionClass(CI)) ||
(IsNoopOnNull(GetBasicInstructionClass(CI)) &&
isa<ConstantPointerNull>(OldArg))) &&
"Can't delete non-forwarding instruction with users!");
CI->replaceAllUsesWith(OldArg);
}
CI->eraseFromParent();
if (Unused)
RecursivelyDeleteTriviallyDeadInstructions(OldArg);
}
static inline bool IsPotentialRetainableObjPtr(const Value *Op) {
if (isa<Constant>(Op) || isa<AllocaInst>(Op))
return false;
if (const Argument *Arg = dyn_cast<Argument>(Op))
if (Arg->hasByValAttr() ||
Arg->hasInAllocaAttr() ||
Arg->hasNestAttr() ||
Arg->hasStructRetAttr())
return false;
PointerType *Ty = dyn_cast<PointerType>(Op->getType());
if (!Ty)
return false;
return true;
}
static inline bool IsPotentialRetainableObjPtr(const Value *Op,
AliasAnalysis &AA) {
if (!IsPotentialRetainableObjPtr(Op))
return false;
if (AA.pointsToConstantMemory(Op))
return false;
if (const LoadInst *LI = dyn_cast<LoadInst>(Op))
if (AA.pointsToConstantMemory(LI->getPointerOperand()))
return false;
return true;
}
static inline InstructionClass GetCallSiteClass(ImmutableCallSite CS) {
for (ImmutableCallSite::arg_iterator I = CS.arg_begin(), E = CS.arg_end();
I != E; ++I)
if (IsPotentialRetainableObjPtr(*I))
return CS.onlyReadsMemory() ? IC_User : IC_CallOrUser;
return CS.onlyReadsMemory() ? IC_None : IC_Call;
}
static inline bool IsObjCIdentifiedObject(const Value *V) {
if (isa<CallInst>(V) || isa<InvokeInst>(V) ||
isa<Argument>(V) || isa<Constant>(V) ||
isa<AllocaInst>(V))
return true;
if (const LoadInst *LI = dyn_cast<LoadInst>(V)) {
const Value *Pointer =
StripPointerCastsAndObjCCalls(LI->getPointerOperand());
if (const GlobalVariable *GV = dyn_cast<GlobalVariable>(Pointer)) {
if (GV->isConstant())
return true;
StringRef Name = GV->getName();
if (Name.startswith("\01L_OBJC_SELECTOR_REFERENCES_") ||
Name.startswith("\01L_OBJC_CLASSLIST_REFERENCES_") ||
Name.startswith("\01L_OBJC_CLASSLIST_SUP_REFS_$_") ||
Name.startswith("\01L_OBJC_METH_VAR_NAME_") ||
Name.startswith("\01l_objc_msgSend_fixup_"))
return true;
}
}
return false;
}
} }
#endif