#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"
#include "ARCInstKind.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_unsafeClaimAutoreleasedReturnValue") ||
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");
}
static inline const Value *GetUnderlyingObjCPtr(const Value *V,
const DataLayout &DL) {
for (;;) {
V = GetUnderlyingObject(V, DL);
if (!IsForwarding(GetBasicARCInstKind(V)))
break;
V = cast<CallInst>(V)->getArgOperand(0);
}
return V;
}
static inline const Value *GetRCIdentityRoot(const Value *V) {
for (;;) {
V = V->stripPointerCasts();
if (!IsForwarding(GetBasicARCInstKind(V)))
break;
V = cast<CallInst>(V)->getArgOperand(0);
}
return V;
}
static inline Value *GetRCIdentityRoot(Value *V) {
return const_cast<Value *>(GetRCIdentityRoot((const Value *)V));
}
static inline Value *GetArgRCIdentityRoot(Value *Inst) {
return GetRCIdentityRoot(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(GetBasicARCInstKind(CI)) ||
(IsNoopOnNull(GetBasicARCInstKind(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 ARCInstKind GetCallSiteClass(ImmutableCallSite CS) {
for (ImmutableCallSite::arg_iterator I = CS.arg_begin(), E = CS.arg_end();
I != E; ++I)
if (IsPotentialRetainableObjPtr(*I))
return CS.onlyReadsMemory() ? ARCInstKind::User : ARCInstKind::CallOrUser;
return CS.onlyReadsMemory() ? ARCInstKind::None : ARCInstKind::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 =
GetRCIdentityRoot(LI->getPointerOperand());
if (const GlobalVariable *GV = dyn_cast<GlobalVariable>(Pointer)) {
if (GV->isConstant())
return true;
StringRef Name = GV->getName();
if (Name.startswith("\01l_objc_msgSend_fixup_"))
return true;
StringRef Section = GV->getSection();
if (Section.find("__message_refs") != StringRef::npos ||
Section.find("__objc_classrefs") != StringRef::npos ||
Section.find("__objc_superrefs") != StringRef::npos ||
Section.find("__objc_methname") != StringRef::npos ||
Section.find("__cstring") != StringRef::npos)
return true;
}
}
return false;
}
struct ARCMDKindCache {
unsigned ImpreciseReleaseMDKind;
unsigned CopyOnEscapeMDKind;
unsigned NoObjCARCExceptionsMDKind;
};
} }
#endif