blob: bf6b49a4e78dc85515c318799957f9096b2e0f4b [file] [log] [blame]
//===-- insert.cpp - Insert SAFECode Run-time Checks ----------------------===//
//
// SAFECode
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the insertion of SAFECode's run-time checks.
//
//===----------------------------------------------------------------------===//
#include "safecode/Config/config.h"
#include "InsertPoolChecks.h"
#include "SCUtils.h"
#include "llvm/Instruction.h"
#include "llvm/Module.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/InstIterator.h"
#include "llvm/ADT/VectorExtras.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ConstantRange.h"
#include "llvm/Analysis/ScalarEvolutionExpander.h"
#include "llvm/Analysis/LoopInfo.h"
#include <iostream>
#include <vector>
#include <set>
using namespace llvm;
extern Value *getRepresentativeMetaPD(Value *);
RegisterPass<PreInsertPoolChecks> pipc ("presafecode", "prepare for SAFECode");
RegisterPass<InsertPoolChecks> ipc ("safecode", "insert runtime checks");
cl::opt<bool> EnableSplitChecks ("enable-splitchecks", cl::Hidden,
cl::init(false),
cl::desc("Split lookup and checks"));
cl::opt<bool> InsertPoolChecksForArrays("boundschecks-usepoolchecks",
cl::Hidden, cl::init(false),
cl::desc("Insert pool checks instead of exact bounds checks"));
// Options for Enabling/Disabling the Insertion of Various Checks
cl::opt<bool> EnableUnknownChecks ("enable-unknownchecks", cl::Hidden,
cl::init(false),
cl::desc("Enable Checks on Incomplete/Unknown Nodes"));
cl::opt<bool> EnableNullChecks ("enable-nullchecks", cl::Hidden,
cl::init(false),
cl::desc("Enable Checks on NULL Pools"));
cl::opt<bool> DisableRegisterGlobals ("disable-regglobals", cl::Hidden,
cl::init(false),
cl::desc("Do not register globals"));
cl::opt<bool> DisableLSChecks ("disable-lschecks", cl::Hidden,
cl::init(false),
cl::desc("Disable Load/Store Checks"));
cl::opt<bool> DisableGEPChecks ("disable-gepchecks", cl::Hidden,
cl::init(false),
cl::desc("Disable GetElementPtr(GEP) Checks"));
cl::opt<bool> DisableStackChecks ("disable-stackchecks", cl::Hidden,
cl::init(false),
cl::desc("Disable Stack Checks"));
cl::opt<bool> DisableFuncChecks ("disable-funcchecks", cl::Hidden,
cl::init(false),
cl::desc("Disable Function Call Checks"));
cl::opt<bool> DisableIntrinsicChecks ("disable-intrinchecks", cl::Hidden,
cl::init(false),
cl::desc("Disable Intrinsic Checks"));
cl::opt<bool> EnableMonotonicOptimisation("enable-monotonic", cl::Hidden,
cl::init(false),
cl::desc("Enable LICM for bounds checks on monotonic loops"));
// Options for where to insert various initialization code
cl::opt<string> InitFunctionName ("initfunc",
cl::desc("Specify name of initialization "
"function"),
cl::value_desc("function name"));
// Pass Statistics
static Statistic<> NullChecks ("safecode",
"Poolchecks with NULL pool descriptor");
static Statistic<> FullChecks ("safecode",
"Poolchecks with non-NULL pool descriptor");
static Statistic<> MissChecks ("safecode",
"Poolchecks omitted due to bad pool descriptor");
static Statistic<> PoolChecks ("safecode", "Poolchecks Added");
static Statistic<> FuncChecks ("safecode", "Indirect Call Checks Added");
static Statistic<> MissedFuncChecks ("safecode", "Indirect Call Checks Missed");
static Statistic<> SavedPoolChecks ("safecode", "Pool Checks Performed on Checked Pointers");
static Statistic<> AlignChecks ("safecode", "Number of alignment checks required");
static Statistic<> AlignLSChecks ("safecode", "Number of alignment on load/store checks required");
// Bounds Check Statistics
static Statistic<> BoundsChecks ("safecode",
"Total bounds checks inserted");
static Statistic<> IBoundsChecks ("safecode",
"Bounds checks with incomplete DSNode");
static Statistic<> UBoundsChecks ("safecode",
"Bounds checks with unknown DSNode");
static Statistic<> ABoundsChecks ("safecode",
"Bounds checks with stack DSNode");
static Statistic<> NullBoundsChecks ("safecode",
"Missed bounds checks - NULL pool handle");
static Statistic<> NoSHGBoundsChecks ("safecode",
"Missed bounds checks - no SHG DSNode");
static Statistic<> MissedIncompleteChecks ("safecode",
"Poolchecks missed because of incompleteness");
static Statistic<> MissedMultDimArrayChecks ("safecode",
"Multi-dimensional array checks");
static Statistic<> MissedGlobalChecks ("safecode", "Missed global checks");
static Statistic<> MissedNullChecks ("safecode", "Missed PD checks");
// Exact Check Statistics
static Statistic<> ExactChecks ("safecode", "Exactchecks inserted");
static Statistic<> ConstExactChecks ("safecode", "Omitted Exactchecks with constant arguments");
static Statistic<> ZeroFuncChecks ("safecode", "Indirect Call Checks with Zero Targets");
// Object registration statistics
static Statistic<> StackRegisters ("safecode", "Stack registrations");
static Statistic<> SavedRegAllocs ("safecode", "Stack registrations avoided");
// Other statistics
static Statistic<> StructGEPsRemoved ("safecode", "Structure GEP Checks Removed");
//MonotonicOpts
static Statistic<> MonotonicOpts ("safecode", "Number of monotonic LICM bounds check optimisations");
// The set of values that already have run-time checks
static std::set<Value *> CheckedValues;
////////////////////////////////////////////////////////////////////////////
// Static Functions
////////////////////////////////////////////////////////////////////////////
static inline bool
isNodeRegistered (DSNode * Node) {
// Do not perform checks on the pointer if its DSNode does not have a known
// allocation site.
if (!((Node->isAllocaNode()) ||
(Node->isHeapNode()) ||
(Node->isGlobalNode()))) {
++NoSHGBoundsChecks;
return false;
}
return true;
}
//Do not replace these with check results
static std::set<Value*> AddedValues;
static GlobalVariable*
makeMetaPool(Module* M, DSNode* N) {
//Here we insert a global meta pool
//Now create a meta pool for this value, DSN Node
const Type * VoidPtrType = PointerType::get(Type::SByteTy);
std::vector<const Type*> MPTV;
for (int x = 0; x < 9; ++x)
MPTV.push_back(VoidPtrType);
// Add the types for the hit cache
MPTV.push_back(Type::UIntTy);
MPTV.push_back(ArrayType::get (Type::UIntTy, 4));
MPTV.push_back(ArrayType::get (Type::UIntTy, 4));
MPTV.push_back(ArrayType::get (VoidPtrType, 4));
const StructType* MPT = StructType::get(MPTV);
static int x = 0;
std::string Name = "_metaPool_";
unsigned Flags = N ? N->getMP()->getFlags() : 0;
if(Flags & DSNode::Incomplete)
Name += "I";
if(Flags & DSNode::UnknownNode)
Name += "U";
if(Flags & DSNode::AllocaNode)
Name += "A";
if(Flags & DSNode::GlobalNode)
Name += "G";
if(Flags & DSNode::HeapNode)
Name += "H";
if( N && N->isNodeCompletelyFolded())
Name += "F";
Name += "_";
char c[100];
snprintf(c, sizeof(c), "%d", x);
Name += c;
Name += "_";
++x;
return new GlobalVariable(
/*type=*/ MPT,
/*isConstant=*/ false,
/*Linkage=*/ GlobalValue::InternalLinkage,
/*initializer=*/ Constant::getNullValue(MPT),
/*name=*/ Name,
/*parent=*/ M );
}
Value *
PreInsertPoolChecks::createPoolHandle (Module & M, DSNode * Node) {
// If there is no node, return NULL.
if (!Node) return 0;
// Get the DSNode's MetaPool. If it doesn't have one, return NULL.
MetaPool * MP = Node->getMP();
if (!MP) return 0;
// If the MetaPool global variable has already been created, then simply
// return it. Otherwise, create one.
if (!(MP->getMetaPoolValue()))
MP->setMetaPoolValue (makeMetaPool (&M, Node));
return (MP->getMetaPoolValue());
}
Value *
PreInsertPoolChecks::createPoolHandle (const Value * V, Function * F) {
//
// Get the DSNode from the Top Down DSGraph.
//
DSGraph &TDG = TDPass->getDSGraph(*F);
DSNode *Node = TDG.getNodeForValue((Value *)V).getNode();
// If there is no node, return NULL.
if (!Node) return 0;
// Get the DSNode's MetaPool. If it doesn't have one, return NULL.
MetaPool * MP = Node->getMP();
if (!MP) return 0;
// If the MetaPool global variable has already been created, then simply
// return it. Otherwise, create one.
if (!(MP->getMetaPoolValue()))
MP->setMetaPoolValue (makeMetaPool (F->getParent(), Node));
return (MP->getMetaPoolValue());
}
static void
AddCallToRegFunc (Function* F, GlobalVariable* GV, Function* PR, Value* PH,
Value* AllocSize) {
//
// First, make sure that we're not registering an external zero-sized global.
// These are caused by the following C construct and should never be checked:
// extern variable[];
//
ConstantInt * C;
if (GV->isExternal())
if ((C = dyn_cast<ConstantInt>(AllocSize)) && (!(C->getZExtValue())))
return;
const Type *VoidPtrType = PointerType::get(Type::SByteTy);
assert(PH && "No PoolHandle for Global!");
BasicBlock::iterator InsertPt = F->getEntryBlock().begin();
Instruction *GVCasted = new CastInst(GV, VoidPtrType, GV->getName()+"casted",InsertPt);
Value *PHCasted = new CastInst(PH, VoidPtrType, PH->getName()+"casted",InsertPt);
AllocSize = castTo (AllocSize, Type::UIntTy, InsertPt);
std::vector<Value *> args (1, PHCasted);
args.push_back (GVCasted);
args.push_back (AllocSize);
new CallInst(PR, args, "", InsertPt);
}
////////////////////////////////////////////////////////////////////////////
// Class: PreInsertPoolChecks
////////////////////////////////////////////////////////////////////////////
//
// Method: runOnModule()
//
// Description:
// This method is called by the pass manager. The job of this class is to
// create any global variables and inter-procedural changes that cannot be
// done in the doInitialization() method of the InsertPoolChecks class.
//
bool
PreInsertPoolChecks::runOnModule (Module & M) {
// Retrieve the analysis results from other passes
cuaPass = &getAnalysis<ConvertUnsafeAllocas>();
TDPass = &getAnalysis<TDDataStructures>();
TD = &getAnalysis<TargetData>();
// Add prototypes for the run-time checks to the module
addPoolCheckProto (M);
// Register global arrays and collapsed nodes with global pools
if (!DisableRegisterGlobals) registerGlobalArraysWithGlobalPools(M);
//
// Create a MetaPool global variable for every DSNode that we might
// encounter.
//
Module::iterator mI = M.begin(), mE = M.end();
for ( ; mI != mE; ++mI) {
Function *F = mI;
// Skip functions that are external
if (F->isExternal()) continue;
// Skip the poolcheckglobals() function because it won't have a DSGraph
if (F->getName() == "poolcheckglobals") continue;
// Create a MetaPool variable for each DSNode in the DSGraph.
DSGraph & TDG = TDPass->getDSGraph(*F);
DSGraph::node_iterator NI = TDG.node_begin(), NE = TDG.node_end();
while (NI != NE) {
addLinksNeedingAlignment (NI);
createPoolHandle (M, NI);
++NI;
}
}
}
//
// Method: addLinksNeedingAlignment()
//
// Description:
// Determine if this DSNode has any pointers to DSNodes which will require
// alignment checks. If so, add those DSNodes to the set of DSNodes needing
// alignment checks. Note that we do not determine if the *given* node needs
// alignment checks.
//
void
PreInsertPoolChecks::addLinksNeedingAlignment (DSNode * Node) {
//
// Determine whether an alignment check is needed. This occurs when a DSNode
// is type unknown (collapsed) but has pointers to type known (uncollapsed)
// DSNodes.
//
if ((Node) && (Node->isNodeCompletelyFolded())) {
for (unsigned i = 0 ; i < Node->getNumLinks(); ++i) {
DSNode * LinkNode = Node->getLink(i).getNode();
if (LinkNode && (!(LinkNode->isNodeCompletelyFolded()))) {
AlignmentNodes.insert (LinkNode);
}
}
}
}
void
PreInsertPoolChecks::addPoolCheckProto(Module &M) {
const Type * VoidPtrType = PointerType::get(Type::SByteTy);
#if 0
const Type *PoolDescType = ArrayType::get(VoidPtrType, 50);
// StructType::get(make_vector<const Type*>(VoidPtrType, VoidPtrType,
// Type::UIntTy, Type::UIntTy, 0));
const Type * PoolDescTypePtr = PointerType::get(PoolDescType);
#endif
std::vector<const Type *> Arg(1, VoidPtrType);
Arg.push_back(VoidPtrType);
FunctionType *PoolCheckTy =
FunctionType::get(Type::VoidTy,Arg, false);
PoolCheck = M.getOrInsertFunction("poolcheck", PoolCheckTy);
std::vector<const Type *> Arg2(1, VoidPtrType);
Arg2.push_back(VoidPtrType);
Arg2.push_back(VoidPtrType);
FunctionType *PoolCheckArrayTy =
FunctionType::get(Type::VoidTy,Arg2, false);
PoolCheckArray = M.getOrInsertFunction("poolcheckarray", PoolCheckArrayTy);
PoolCheckIArray = M.getOrInsertFunction("poolcheckarray_i", PoolCheckArrayTy);
std::vector<const Type *> Arg3(1, VoidPtrType);
Arg3.push_back(VoidPtrType); //for output
Arg3.push_back(VoidPtrType); //for referent
FunctionType *BoundsCheckTy = FunctionType::get(VoidPtrType,Arg3, false);
BoundsCheck = M.getOrInsertFunction("pchk_bounds", BoundsCheckTy);
UIBoundsCheck = M.getOrInsertFunction("pchk_bounds_i", BoundsCheckTy);
std::vector<const Type *> Arg4(1, VoidPtrType);
Arg4.push_back(VoidPtrType);
FunctionType *getBoundsTy = FunctionType::get(VoidPtrType,Arg4, false);
getBounds = M.getOrInsertFunction("getBounds", getBoundsTy);
UIgetBounds = M.getOrInsertFunction("getBounds_i", getBoundsTy);
//Get the poolregister function
PoolRegister = M.getOrInsertFunction("pchk_reg_obj", Type::VoidTy, VoidPtrType,
VoidPtrType, Type::UIntTy, NULL);
StackRegister = M.getOrInsertFunction("pchk_reg_stack", Type::VoidTy, VoidPtrType,
VoidPtrType, Type::UIntTy, NULL);
ObjFree = M.getOrInsertFunction("pchk_drop_obj", Type::VoidTy, VoidPtrType,
VoidPtrType, NULL);
StackFree = M.getOrInsertFunction("pchk_drop_stack", Type::VoidTy, VoidPtrType,
VoidPtrType, NULL);
FuncRegister = M.getOrInsertFunction("pchk_reg_func", Type::VoidTy, VoidPtrType, Type::UIntTy, PointerType::get(VoidPtrType), NULL);
PoolFindMP = M.getOrInsertFunction("pchk_getLoc", VoidPtrType, VoidPtrType, NULL);
PoolRegMP = M.getOrInsertFunction("pchk_reg_pool", Type::VoidTy, VoidPtrType, VoidPtrType, VoidPtrType, NULL);
std::vector<const Type *> FArg2(1, Type::IntTy);
FArg2.push_back(Type::IntTy);
FArg2.push_back(VoidPtrType);
FunctionType *ExactCheckTy = FunctionType::get(VoidPtrType, FArg2, false);
ExactCheck = M.getOrInsertFunction("exactcheck", ExactCheckTy);
std::vector<const Type *> FArg3(1, Type::UIntTy);
FArg3.push_back(VoidPtrType);
FArg3.push_back(VoidPtrType);
FArg3.push_back(VoidPtrType);
FArg3.push_back(VoidPtrType);
FArg3.push_back(VoidPtrType);
FArg3.push_back(VoidPtrType);
FArg3.push_back(VoidPtrType);
FunctionType *FunctionCheckTy = FunctionType::get(Type::VoidTy, FArg3, true);
FunctionCheck = M.getOrInsertFunction("funccheck", FunctionCheckTy);
std::vector<const Type *> FArg6(1, VoidPtrType);
FArg6.push_back(VoidPtrType);
FunctionType *FunctionCheckGTy = FunctionType::get(Type::VoidTy, FArg6, true);
FunctionCheckG = M.getOrInsertFunction("funccheck_g", FunctionCheckGTy);
std::vector<const Type *> FArg9(1, Type::UIntTy);
FArg9.push_back(VoidPtrType);
FArg9.push_back(PointerType::get(VoidPtrType));
FunctionType *FunctionCheckTTy = FunctionType::get(Type::VoidTy, FArg9, true);
FunctionCheckT = M.getOrInsertFunction("funccheck_t", FunctionCheckTTy);
FArg9.clear();
FArg9.push_back(VoidPtrType);
FunctionType *ICCheckTy = FunctionType::get(Type::VoidTy, FArg9, true);
ICCheck = M.getOrInsertFunction("pchk_iccheck", ICCheckTy);
std::vector<const Type*> FArg5(1, VoidPtrType);
FArg5.push_back(VoidPtrType);
FunctionType *GetActualValueTy = FunctionType::get(VoidPtrType, FArg5, false);
GetActualValue = M.getOrInsertFunction("pchk_getActualValue", GetActualValueTy);
std::vector<const Type*> FArg4(1, VoidPtrType); //base
FArg4.push_back(VoidPtrType); //result
FArg4.push_back(Type::UIntTy); //size
FunctionType *ExactCheck2Ty = FunctionType::get(VoidPtrType, FArg4, false);
ExactCheck2 = M.getOrInsertFunction("exactcheck2", ExactCheck2Ty);
std::vector<const Type*> FArg7(1, VoidPtrType); //base
FArg7.push_back(VoidPtrType); //result
FArg7.push_back(VoidPtrType); //end
FunctionType *ExactCheck3Ty = FunctionType::get(VoidPtrType, FArg7, false);
ExactCheck3 = M.getOrInsertFunction("exactcheck3", ExactCheck3Ty);
std::vector<const Type*> FArg8(1, VoidPtrType); //base
FunctionType *getBeginEndTy = FunctionType::get(VoidPtrType, FArg8, false);
getBegin = M.getOrInsertFunction("getBegin", getBeginEndTy);
getEnd = M.getOrInsertFunction("getEnd", getBeginEndTy);
}
void
PreInsertPoolChecks::registerGlobalArraysWithGlobalPools(Module &M) {
#ifdef LLVA_KERNEL
const Type *VoidPtrType = PointerType::get(Type::SByteTy);
const Type *PoolDescType = ArrayType::get(VoidPtrType, 50);
const Type *PoolDescPtrTy = PointerType::get(PoolDescType);
const Type* csiType = Type::getPrimitiveType(Type::UIntTyID);
//Get the registration function
std::vector<const Type*> Vt;
const FunctionType* RFT = FunctionType::get(Type::VoidTy, Vt, false);
Function* RegFunc = M.getOrInsertFunction("poolcheckglobals", RFT);
if (RegFunc->empty()) {
BasicBlock* BB = new BasicBlock("reg", RegFunc);
new ReturnInst(BB);
}
//Now iterate over globals and register all the arrays
DSGraph &G = TDPass->getGlobalsGraph();
Module::global_iterator GI = M.global_begin(), GE = M.global_end();
for ( ; GI != GE; ++GI) {
if (GlobalVariable *GV = dyn_cast<GlobalVariable>(GI)) {
if (GV->getType() != PoolDescPtrTy) {
GlobalValue * GVLeader = G.getScalarMap().getLeaderForGlobal(GV);
DSNode *DSN = G.getNodeForValue(GVLeader).getNode();
if (((isa<ArrayType>(GV->getType()->getElementType())) ||
(DSN && DSN->isNodeCompletelyFolded()))
&& !isa<OpaqueType>(GV->getType())
&& !(isa<PointerType>(GV->getType()) &&
isa<OpaqueType>(cast<PointerType>(GV->getType())->getElementType()))) {
Value * AllocSize;
if (const ArrayType *AT = dyn_cast<ArrayType>(GV->getType()->getElementType())) {
//std::cerr << "found global" << *GI << std::endl;
AllocSize = ConstantInt::get(csiType,
(AT->getNumElements() * TD->getTypeSize(AT->getElementType())));
} else {
AllocSize = ConstantInt::get(csiType, TD->getTypeSize(GV->getType()->getElementType()));
}
Value* PH = getPD(DSN, M);
if (PH)
AddCallToRegFunc(RegFunc, GV, PoolRegister, PH, AllocSize);
}
}
}
}
#else
Function *MainFunc = M.getMainFunction();
if (MainFunc == 0 || MainFunc->isExternal()) {
std::cerr << "Cannot do array bounds check for this program"
<< "no 'main' function yet!\n";
abort();
}
//First register, argc and argv
Function::arg_iterator AI = MainFunc->arg_begin(), AE = MainFunc->arg_end();
if (AI != AE) {
//There is argc and argv
Value *Argc = AI;
AI++;
Value *Argv = AI;
PA::FuncInfo *FI = paPass->getFuncInfoOrClone(*MainFunc);
Value *PH= getPoolHandle(Argv, MainFunc, *FI);
Function *PoolRegister = paPass->PoolRegister;
BasicBlock::iterator InsertPt = MainFunc->getEntryBlock().begin();
while ((isa<CallInst>(InsertPt)) || isa<CastInst>(InsertPt) || isa<AllocaInst>(InsertPt) || isa<BinaryOperator>(InsertPt)) ++InsertPt;
if (PH) {
Type *VoidPtrType = PointerType::get(Type::SByteTy);
Instruction *GVCasted = new CastInst(Argv,
VoidPtrType, Argv->getName()+"casted",InsertPt);
const Type* csiType = Type::getPrimitiveType(Type::UIntTyID);
Value *AllocSize = new CastInst(Argc,
csiType, Argc->getName()+"casted",InsertPt);
AllocSize = BinaryOperator::create(Instruction::Mul, AllocSize,
ConstantInt::get(csiType, 4), "sizetmp", InsertPt);
new CallInst(PoolRegister,
make_vector(PH, AllocSize, GVCasted, 0),
"", InsertPt);
} else {
std::cerr << "argv's pool descriptor is not present. \n";
// abort();
}
}
//Now iterate over globals and register all the arrays
Module::global_iterator GI = M.global_begin(), GE = M.global_end();
for ( ; GI != GE; ++GI) {
if (GlobalVariable *GV = dyn_cast<GlobalVariable>(GI)) {
Type *VoidPtrType = PointerType::get(Type::SByteTy);
Type *PoolDescType = ArrayType::get(VoidPtrType, 50);
Type *PoolDescPtrTy = PointerType::get(PoolDescType);
if (GV->getType() != PoolDescPtrTy) {
DSGraph &G = equivPass->getGlobalsGraph();
DSNode *DSN = G.getNodeForValue(GV).getNode();
if ((isa<ArrayType>(GV->getType()->getElementType())) ||
DSN->isNodeCompletelyFolded()) {
Value * AllocSize;
const Type* csiType = Type::getPrimitiveType(Type::UIntTyID);
if (const ArrayType *AT = dyn_cast<ArrayType>(GV->getType()->getElementType())) {
//std::cerr << "found global" << *GI << std::endl;
AllocSize = ConstantInt::get(csiType,
(AT->getNumElements() * TD->getTypeSize(AT->getElementType())));
} else {
AllocSize = ConstantInt::get(csiType, TD->getTypeSize(GV->getType()));
}
Function *PoolRegister = paPass->PoolRegister;
BasicBlock::iterator InsertPt = MainFunc->getEntryBlock().begin();
//skip the calls to poolinit
while ((isa<CallInst>(InsertPt)) ||
isa<CastInst>(InsertPt) ||
isa<AllocaInst>(InsertPt) ||
isa<BinaryOperator>(InsertPt)) ++InsertPt;
std::map<const DSNode *, Value *>::iterator I = paPass->GlobalNodes.find(DSN);
if (I != paPass->GlobalNodes.end()) {
Value *PH = I->second;
Instruction *GVCasted = new CastInst(GV,
VoidPtrType, GV->getName()+"casted",InsertPt);
new CallInst(PoolRegister,
make_vector(PH, AllocSize, GVCasted, 0),
"", InsertPt);
} else {
std::cerr << "pool descriptor not present \n ";
abort();
}
}
}
}
}
#endif
}
////////////////////////////////////////////////////////////////////////////
// Class: InsertPoolChecks
////////////////////////////////////////////////////////////////////////////
void
InsertPoolChecks::addPoolCheckProto(Module &M) {
const Type * VoidPtrType = PointerType::get(Type::SByteTy);
#if 0
const Type *PoolDescType = ArrayType::get(VoidPtrType, 50);
// StructType::get(make_vector<const Type*>(VoidPtrType, VoidPtrType,
// Type::UIntTy, Type::UIntTy, 0));
const Type * PoolDescTypePtr = PointerType::get(PoolDescType);
#endif
std::vector<const Type *> Arg(1, VoidPtrType);
Arg.push_back(VoidPtrType);
FunctionType *PoolCheckTy =
FunctionType::get(Type::VoidTy,Arg, false);
PoolCheck = M.getOrInsertFunction("poolcheck", PoolCheckTy);
PoolCheckUI = M.getOrInsertFunction("poolcheck_i", PoolCheckTy);
Arg.clear();
Arg.push_back(VoidPtrType);
Arg.push_back(VoidPtrType);
Arg.push_back(Type::UIntTy);
PoolCheckTy = FunctionType::get(Type::VoidTy,Arg, false);
PoolCheckAlign = M.getOrInsertFunction("poolcheckalign", PoolCheckTy);
PoolCheckAlignUI = M.getOrInsertFunction("poolcheckalign_i", PoolCheckTy);
std::vector<const Type *> Arg2(1, VoidPtrType);
Arg2.push_back(VoidPtrType);
Arg2.push_back(VoidPtrType);
FunctionType *PoolCheckArrayTy =
FunctionType::get(Type::VoidTy,Arg2, false);
PoolCheckArray = M.getOrInsertFunction("poolcheckarray", PoolCheckArrayTy);
PoolCheckIArray = M.getOrInsertFunction("poolcheckarray_i", PoolCheckArrayTy);
std::vector<const Type *> Arg3(1, VoidPtrType);
Arg3.push_back(VoidPtrType); //for output
Arg3.push_back(VoidPtrType); //for referent
FunctionType *BoundsCheckTy = FunctionType::get(VoidPtrType,Arg3, false);
BoundsCheck = M.getOrInsertFunction("pchk_bounds", BoundsCheckTy);
UIBoundsCheck = M.getOrInsertFunction("pchk_bounds_i", BoundsCheckTy);
std::vector<const Type *> Arg4(1, VoidPtrType);
Arg4.push_back(VoidPtrType);
FunctionType *getBoundsTy = FunctionType::get(VoidPtrType,Arg4, false);
getBounds = M.getOrInsertFunction("getBounds", getBoundsTy);
UIgetBounds = M.getOrInsertFunction("getBounds_i", getBoundsTy);
//Get the poolregister function
PoolRegister = M.getOrInsertFunction("pchk_reg_obj", Type::VoidTy, VoidPtrType,
VoidPtrType, Type::UIntTy, NULL);
StackRegister = M.getOrInsertFunction("pchk_reg_stack", Type::VoidTy, VoidPtrType,
VoidPtrType, Type::UIntTy, NULL);
ObjFree = M.getOrInsertFunction("pchk_drop_obj", Type::VoidTy, VoidPtrType,
VoidPtrType, NULL);
StackFree = M.getOrInsertFunction("pchk_drop_stack", Type::VoidTy, VoidPtrType,
VoidPtrType, NULL);
FuncRegister = M.getOrInsertFunction("pchk_reg_func", Type::VoidTy, VoidPtrType, Type::UIntTy, PointerType::get(VoidPtrType), NULL);
PoolFindMP = M.getOrInsertFunction("pchk_getLoc", VoidPtrType, VoidPtrType, NULL);
PoolRegMP = M.getOrInsertFunction("pchk_reg_pool", Type::VoidTy, VoidPtrType, VoidPtrType, VoidPtrType, NULL);
// Function *KmemCacheAlloc = M.getNamedFunction("kmem_cache_alloc");
// assert(KmemCacheAlloc->arg_size() == 2 &&"Kmem_cache_alloc number of arguments != 2");
// Function::arg_iterator kcai = KmemCacheAlloc->arg_begin();
// Type *kmem_cache_t = kcai->getType();
// kcai++;
// Type *kem_cache_size_t = kcai->getType();
// We'll use Void * instead of the above
KmemCachegetSize = M.getOrInsertFunction("kmem_cache_size", Type::UIntTy, VoidPtrType, NULL);
std::vector<const Type *> FArg2(1, Type::IntTy);
FArg2.push_back(Type::IntTy);
FArg2.push_back(VoidPtrType);
FunctionType *ExactCheckTy = FunctionType::get(VoidPtrType, FArg2, false);
ExactCheck = M.getOrInsertFunction("exactcheck", ExactCheckTy);
std::vector<const Type *> FArg3(1, Type::UIntTy);
FArg3.push_back(VoidPtrType);
FArg3.push_back(VoidPtrType);
FunctionType *FunctionCheckTy = FunctionType::get(Type::VoidTy, FArg3, true);
FunctionCheck = M.getOrInsertFunction("funccheck", FunctionCheckTy);
std::vector<const Type *> FArg6(1, VoidPtrType);
FArg6.push_back(VoidPtrType);
FunctionType *FunctionCheckGTy = FunctionType::get(Type::VoidTy, FArg6, true);
FunctionCheckG = M.getOrInsertFunction("funccheck_g", FunctionCheckGTy);
std::vector<const Type *> FArg9(1, Type::UIntTy);
FArg9.push_back(VoidPtrType);
FArg9.push_back(PointerType::get(VoidPtrType));
FunctionType *FunctionCheckTTy = FunctionType::get(Type::VoidTy, FArg9, true);
FunctionCheckT = M.getOrInsertFunction("funccheck_t", FunctionCheckTTy);
FArg9.clear();
FArg9.push_back(VoidPtrType);
FunctionType *ICCheckTy = FunctionType::get(Type::VoidTy, FArg9, true);
ICCheck = M.getOrInsertFunction("pchk_iccheck", ICCheckTy);
std::vector<const Type*> FArg5(1, VoidPtrType);
FArg5.push_back(VoidPtrType);
FunctionType *GetActualValueTy = FunctionType::get(VoidPtrType, FArg5, false);
GetActualValue = M.getOrInsertFunction("pchk_getActualValue", GetActualValueTy);
std::vector<const Type*> FArg4(1, VoidPtrType); //base
FArg4.push_back(VoidPtrType); //result
FArg4.push_back(Type::UIntTy); //size
FunctionType *ExactCheck2Ty = FunctionType::get(VoidPtrType, FArg4, false);
ExactCheck2 = M.getOrInsertFunction("exactcheck2", ExactCheck2Ty);
std::vector<const Type*> FArg7(1, VoidPtrType); //base
FArg7.push_back(VoidPtrType); //result
FArg7.push_back(VoidPtrType); //end
FunctionType *ExactCheck3Ty = FunctionType::get(VoidPtrType, FArg7, false);
ExactCheck3 = M.getOrInsertFunction("exactcheck3", ExactCheck3Ty);
std::vector<const Type*> FArg8(1, VoidPtrType); //base
FunctionType *getBeginEndTy = FunctionType::get(VoidPtrType, FArg8, false);
getBegin = M.getOrInsertFunction("getBegin", getBeginEndTy);
getEnd = M.getOrInsertFunction("getEnd", getBeginEndTy);
}
void
InsertPoolChecks::addHeapRegs (Module & M) {
DSNode * Node;
MetaPool * MP;
const Type * VoidPtrType = PointerType::get(Type::SByteTy);
std::set<Value *> ProcessedMetaPools;
std::vector<Value *> args;
while (PHNeeded.size()) {
Node = *(PHNeeded.begin());
PHNeeded.erase(Node);
MP = Node->getMP();
Value* MPV = MP->getMetaPoolValue();
//
// Determine if we have already processed this MetaPool. If we have, then
// just go on to the next DSNode.
if (ProcessedMetaPools.find (MPV) == ProcessedMetaPools.end())
ProcessedMetaPools.insert (MPV);
else
continue;
// Add registers in front of every allocation
for (std::list<CallSite>::iterator i = MP->allocs.begin(),
e = MP->allocs.end(); i != e; ++i) {
args.clear();
std::string name = i->getCalledFunction()->getName();
if (name == "kmem_cache_alloc") {
Instruction * InsertPt = i->getInstruction();
//insert a register before
Value* VP = castTo (i->getArgument(0), VoidPtrType, InsertPt);
Value* VMP = castTo (MPV, VoidPtrType, InsertPt);
Value* VMPP = new CallInst(PoolFindMP, VP, "", InsertPt);
args.push_back (VMP);
args.push_back (VP);
args.push_back (VMPP);
new CallInst (PoolRegMP, args, "", i->getInstruction());
//Insert Obj reg using kmem_cache_size after
Instruction* IP = i->getInstruction()->getNext();
Value* VRP = castTo (i->getInstruction(), VoidPtrType, IP);
CallInst *len = new CallInst(KmemCachegetSize, VP, "", IP);
args.clear();
args.push_back (VMP); //MetaPool
args.push_back (VRP); //object
args.push_back (len); //len
new CallInst(PoolRegister, args, "", IP);
#if 0
} else if ((name == "kmalloc") ||
#else
} else if (
#endif
(name == "__vmalloc") ||
(name == "__alloc_bootmem")) {
//inser obj register after
Instruction* IP = i->getInstruction()->getNext();
Value* VP = castTo (i->getInstruction(), VoidPtrType, IP);
Value* VMP = castTo (MPV, VoidPtrType, IP);
Value* len = castTo (i->getArgument(0), Type::UIntTy, IP);
args.push_back (VMP);
args.push_back (VP);
args.push_back (len);
new CallInst(PoolRegister, args, "", IP);
} else
assert(0 && "unknown alloc");
}
}
}
void InsertPoolChecks::addMetaPools(Module& M, MetaPool* MP, DSNode* N) {
if (!MP || MP->getMetaPoolValue()) return;
MP->setMetaPoolValue(makeMetaPool(&M, N));
Value* MPV = MP->getMetaPoolValue();
//added registers in front of every allocation
for(std::list<CallSite>::iterator i = MP->allocs.begin(),
e = MP->allocs.end(); i != e; ++i) {
std::string name = i->getCalledFunction()->getName();
if (name == "kmem_cache_alloc") {
//insert a register before
Value* VP = new CastInst(i->getArgument(0), PointerType::get(Type::SByteTy), "", i->getInstruction());
Value* VMP = new CastInst(MPV, PointerType::get(Type::SByteTy), "MP", i->getInstruction());
Value* VMPP = new CallInst(PoolFindMP, make_vector(VP, 0), "", i->getInstruction());
new CallInst(PoolRegMP, make_vector(VMP, VP, VMPP, 0), "", i->getInstruction());
#if 0
} else if ((name == "kmalloc") ||
#else
} else if (
#endif
(name == "__vmalloc") ||
(name == "__alloc_bootmem")) {
//inser obj register after
Instruction* IP = i->getInstruction()->getNext();
Value* VP = new CastInst(i->getInstruction(), PointerType::get(Type::SByteTy), "", IP);
Value* VMP = new CastInst(MPV, PointerType::get(Type::SByteTy), "MP", IP);
Value* len = new CastInst(i->getArgument(0), Type::UIntTy, "len", IP);
new CallInst(PoolRegister, make_vector(VMP, VP, len, 0), "", IP);
} else
assert(0 && "unknown alloc");
}
}
void InsertPoolChecks::addObjFrees(Module& M) {
#ifdef LLVA_KERNEL
#if 0
Function* KMF = M.getNamedFunction("kfree");
#endif
Function* VMF = M.getNamedFunction("vfree");
std::list<Function*> L;
#if 0
if (KMF) L.push_back(KMF);
#endif
if (VMF) L.push_back(VMF);
for (std::list<Function*>::iterator ii = L.begin(), ee = L.end();
ii != ee; ++ii) {
Function* F = *ii;
for (Value::use_iterator ii = F->use_begin(), ee = F->use_end();
ii != ee; ++ii) {
if (CallInst* CI = dyn_cast<CallInst>(*ii)) {
if (CI->getCalledFunction() == F) {
Value* Ptr = CI->getOperand(1);
Value* MP = getPD(getDSNode(Ptr, CI->getParent()->getParent()), M);
if (MP) {
MP = new CastInst(MP, PointerType::get(Type::SByteTy), "MP", CI);
Ptr = new CastInst(Ptr, PointerType::get(Type::SByteTy), "ADDR", CI);
new CallInst(ObjFree, make_vector(MP, Ptr, 0), "", CI);
}
}
}
}
}
#endif
}
//
// Method: insertICCheck()
//
// Description:
// Perform a run-time check to ensure that this pointer points to the
// beginning of an interrupt context.
//
void
InsertPoolChecks::insertICCheck (Value * IC, Instruction * InsertPt) {
const Type * VoidPtrType = PointerType::get(Type::SByteTy);
Value * CastPointer = castTo (IC, VoidPtrType, InsertPt);
new CallInst (ICCheck, CastPointer, "", InsertPt);
}
//
// Return value:
// Returns the inserted boundscheck call instruction. This can be used to
// replace the destination instruction if desired.
// If no instruction was inserted, it returns Dest.
//
Value *
InsertPoolChecks::insertBoundsCheck (Instruction * I,
Value * Src,
Value * Dest,
Instruction * InsertPt) {
// Enclosing function
Function * F = I->getParent()->getParent();
Function *Fnew = F;
// Source node on which we will look up the pool handle
Value *newSrc = Src;
#ifndef LLVA_KERNEL
// Some times the ECGraphs doesnt contain F for newly created cloned
// functions
if (!equivPass->ContainsDSGraphFor(*F)) {
PA::FuncInfo *FI = paPass->getFuncInfoOrClone(*F);
newSrc = FI->MapValueToOriginal(MAI);
assert(newSrc && " Instruction not in value map (clone)\n");
}
Function *Fnew = newSrc->getParent()->getParent();
#endif
//
// Get the pool handle for the source pointer.
//
Value *PH = getPoolHandle(newSrc, Fnew);
if (!PH) {
// Update statistics
++NullBoundsChecks;
return Dest;
}
//
// Get the DSGraph of the enclosing function and get the corresponding
// DSNode.
//
DSGraph & TDG = TDPass->getDSGraph(*F);
DSNode * Node = TDG.getNodeForValue(I).getNode();
//
// Determine whether an alignment check is needed. This occurs when a DSNode
// is type unknown (collapsed) but has pointers to type known (uncollapsed)
// DSNodes.
//
if (preSCPass->nodeNeedsAlignment (Node)) {
++AlignChecks;
}
// If there is no DSNode, do not perform a check
if (!Node) return Dest;
// If we do not know the allocation site, don't bother checking it
if (!(isNodeRegistered (Node)))
return Dest;
// Record statistics on the incomplete checks we do. Note that a node may
// be counted more than once.
if (Node->isIncomplete())
++IBoundsChecks;
if (Node->isUnknownNode())
++UBoundsChecks;
if (Node->isAllocaNode())
++ABoundsChecks;
//
// Cast the pool handle, source and destination pointers into the correct
// type for the call instruction.
//
Value * SrcCast = Src;
Value * DestCast = Dest;
if (Src->getType() != PointerType::get(Type::SByteTy))
SrcCast = new CastInst (Src, PointerType::get(Type::SByteTy),
"castsrc", InsertPt);
if (Dest->getType() != PointerType::get(Type::SByteTy))
DestCast = new CastInst (Dest, PointerType::get(Type::SByteTy),
"castdst", InsertPt);
if (PH->getType() != PointerType::get(Type::SByteTy))
PH = new CastInst (PH, PointerType::get(Type::SByteTy),
"castph", InsertPt);
AddedValues.insert(DestCast);
//
// Insert the bounds check.
//
Value * CI;
if (EnableSplitChecks) {
std::vector<Value *> args(1, PH);
args.push_back (SrcCast);
if ((Node == 0) ||
(Node->isAllocaNode()) ||
(Node->isIncomplete()) ||
(Node->isUnknownNode()))
CI = new CallInst(UIgetBounds, args, "uibc",InsertPt);
else
CI = new CallInst(getBounds, args, "bc", InsertPt);
std::vector<Value *> boundsargs(1, CI);
Instruction * LowerBound = new CallInst(getBegin, boundsargs, "gb", InsertPt);
Instruction * UpperBound = new CallInst(getEnd, boundsargs, "ge", InsertPt);
Value * EC3 = addExactCheck3 (LowerBound, DestCast, UpperBound, InsertPt);
AddedValues.insert(EC3);
if (EC3->getType() != Dest->getType())
EC3 = new CastInst(EC3, Dest->getType(), EC3->getName(), InsertPt);
AddedValues.insert(EC3);
// Replace all uses of the original pointer with the result of the exactcheck.
// This ensures that the check will not get dead code eliminated.
Value::use_iterator UI = Dest->use_begin();
for (; UI != Dest->use_end(); ++UI) {
if (AddedValues.find(*UI) == AddedValues.end())
UI->replaceUsesOfWith (Dest,EC3);
}
CI = EC3;
} else {
std::vector<Value *> args(1, PH);
args.push_back (SrcCast);
args.push_back (DestCast);
if ((Node == 0) ||
(Node->isAllocaNode()) ||
(Node->isIncomplete()) ||
(Node->isUnknownNode()))
CI = new CallInst(UIBoundsCheck, args, "uibc",InsertPt);
else
CI = new CallInst(BoundsCheck, args, "bc", InsertPt);
}
//
// Record that this value was checked.
//
CheckedValues.insert (Dest);
CheckedValues.insert (CI);
// Update statistics
++BoundsChecks;
return CI;
}
//
// Method: getOrCreateFunctionTable()
//
// Description:
// Given a DSNode, return a global variable containing an array of the
// function pointers within that DSNode. If this global variable does not
// exist, create it and modify poolcheckglobals() to register it with its
// MetaPool.
//
GlobalVariable *
InsertPoolChecks::getOrCreateFunctionTable (DSNode * Node, Value * PH,
Module * M) {
// Determine if we have already created such a global.
if (FuncListMap.count (PH)) {
return FuncListMap[PH];
}
// Get the globals list corresponding to the node
std::vector<Function *> FuncList;
Node->addFullFunctionList(FuncList);
unsigned num = FuncList.size();
// Create a global array of void pointers containing the list of possible
// function targets.
std::vector<Function *>::iterator flI= FuncList.begin(), flE = FuncList.end();
const Type* csiType = Type::getPrimitiveType(Type::UIntTyID);
Value *NumArg = ConstantInt::get(csiType, num);
Type *VoidPtrType = PointerType::get(Type::SByteTy);
std::vector<Constant *> Targets;
for (; flI != flE ; ++flI) {
Function *func = *flI;
Constant *CastfuncI = ConstantExpr::getCast (func, VoidPtrType);
Targets.push_back(CastfuncI);
}
ArrayType * TableType = ArrayType::get (VoidPtrType, num);
Constant * TableInit = ConstantArray::get (TableType, Targets);
GlobalVariable * Table = new GlobalVariable (TableType, true, GlobalValue::InternalLinkage, TableInit, "functargets", M);
Value * TableCast = ConstantExpr::getCast (Table, PointerType::get(VoidPtrType));
//
// Add an instruction to poolcheckglobals() to register this table of
// functions with the MetaPool.
//
std::vector<const Type*> Vt;
const FunctionType* RFT = FunctionType::get(Type::VoidTy, Vt, false);
Function * RegFunc = M->getOrInsertFunction("poolcheckglobals", RFT);
BasicBlock* BB;
if (RegFunc->empty()) {
BasicBlock* BB = new BasicBlock("reg", RegFunc);
new ReturnInst(BB);
} else {
BB = &(RegFunc->getEntryBlock());
}
Instruction * InsertPt = BB->getTerminator();
Value * CastPH = new CastInst(PH, VoidPtrType, "casted", InsertPt);
std::vector<Value *> args;
args.push_back (CastPH);
args.push_back (NumArg);
args.push_back (TableCast);
new CallInst(FuncRegister, args, "", InsertPt);
//
// Insert the DSNode and Table into the map.
//
FuncListMap.insert (make_pair(PH,Table));
return Table;
}
//
// Method: insertFunctionCheck()
//
// Description:
// Insert a run-time check on the argument to an indirect call instruction.
//
void
InsertPoolChecks::insertFunctionCheck (CallInst * CI) {
if (DisableFuncChecks)
return;
// Get the containing function and the function pointer.
Function * F = CI->getParent()->getParent();
Value * FuncPointer = CI->getCalledValue();
// Try to remove any encapsulating casts to get to the original instruction
ConstantExpr *cExpr;
while ((cExpr = dyn_cast<ConstantExpr>(FuncPointer)) &&
(cExpr->getOpcode() == Instruction::Cast))
FuncPointer = cExpr->getOperand(0);
//
// Determine if the function pointer came from a load instruction that loaded
// its value from a type known pool. If it is, it does not need a check.
//
if (LoadInst * LI = dyn_cast<LoadInst>(FuncPointer)) {
DSNode * LoadNode = getDSNode (LI->getPointerOperand(), F);
if ((LoadNode) && (!(LoadNode->isNodeCompletelyFolded())))
return;
}
//
// Get the DSNode and Pool handle for the call instruction.
//
Value *PH = getPoolHandle (FuncPointer, F);
if (!PH) {
// Update statistics
++NullBoundsChecks;
return;
}
DSNode* Node = getDSNode(FuncPointer, F);
//
// If the node is incomplete, then the call targets associated with the
// DSNode may be missing valid function targets. In that case, do not
// insert a check.
//
if ((!EnableUnknownChecks) && (Node->isIncomplete())) {
++MissedFuncChecks;
return;
}
// Get the globals list corresponding to the node
std::vector<Function *> FuncList;
Node->addFullFunctionList(FuncList);
unsigned num = FuncList.size();
//
// Insert a call to one of the function check functions, depending upon
// the number of functions we must check against.
//
if (num == 0) {
++ZeroFuncChecks;
return;
}
// Update statistics on the number of indirect call checks.
++FuncChecks;
std::vector<Function *>::iterator flI= FuncList.begin(), flE = FuncList.end();
const Type* csiType = Type::getPrimitiveType(Type::UIntTyID);
Value *NumArg = ConstantInt::get(csiType, num);
Type *VoidPtrType = PointerType::get(Type::SByteTy);
if (num < 7) {
const Type* csiType = Type::getPrimitiveType(Type::UIntTyID);
Value *NumArg = ConstantInt::get(csiType, num);
CastInst *CastVI =
new CastInst(FuncPointer, VoidPtrType, "casted", (Instruction *)(CI));
std::vector<Value *> args(1, NumArg);
args.push_back(CastVI);
for (; flI != flE ; ++flI) {
Function *func = *flI;
CastInst *CastfuncI =
new CastInst(func, VoidPtrType, "casted", (Instruction *)(CI));
args.push_back(CastfuncI);
}
for (unsigned index = num; index < 7; ++index)
args.push_back (ConstantPointerNull::get (PointerType::get (Type::SByteTy)));
new CallInst(FunctionCheck, args,"", (Instruction *)(CI));
} else if (num < 21) {
// Create the first two arguments for the function check call
std::vector<Value *> args(1, NumArg);
CastInst *CastVI =
new CastInst(FuncPointer, VoidPtrType, "casted", (Instruction *)(CI));
args.push_back(CastVI);
// Create a global array of void pointers containing the list of possible
// function targets.
GlobalVariable * Table = getOrCreateFunctionTable (Node, PH, F->getParent());
CastInst *CastTable =
new CastInst(Table,
PointerType::get(VoidPtrType), "casted", (Instruction *)(CI));
args.push_back(CastTable);
new CallInst(FunctionCheckT, args, "", (Instruction *)(CI));
} else {
// Create a global array of void pointers containing the list of possible
// function targets.
getOrCreateFunctionTable (Node, PH, F->getParent());
// Create the first two arguments for the function check call
PH = new CastInst (PH, VoidPtrType, "casted", (Instruction *)(CI));
CastInst *CastVI =
new CastInst(FuncPointer, VoidPtrType, "casted", (Instruction *)(CI));
std::vector<Value *> args(1, PH);
args.push_back(CastVI);
new CallInst(FunctionCheckG, args,"", (Instruction *)(CI));
}
}
//
// Function: addExactCheck2()
//
// Description:
// Utility routine that inserts a call to exactcheck2().
//
// Inputs:
// BasePointer - An LLVM Value representing the base of the object to check.
// Result - An LLVM Value representing the pointer to check.
// Bounds - An LLVM Value representing the bounds of the check.
// InsertPt - The instruction before which to insert the check.
//
void
InsertPoolChecks::addExactCheck2 (Value * BasePointer,
Value * Result,
Value * Bounds,
Instruction * InsertPt) {
Value * ResultPointer = Result;
// The LLVM type for a void *
Type *VoidPtrType = PointerType::get(Type::SByteTy);
//
// Cast the operands to the correct type.
//
if (BasePointer->getType() != VoidPtrType)
BasePointer = new CastInst(BasePointer, VoidPtrType,
BasePointer->getName()+".ec2.casted",
InsertPt);
if (ResultPointer->getType() != VoidPtrType)
ResultPointer = new CastInst(ResultPointer, VoidPtrType,
ResultPointer->getName()+".ec2.casted",
InsertPt);
Value * CastBounds = Bounds;
if (Bounds->getType() != Type::UIntTy)
CastBounds = new CastInst(Bounds, Type::UIntTy,
Bounds->getName()+".ec.casted", InsertPt);
//
// Create the call to exactcheck2().
//
std::vector<Value *> args(1, BasePointer);
args.push_back(ResultPointer);
args.push_back(CastBounds);
Instruction * CI;
CI = new CallInst(ExactCheck2, args, "", InsertPt);
//
// Record that this value was checked.
//
CheckedValues.insert (Result);
#if 0
//
// Replace the old pointer with the return value of exactcheck2(); this
// prevents GCC from removing it completely.
//
if (CI->getType() != GEP->getType())
CI = new CastInst (CI, GEP->getType(), GEP->getName(), InsertPt);
Value::use_iterator UI = GEP->use_begin();
for (; UI != GEP->use_end(); ++UI) {
if (((*UI) != CI) && ((*UI) != ResultPointer))
UI->replaceUsesOfWith (GEP, CI);
}
#endif
// Update statistics
++ExactChecks;
return;
}
//
// Function: addExactCheck3()
//
// Description:
// Utility routine that inserts a call to exactcheck3().
//
// Inputs:
// Source - The pointer that is the lower bound of the array.
// Result - The pointer that we wish to check.
// Bounds - The length of the array in bytes.
// InsertPt - The instruction before which to insert the check.
//
Value *
InsertPoolChecks::addExactCheck3 (Value * Source,
Value * Result,
Value * Bounds,
Instruction * InsertPt) {
// The LLVM type for a void *
Type *VoidPtrType = PointerType::get(Type::SByteTy);
// Update statistics
++ExactChecks;
//
// Cast the operands to the correct type.
//
Value * BasePointer = Source;
if (BasePointer->getType() != VoidPtrType)
BasePointer = new CastInst(BasePointer, VoidPtrType,
BasePointer->getName()+".ec3.base.casted",
InsertPt);
Value * ResultPointer = Result;
if (ResultPointer->getType() != VoidPtrType)
ResultPointer = new CastInst(Result, VoidPtrType,
Result->getName()+".ec3.result.casted",
InsertPt);
Value * CastBounds = Bounds;
if (Bounds->getType() != VoidPtrType)
CastBounds = new CastInst(Bounds, VoidPtrType,
Bounds->getName()+".ec3.end.casted", InsertPt);
std::vector<Value *> args(1, BasePointer);
args.push_back(ResultPointer);
args.push_back(CastBounds);
//
// Record that this value was checked.
//
CheckedValues.insert (Result);
return new CallInst(ExactCheck3, args, "ec3", InsertPt);
}
//
// Function: addExactCheck()
//
// Description:
// Utility routine that inserts a call to exactcheck(). This function can
// perform some optimization be determining if the arguments are constant.
// If they are, we can forego inserting the call.
//
// Inputs:
// Index - An LLVM Value representing the index of the access.
// Bounds - An LLVM Value representing the bounds of the check.
//
void
InsertPoolChecks::addExactCheck (Value * Pointer,
Value * Index, Value * Bounds,
Instruction * InsertPt) {
//
// Record that this value was checked.
//
CheckedValues.insert (Pointer);
//
// Attempt to determine statically if this check will always pass; if so,
// then don't bother doing it at run-time.
//
ConstantInt * CIndex = dyn_cast<ConstantInt>(Index);
ConstantInt * CBounds = dyn_cast<ConstantInt>(Bounds);
if (CIndex && CBounds) {
int index = CIndex->getSExtValue();
int bounds = CBounds->getSExtValue();
assert ((index >= 0) && "exactcheck: const negative index");
assert ((index < bounds) && "exactcheck: const out of range");
// Update stats and return
++ConstExactChecks;
return;
}
//
// Second, cast the operands to the correct type.
//
Value * CastIndex = Index;
if (Index->getType() != Type::IntTy)
CastIndex = new CastInst(Index, Type::IntTy,
Index->getName()+".ec.casted", InsertPt);
Value * CastBounds = Bounds;
if (Bounds->getType() != Type::IntTy)
CastBounds = new CastInst(Bounds, Type::IntTy,
Bounds->getName()+".ec.casted", InsertPt);
const Type *VoidPtrType = PointerType::get(Type::SByteTy);
Value * CastResult = Pointer;
if (CastResult->getType() != VoidPtrType)
CastResult = new CastInst(CastResult, VoidPtrType,
CastResult->getName()+".ec.casted", InsertPt);
std::vector<Value *> args(1, CastIndex);
args.push_back(CastBounds);
args.push_back(CastResult);
Instruction * CI = new CallInst(ExactCheck, args, "ec", InsertPt);
#if 0
//
// Replace the old index with the return value of exactcheck(); this
// prevents GCC from removing it completely.
//
Value * CastCI = CI;
if (CI->getType() != GEP->getType())
CastCI = new CastInst (CI, GEP->getType(), GEP->getName(), InsertPt);
Value::use_iterator UI = GEP->use_begin();
for (; UI != GEP->use_end(); ++UI) {
if (((*UI) != CI) && ((*UI) != CastResult))
UI->replaceUsesOfWith (GEP, CastCI);
}
#endif
// Update statistics
++ExactChecks;
return;
}
//
// Function: addExactCheck()
//
// Description:
// Utility routine that inserts a call to exactcheck(). This function can
// perform some optimization be determining if the arguments are constant.
// If they are, we can forego inserting the call.
//
// Inputs:
// GEP - The GEP for which the check will be done.
// Index - An LLVM Value representing the index of the access.
// Bounds - An LLVM Value representing the bounds of the check.
//
void
InsertPoolChecks::addExactCheck (Instruction * GEP,
Value * Index, Value * Bounds) {
//
// Record that this value was checked.
//
CheckedValues.insert (GEP);
// Upper and lower values on the index and bounds
int index_lower;
int index_upper;
int bounds_lower;
int bounds_upper;
//
// First, attempt to determine statically whether the check will always pass.
// If so, then don't bother doing it at run-time.
//
ConstantInt * CIndex = dyn_cast<ConstantInt>(Index);
ConstantInt * CBounds = dyn_cast<ConstantInt>(Bounds);
if (CIndex && CBounds) {
int index = CIndex->getSExtValue();
int bounds = CBounds->getSExtValue();
assert ((index >= 0) && "exactcheck: const negative index");
assert ((index < bounds) && "exactcheck: const out of range");
// Update stats and return
++ConstExactChecks;
return;
} else if (CBounds) {
int bounds = CBounds->getSExtValue();
SCEVHandle SCEVIndex = scevPass->getSCEV (Index);
ConstantRange IndexRange = SCEVIndex->getValueRange();
if (!(IndexRange.isWrappedSet())) {
int index_lower = IndexRange.getLower()->getSExtValue();
int index_upper = IndexRange.getUpper()->getSExtValue();
int bounds_lower = bounds;
int bounds_upper = bounds;
if ((index_lower >= 0) && (index_upper < bounds_lower)) {
++ConstExactChecks;
return;
}
}
}
SCEVHandle SCEVIndex = scevPass->getSCEV (Index);
SCEVHandle SCEVBounds = scevPass->getSCEV (Bounds);
ConstantRange BoundsRange = SCEVBounds->getValueRange();
ConstantRange IndexRange = SCEVIndex->getValueRange();
if ((!(IndexRange.isWrappedSet())) && (!(BoundsRange.isWrappedSet()))) {
int index_lower = IndexRange.getLower()->getSExtValue();
int index_upper = IndexRange.getUpper()->getSExtValue();
int bounds_lower = BoundsRange.getLower()->getSExtValue();
int bounds_upper = BoundsRange.getUpper()->getSExtValue();
if ((index_lower >= 0) && (index_upper < bounds_lower)) {
++ConstExactChecks;
return;
}
}
//
// Cast the operands to the correct type.
//
Instruction * InsertPt = GEP->getNext();
Value * CastIndex = Index;
if (Index->getType() != Type::IntTy)
CastIndex = new CastInst(Index, Type::IntTy,
Index->getName()+".ec.casted", InsertPt);
Value * CastBounds = Bounds;
if (Bounds->getType() != Type::IntTy)
CastBounds = new CastInst(Bounds, Type::IntTy,
Bounds->getName()+".ec.casted", InsertPt);
const Type *VoidPtrType = PointerType::get(Type::SByteTy);
Value * CastResult = GEP;
if (CastResult->getType() != VoidPtrType)
CastResult = new CastInst(CastResult, VoidPtrType,
CastResult->getName()+".ec.casted", InsertPt);
std::vector<Value *> args(1, CastIndex);
args.push_back(CastBounds);
args.push_back(CastResult);
Instruction * CI = new CallInst(ExactCheck, args, "ec", InsertPt);
//
// Replace the old index with the return value of exactcheck(); this
// prevents GCC from removing it completely.
//
#if 0
Value * CastCI = CI;
if (CI->getType() != GEP->getType())
CastCI = new CastInst (CI, GEP->getType(), GEP->getName(), InsertPt);
Value::use_iterator UI = GEP->use_begin();
for (; UI != GEP->use_end(); ++UI) {
if (((*UI) != CI) && ((*UI) != CastResult))
UI->replaceUsesOfWith (GEP, CastCI);
}
#endif
// Update statistics
++ExactChecks;
return;
}
//
// Function: isEligableForExactCheck()
//
// Return value:
// true - This value is eligable for an exactcheck.
// false - This value is not eligable for an exactcheck.
//
static inline bool
isEligableForExactCheck (Value * Pointer) {
if ((isa<AllocaInst>(Pointer)) || (isa<GlobalVariable>(Pointer)))
return true;
if (CallInst* CI = dyn_cast<CallInst>(Pointer)) {
if (CI->getCalledFunction() &&
(CI->getCalledFunction()->getName() == "__vmalloc" ||
CI->getCalledFunction()->getName() == "kmalloc")) {
return true;
}
}
return false;
}
//
// Function: findCheckedPointer()
//
// Description:
// Given a pointer value, attempt to determine whether the pointer or all of
// the instructions that created it have been checked.
//
bool
InsertPoolChecks::findCheckedPointer (Value * PointerOperand) {
Value * SourcePointer = PointerOperand;
while (CheckedValues.find (SourcePointer) == CheckedValues.end()) {
// Check for cast constant expressions and instructions
if (ConstantExpr * cExpr = dyn_cast<ConstantExpr>(SourcePointer)) {
if (cExpr->getOpcode() == Instruction::Cast) {
if (isa<PointerType>(cExpr->getOperand(0)->getType())) {
SourcePointer = cExpr->getOperand(0);
continue;
}
}
// We cannot handle this expression; break out of the loop
break;
}
if (CastInst * CastI = dyn_cast<CastInst>(SourcePointer)) {
if (isa<PointerType>(CastI->getOperand(0)->getType())) {
SourcePointer = CastI->getOperand(0);
continue;
}
break;
}
// We can't scan through any more instructions; give up
break;
}
//
// If the pointer is a GEP, then as long as it has a DSNode, it has been
// checked or proven safe.
//
Instruction * I;
if ((I = dyn_cast<GetElementPtrInst>(SourcePointer)) &&
(getDSNode (I, I->getParent()->getParent())) &&
(getPoolHandle(I, I->getParent()->getParent()))) {
return true;
}
#if 0
return (CheckedValues.find (SourcePointer) != CheckedValues.end());
#else
// Return false; check must dominate load/store.
return false;
#endif
}
//
// Function: findSourcePointer()
//
// Description:
// Given a pointer value, attempt to find a source of the pointer that can
// be used in an exactcheck().
//
// Outputs:
// indexed - Flags whether the data flow went through a indexing operation
// (i.e. a GEP). This value is always written.
//
static Value *
findSourcePointer (Value * PointerOperand, bool & indexed) {
//
// Attempt to look for the originally allocated object by scanning the data
// flow up.
//
indexed = false;
Value * SourcePointer = PointerOperand;
Value * OldSourcePointer = 0;
while (!isEligableForExactCheck (SourcePointer)) {
assert (OldSourcePointer != SourcePointer);
OldSourcePointer = SourcePointer;
// Check for GEP and cast constant expressions
if (ConstantExpr * cExpr = dyn_cast<ConstantExpr>(SourcePointer)) {
if ((cExpr->getOpcode() == Instruction::Cast) ||
(cExpr->getOpcode() == Instruction::GetElementPtr)) {
if (isa<PointerType>(cExpr->getOperand(0)->getType())) {
SourcePointer = cExpr->getOperand(0);
continue;
}
}
// We cannot handle this expression; break out of the loop
break;
}
// Check for GEP and cast instructions
if (GetElementPtrInst * G = dyn_cast<GetElementPtrInst>(SourcePointer)) {
SourcePointer = G->getPointerOperand();
indexed = true;
continue;
}
if (CastInst * CastI = dyn_cast<CastInst>(SourcePointer)) {
if (isa<PointerType>(CastI->getOperand(0)->getType())) {
SourcePointer = CastI->getOperand(0);
continue;
}
break;
}
// Check for call instructions to exact checks.
CallInst * CI1;
if ((CI1 = dyn_cast<CallInst>(SourcePointer)) &&
(CI1->getCalledFunction()) &&
(CI1->getCalledFunction()->getName() == "exactcheck3")) {
SourcePointer = CI1->getOperand (2);
continue;
}
// We can't scan through any more instructions; give up
break;
}
if (isEligableForExactCheck (SourcePointer))
PointerOperand = SourcePointer;
return PointerOperand;
}
//
// Function: insertExactCheck()
//
// Description:
// Attepts to insert an efficient, accurate array bounds check for the given
// GEP instruction; this check will not use Pools are MetaPools.
//
// Return value:
// true - An exactcheck() was successfully added.
// false - An exactcheck() could not be added; a more extensive check will be
// needed.
//
bool
InsertPoolChecks::insertExactCheck (GetElementPtrInst * GEP) {
// The GEP instruction casted to the correct type
Instruction *Casted = GEP;
// The pointer operand of the GEP expression
Value * PointerOperand = GEP->getPointerOperand();
//
// Get the DSNode for the instruction
//
Function *F = GEP->getParent()->getParent();
DSGraph & TDG = TDPass->getDSGraph(*F);
DSNode * Node = TDG.getNodeForValue(GEP).getNode();
assert (Node && "boundscheck: DSNode is NULL!");
//
// Determine whether an alignment check is needed. This occurs when a DSNode
// is type unknown (collapsed) but has pointers to type known (uncollapsed)
// DSNodes.
//
if (preSCPass->nodeNeedsAlignment (Node)) {
++AlignChecks;
}
#if 0
// Debugging: See if we're missing exactcheck opportunities
if (isa<SelectInst>(PointerOperand))
std::cerr << "LLVA: EC: Select Inst\n";
if (isa<GetElementPtrInst>(PointerOperand))
std::cerr << "LLVA: EC: GEP: In " << F->getName() << "\n";
CallInst * CI1;
if ((CI1 = dyn_cast<CallInst>(PointerOperand)) &&
(CI1->getCalledFunction()) &&
(CI1->getCalledFunction()->getName() == "exactcheck3"))
std::cerr << "LLVA: EC: GEP: Hidden by ec3: In " << F->getName() << "\n";
PHINode * PN = 0;
if (PN = dyn_cast<PHINode>(PointerOperand)) {
std::cerr << "LLVA: EC: PHI\n";
for (unsigned index = 0; index < PN->getNumIncomingValues(); ++index) {
std::cerr << "LLVA: " << *(PN->getIncomingValue(index)) << std::endl;
}
}
#endif
//
// Attempt to find the object which we need to check.
//
bool WasIndexed = true;
PointerOperand = findSourcePointer (PointerOperand, WasIndexed);
//
// Ensure the pointer operand really is a pointer.
//
if (!isa<PointerType>(PointerOperand->getType()))
return false;
if (GlobalVariable *GV = dyn_cast<GlobalVariable>(PointerOperand)) {
//
// Attempt to remove checks on GEPs that only index into structures.
// These criteria must be met:
// 1) The pool must be Type-Homogoneous.
//
#if 0
if ((!(Node->isNodeCompletelyFolded())) &&
(indexesStructsOnly (GEP))) {
++StructGEPsRemoved;
return true;
}
#endif
//
// Attempt to use a call to exactcheck() to check this value if it is a
// global array with a non-zero size. We do not check zero length arrays
// because in C they are often used to declare an external array of unknown
// size as follows:
// extern struct foo the_array[];
//
const ArrayType *AT = dyn_cast<ArrayType>(GV->getType()->getElementType());
if ((!WasIndexed) && AT && (AT->getNumElements())) {
// we need to insert an actual check
// It could be a select instruction
// First get the size
// This only works for one or two dimensional arrays
if (GEP->getNumOperands() == 2) {
Value *secOp = GEP->getOperand(1);
const Type* csiType = Type::getPrimitiveType(Type::IntTyID);
ConstantInt * Bounds = ConstantInt::get(csiType,AT->getNumElements());
addExactCheck (GEP, secOp, Bounds);
return true;
} else if (GEP->getNumOperands() == 3) {
if (ConstantInt *COP = dyn_cast<ConstantInt>(GEP->getOperand(1))) {
//FIXME assuming that the first array index is 0
assert((COP->getZExtValue() == 0) && "non zero array index\n");
Value * secOp = GEP->getOperand(2);
const Type* csiType = Type::getPrimitiveType(Type::IntTyID);
ConstantInt * Bounds = ConstantInt::get(csiType,AT->getNumElements());
addExactCheck (GEP, secOp, Bounds);
return true;
} else {
// TODO:
// Handle non constant index two dimensional arrays later
Value* Size=ConstantInt::get(Type::IntTy, TD->getTypeSize(GV->getType()));
addExactCheck2 (PointerOperand, GEP, Size, GEP->getNext());
return true;
}
} else {
// Handle Multi dimensional cases later
Value* AllocSize=ConstantInt::get(Type::IntTy, TD->getTypeSize(GV->getType()->getElementType()));
addExactCheck2 (PointerOperand, GEP, AllocSize, GEP->getNext());
return true;
GEP->dump();
++MissedMultDimArrayChecks;
}
DEBUG(std::cerr << " Global variable ok \n");
} else {
Value* Size=ConstantInt::get(Type::IntTy, TD->getTypeSize(GV->getType()));
addExactCheck2 (PointerOperand, GEP, Size, GEP->getNext());
return true;
}
}
//
// If the pointer was generated by a dominating alloca instruction, we can
// do an exactcheck on it, too.
//
if (AllocaInst *AI = dyn_cast<AllocaInst>(PointerOperand)) {
//
// Attempt to remove checks on GEPs that only index into structures.
// These criteria must be met:
// 1) The pool must be Type-Homogoneous.
//
#if 0
if ((!(Node->isNodeCompletelyFolded())) &&
(indexesStructsOnly (GEP))) {
++StructGEPsRemoved;
return true;
}
#endif
const Type * AllocaType = AI->getAllocatedType();
Value *AllocSize=ConstantInt::get(Type::IntTy, TD->getTypeSize(AllocaType));
if (AI->isArrayAllocation())
AllocSize = BinaryOperator::create(Instruction::Mul,
AllocSize,
AI->getOperand(0), "sizetmp", GEP);
addExactCheck2 (PointerOperand, GEP, AllocSize, GEP->getNext());
return true;
}
//
// If the pointer was an allocation, we should be able to do exact checks
//
if(CallInst* CI = dyn_cast<CallInst>(PointerOperand)) {
if (CI->getCalledFunction() &&
(CI->getCalledFunction()->getName() == "__vmalloc" ||
CI->getCalledFunction()->getName() == "kmalloc")) {
//
// Attempt to remove checks on GEPs that only index into structures.
// These criteria must be met:
// 1) The pool must be Type-Homogoneous.
//
#if 0
if ((!(Node->isNodeCompletelyFolded())) &&
(indexesStructsOnly (GEP))) {
++StructGEPsRemoved;
return true;
}
#endif
Value* Cast = new CastInst(CI->getOperand(1), Type::IntTy, "", GEP);
addExactCheck2(PointerOperand, GEP, Cast, GEP->getNext());
return true;
}
}
//
// If the pointer is to a structure, we may be able to perform a simple
// exactcheck on it, too, unless the array is at the end of the structure.
// Then, we assume it's a variable length array and must be full checked.
//
#if 0
if (const PointerType * PT = dyn_cast<PointerType>(PointerOperand->getType()))
if (const StructType *ST = dyn_cast<StructType>(PT->getElementType())) {
const Type * CurrentType = ST;
ConstantInt * C;
for (unsigned index = 2; index < GEP->getNumOperands() - 1; ++index) {
//
// If this GEP operand is a constant, index down into the next type.
//
if (C = dyn_cast<ConstantInt>(GEP->getOperand(index))) {
if (const StructType * ST2 = dyn_cast<StructType>(CurrentType)) {
CurrentType = ST2->getElementType(C->getZExtValue());
continue;
}
if (const ArrayType * AT = dyn_cast<ArrayType>(CurrentType)) {
CurrentType = AT->getElementType();
continue;
}
// We don't know how to handle this type of element
break;
}
//
// If the GEP operand is not constant and points to an array type,
// then try to insert an exactcheck().
//
const ArrayType * AT;
if ((AT = dyn_cast<ArrayType>(CurrentType)) && (AT->getNumElements())) {
const Type* csiType = Type::getPrimitiveType(Type::IntTyID);
ConstantInt * Bounds = ConstantInt::get(csiType,AT->getNumElements());
addExactCheck (GEP, GEP->getOperand (index), Bounds);
return true;
}
}
}
#endif
/*
* We were not able to insert a call to exactcheck().
*/
return false;
}
//
// Function: insertExactCheck()
//
// Description:
// Attepts to insert an efficient, accurate array bounds check for the given
// GEP instruction; this check will not use Pools are MetaPools.
//
// Inputs:
// I - The instruction for which we are adding the check.
// Src - The pointer that needs to be checked.
// Size - The size, in bytes, that will be read/written by instruction I.
// InsertPt - The instruction before which the check should be inserted.
//
// Return value:
// true - An exactcheck() was successfully added.
// false - An exactcheck() could not be added; a more extensive check will be
// needed.
//
bool
InsertPoolChecks::insertExactCheck (Instruction * I,
Value * Src,
Value * Size,
Instruction * InsertPt) {
// The pointer operand of the GEP expression
Value * PointerOperand = Src;
//
// Get the DSNode for the instruction
//
#if 1
Function *F = I->getParent()->getParent();
DSGraph & TDG = TDPass->getDSGraph(*F);
DSNode * Node = TDG.getNodeForValue(I).getNode();
if (!Node)
return false;
#endif
//
// Determine whether an alignment check is needed. This occurs when a DSNode
// is type unknown (collapsed) but has pointers to type known (uncollapsed)
// DSNodes.
//
if (preSCPass->nodeNeedsAlignment (Node)) {
++AlignChecks;
}
//
// Attempt to find the original object for which this check applies.
// This involves unpeeling casts, GEPs, etc.
//
bool WasIndexed = true;
PointerOperand = findSourcePointer (PointerOperand, WasIndexed);
//
// Ensure the pointer operand really is a pointer.
//
if (!isa<PointerType>(PointerOperand->getType()))
{
return false;
}
//
// Attempt to use a call to exactcheck() to check this value if it is a
// global array with a non-zero size. We do not check zero length arrays
// because in C they are often used to declare an external array of unknown
// size as follows:
// extern struct foo the_array[];
//
if (GlobalVariable *GV = dyn_cast<GlobalVariable>(PointerOperand)) {
const Type* csiType = Type::getPrimitiveType(Type::IntTyID);
unsigned int arraysize = TD->getTypeSize(GV->getType()->getElementType());
ConstantInt * Bounds = ConstantInt::get(csiType, arraysize);
if (WasIndexed)
addExactCheck2 (PointerOperand, Src, Bounds, InsertPt);
else
addExactCheck (Src, Size, Bounds, InsertPt);
return true;
}
//
// If the pointer was generated by a dominating alloca instruction, we can
// do an exactcheck on it, too.
//
if (AllocaInst *AI = dyn_cast<AllocaInst>(PointerOperand)) {
const Type * AllocaType = AI->getAllocatedType();
Value *AllocSize=ConstantInt::get(Type::IntTy, TD->getTypeSize(AllocaType));
if (AI->isArrayAllocation())
AllocSize = BinaryOperator::create(Instruction::Mul,
AllocSize,
AI->getOperand(0), "allocsize", InsertPt);
if (WasIndexed)
addExactCheck2 (PointerOperand, Src, AllocSize, InsertPt);
else
addExactCheck (Src, Size, AllocSize, InsertPt);
return true;
}
//
// If the pointer was an allocation, we should be able to do exact checks
//
if(CallInst* CI = dyn_cast<CallInst>(PointerOperand)) {
if (CI->getCalledFunction() && (
CI->getCalledFunction()->getName() == "__vmalloc" ||
CI->getCalledFunction()->getName() == "kmalloc")) {
Value* Cast = new CastInst(CI->getOperand(1), Type::IntTy, "allocsize", InsertPt);
if (WasIndexed)
addExactCheck2 (PointerOperand, Src, Cast, InsertPt);
else
addExactCheck (Src, Size, Cast, InsertPt);
return true;
}
}
//
// We were not able to insert a call to exactcheck().
//
return false;
}
bool
InsertPoolChecks::doInitialization (Module & M) {
// Add the new poolcheck prototype
addPoolCheckProto (M);
return true;
}
bool
InsertPoolChecks::doFinalization (Module & M) {
// Insert code to register heap allocations with the correct MetaPool
// and to register kernel pools with the correct MetaPool
addHeapRegs (M);
// Insert code to drop objects from MetaPools when they are freed by the
// kernel allocators
addObjFrees (M);
return true;
}
bool
InsertPoolChecks::runOnFunction (Function & F) {
//
// Retrieve references to all of the passes from which we will gather
// information.
//
preSCPass = &getAnalysis<PreInsertPoolChecks>();
cuaPass = &getAnalysis<ConvertUnsafeAllocas>();
TD = &getAnalysis<TargetData>();
scevPass = &getAnalysis<ScalarEvolution>();
LI = &getAnalysis<LoopInfo>();
#ifdef LLVA_KERNEL
TDPass = &getAnalysis<TDDataStructures>();
#else
paPass = &getAnalysis<PoolAllocate>();
equivPass = &(paPass->getECGraphs());
efPass = &getAnalysis<EmbeCFreeRemoval>();
TD = &getAnalysis<TargetData>();
#endif
#if 1
// Transform the function
if (!(F.isExternal())) TransformFunction (F);
if (!DisableLSChecks) addLoadStoreChecks(F);
#endif
//
// Update the statistics.
//
PoolChecks = NullChecks + FullChecks;
return true;
}
void InsertPoolChecks::handleCallInst(CallInst *CI) {
//
// Determine if this is an indirect call. If so, insert a run-time check for
// it.
//
if (!(CI->getCalledFunction()))
insertFunctionCheck (CI);
//
// Check for intrinsic functions and add checks as necessary.
//
if (CI && (!DisableIntrinsicChecks)) {
Value *Fop = CI->getOperand(0);
Function *F = CI->getParent()->getParent();
#ifdef LLVA_KERNEL
std::string FuncName = Fop->getName();
if ((FuncName == "llvm.memcpy.i32") ||
(FuncName == "llvm.memcpy.i64") ||
(FuncName == "llvm.memset.i32") ||
(FuncName == "llvm.memset.i64") ||
(FuncName == "llvm.memmove.i32") ||
(FuncName == "llvm.memmove.i64") ||
(FuncName == "llva_memcpy") ||
(FuncName == "llva_memset") ||
(FuncName == "llva_strncpy") ||
(FuncName == "llva_invokememcpy") ||
(FuncName == "llva_invokestrncpy") ||
(FuncName == "llva_invokememset") ||
(FuncName == "memcmp")) {
//
// Create a call to an accurate bounds check for each string parameter.
//
Instruction *InsertPt = CI;
Value * CastPointer1 = castTo (CI->getOperand(1), Type::UIntTy, InsertPt);
Value * CastPointer2 = castTo (CI->getOperand(2), Type::UIntTy, InsertPt);
Value * CastCIOp3 = castTo (CI->getOperand(3), Type::UIntTy, InsertPt);
Instruction *Bop1 = BinaryOperator::create(Instruction::Add, CastPointer1,
CastCIOp3, "mcadd",InsertPt);
Instruction *Bop2 = BinaryOperator::create(Instruction::Add, CastPointer2,
CastCIOp3, "mcadd",InsertPt);
Instruction *Finalp1 = BinaryOperator::create(Instruction::Sub, Bop1,
ConstantInt::get (Type::UIntTy, 1), "mcsub",InsertPt);
Instruction *Finalp2 = BinaryOperator::create(Instruction::Sub, Bop2,
ConstantInt::get (Type::UIntTy, 1), "mcsub",InsertPt);
Instruction *Length = BinaryOperator::create(Instruction::Sub, CastCIOp3,
ConstantInt::get (Type::UIntTy, 1), "mclen",InsertPt);
AddedValues.insert(CastPointer1);
AddedValues.insert(CastPointer2);
AddedValues.insert(CastCIOp3);
AddedValues.insert(Bop1);
AddedValues.insert(Bop2);
AddedValues.insert(Finalp1);
AddedValues.insert(Finalp2);
AddedValues.insert(Length);
// Create the call to do an accurate bounds check
if (!insertExactCheck(CI, CI->getOperand(1), Length, InsertPt))
insertBoundsCheck (CI, CI->getOperand(1), Bop1, InsertPt);
if (!insertExactCheck(CI, CI->getOperand(2), Length, InsertPt))
insertBoundsCheck (CI, CI->getOperand(2), Bop2, InsertPt);
#if 0
} else if ((FuncName == "llva_load_integer") ||
(FuncName == "llva_save_integer") ||
(FuncName == "llva_load_integer_stackp") ||
(FuncName == "llva_save_integer_stackp") ||
(FuncName == "llva_push_function1")) {
//
// Create a call to an accurate bounds check for the integer state
// pointer.
//
Instruction *InsertPt = CI;
Value * CastPointer1 = castTo (CI->getOperand(1), Type::UIntTy, InsertPt);
Value * CastLength = ConstantInt::get (Type::UIntTy, LLVA_INTEGERSTATE_SIZE);
Instruction *Bop1 = BinaryOperator::create(Instruction::Add, CastPointer1,
CastLength, "mcadd",InsertPt);
Value *Length = ConstantInt::get (Type::UIntTy, LLVA_INTEGERSTATE_SIZE - 1);
// Create the call to do an accurate bounds check
if (!insertExactCheck(CI, CI->getOperand(1), Length, InsertPt))
insertBoundsCheck (CI, CI->getOperand(1), Bop1, InsertPt);
} else if ((FuncName == "llva_load_icontext") ||
(FuncName == "llva_save_icontext")) {
//
// Perform a check on the interrupt context.
//
Instruction *InsertPt = CI;
insertICCheck (CI->getOperand(1), InsertPt);
//
// Create a call to an accurate bounds check for the integer state.
//
Value * CastPointer1 = castTo (CI->getOperand(2), Type::UIntTy, InsertPt);
Value * CastLength = ConstantInt::get (Type::UIntTy, LLVA_ICONTEXT_SIZE);
Instruction *Bop1 = BinaryOperator::create(Instruction::Add, CastPointer1,
CastLength, "mcadd",InsertPt);
Value *Length = ConstantInt::get (Type::UIntTy, LLVA_ICONTEXT_SIZE - 1);
// Create the call to do an accurate bounds check
if (!insertExactCheck(CI, CI->getOperand(2), Length, InsertPt))
insertBoundsCheck (CI, CI->getOperand(1), Bop1, InsertPt);
} else if ((FuncName == "llva_load_fp") || (FuncName == "llva_save_fp")) {
//
// Create a call to an accurate bounds check for the FP state
// pointer.
//
Instruction *InsertPt = CI;
Value * CastPointer1 = castTo (CI->getOperand(1), Type::UIntTy, InsertPt);
Value * CastLength = ConstantInt::get (Type::UIntTy, LLVA_FPSTATE_SIZE);
Instruction *Bop1 = BinaryOperator::create(Instruction::Add, CastPointer1,
CastLength, "mcadd",InsertPt);
Value *Length = ConstantInt::get (Type::UIntTy, LLVA_FPSTATE_SIZE - 1);
// Create the call to do an accurate bounds check
if (!insertExactCheck(CI, CI->getOperand(1), Length, InsertPt))
insertBoundsCheck (CI, CI->getOperand(1), Bop1, InsertPt);
} else if (FuncName == "llva_push_syscall") {
//
// Create a call to an accurate bounds check for the interrupt context
// pointer.
//
Instruction *InsertPt = CI;
Value * CastPointer1 = castTo (CI->getOperand(2), Type::UIntTy, InsertPt);
Value * CastLength = ConstantInt::get (Type::UIntTy, LLVA_ICONTEXT_SIZE);
Instruction *Bop1 = BinaryOperator::create(Instruction::Add, CastPointer1,
CastLength, "mcadd",InsertPt);
Value *Length = ConstantInt::get (Type::UIntTy, LLVA_ICONTEXT_SIZE - 1);
// Create the call to do an accurate bounds check
if (!insertExactCheck(CI, CI->getOperand(1), Length, InsertPt))
insertBoundsCheck (CI, CI->getOperand(1), Bop1, InsertPt);
} else if ((FuncName == "llva_init_icontext") ||
(FuncName == "llva_clear_icontext") ||
(FuncName == "llva_was_privileged") ||
(FuncName == "llva_icontext_lif") ||
(FuncName == "llva_ipop_function0") ||
(FuncName == "llva_ipush_function0") ||
(FuncName == "llva_ipush_function1") ||
(FuncName == "llva_ipush_function3") ||
(FuncName == "llva_ialloca") ||
(FuncName == "llva_unwind") ||
(FuncName == "llva_icontext_load_retvalue") ||
(FuncName == "llva_icontext_save_retvalue") ||
(FuncName == "llva_get_icontext_stackp") ||
(FuncName == "llva_set_icontext_stackp") ||
(FuncName == "llva_iset_privileged")) {
//
// Create a call to an accurate bounds check for the interrupt context
// pointer.
//
Instruction *InsertPt = CI;
insertICCheck (CI->getOperand(1), InsertPt);
#endif
}
#endif
}
}
void InsertPoolChecks::simplifyGEPList() {
#if 0
std::set<Instruction *> & UnsafeGetElemPtrs = cuaPass->getUnsafeGetElementPtrsFromABC();
std::map< std::pair<Value*, BasicBlock*>, std::set<Instruction*> > m;
for (std::set<Instruction *>::iterator ii = UnsafeGetElemPtrs.begin(), ee = UnsafeGetElemPtrs.end();
ii != ee; ++ii) {
GetElementPtrInst* GEP = cast<GetElementPtrInst>(*ii);
m[std::make_pair(GEP->getOperand(0), GEP->getParent())].insert(GEP);
}
unsigned singletons;
unsigned multi;
for (std::map< std::pair<Value*,BasicBlock*>, std::set<Instruction*> >::iterator ii = m.begin(), ee = m.end();
ii != ee; ++ii) {
if (ii->second.size() > 1) {
std::cerr << "##############\n";
for (std::set<Instruction *>::iterator i = ii->second.begin(), e = ii->second.end();
i != e; ++i) {
(*i)->dump();
}
std::cerr << "##############\n";
++multi;
} else
++singletons;
}
std::cerr << "Singletons: " << singletons << " Multitons: " << multi << "\n";
#endif
}
//
// Function: compatibleGEPs()
//
// Description:
// Determine whether two GEPs address the same memory and have the (save the
// for last) same arguments.
//
// Return value:
// true - All arguments (except possibly the last) are identical.
// false - One or more arguments besides the last argument are different.
//
static inline bool
identicalGEPs (GetElementPtrInst * GEP1, GetElementPtrInst * GEP2) {
if (GEP1->getPointerOperand() != GEP2->getPointerOperand()) return false;
if (GEP1->getNumOperands() != GEP2->getNumOperands()) return false;
for (unsigned index = 0; index < GEP1->getNumOperands() - 1; ++index) {
if (GEP1->getOperand(index) != GEP2->getOperand(index)) {
return false;
break;
}
}
return true;
}
bool
InsertPoolChecks::AggregateGEPs (GetElementPtrInst * MAI,
std::set<Instruction *> & RelatedGEPs) {
// Get the set of unsafe GEPs for this instruction's basic block
std::set<Instruction *> * UnsafeGetElemPtrs = cuaPass->getUnsafeGetElementPtrsFromABC(MAI->getParent());
if (!UnsafeGetElemPtrs) {
RelatedGEPs.insert (MAI);
return true;
}
// If this GEP has already been deemed safe, then return;
std::set<Instruction *>::const_iterator iCurrent = UnsafeGetElemPtrs->find(MAI);
if (iCurrent == UnsafeGetElemPtrs->end()) {
return true;
}
// Determine whether the GEP has a constant as its last index.
// If so, search for all other GEPs that have, save for the last index,
// identical operands. Then select the two with the higest and lowest
// indices; we will perform our run-time checks on these.
std::set<Instruction *>::iterator UGI = UnsafeGetElemPtrs->begin(),
UGE = UnsafeGetElemPtrs->end();
Instruction * MinGEP = MAI;
Instruction * MaxGEP = MAI;
if (isa<ConstantInt>(MAI->getOperand((MAI->getNumOperands() - 1)))) {
for (;UGI != UGE; ++UGI) {
Instruction * I = *UGI;
GetElementPtrInst * GEP = dyn_cast<GetElementPtrInst>(I);
if (!GEP) continue;
if (!(isa<ConstantInt>(GEP->getOperand((GEP->getNumOperands() - 1))))) continue;
if (identicalGEPs (GEP, MAI)) {
ConstantInt * GEPLastIndex;
ConstantInt * MinLastIndex;
ConstantInt * MaxLastIndex;
GEPLastIndex = dyn_cast<ConstantInt>(GEP->getOperand(GEP->getNumOperands() - 1));
MinLastIndex = dyn_cast<ConstantInt>(MinGEP->getOperand(MinGEP->getNumOperands() - 1));
MaxLastIndex = dyn_cast<ConstantInt>(MaxGEP->getOperand(MaxGEP->getNumOperands() - 1));
if (GEPLastIndex->getSExtValue() < MinLastIndex->getSExtValue()) {
UnsafeGetElemPtrs->erase (MinGEP);
MinGEP = GEP;
}
if (GEPLastIndex->getSExtValue() > MaxLastIndex->getSExtValue()) {
UnsafeGetElemPtrs->erase (MaxGEP);
MaxGEP = GEP;
}
}
}
//
// Find the first compatible GEP in the basic block.
//
Instruction * Ins = MAI->getParent()->getFirstNonPHI();
GetElementPtrInst * FirstGEP = 0;
while (!(Ins->isTerminator())) {
if (FirstGEP = dyn_cast<GetElementPtrInst>(Ins)) {
if (identicalGEPs (MAI, FirstGEP))
break;
}
Ins = Ins->getNext();
}
//
// Move the minimum and maximum GEPs to before the first identical GEP.
//
if (FirstGEP != MinGEP) {
MinGEP->moveBefore (FirstGEP);
}
if (FirstGEP != MaxGEP) {
MaxGEP->moveBefore (FirstGEP);
}
}
RelatedGEPs.insert (MinGEP);
if (MinGEP != MaxGEP) RelatedGEPs.insert (MaxGEP);
return true;
}
void InsertPoolChecks::handleGetElementPtr(GetElementPtrInst *MAI) {
// Get the set of unsafe GEP instructions from the array bounds check pass
// If this instruction is not within that set, then the result of the GEP
// instruction has been proven safe, and there is no need to insert a check.
std::set<Instruction *> * UnsafeGetElemPtrs = cuaPass->getUnsafeGetElementPtrsFromABC(MAI->getParent());
if (!UnsafeGetElemPtrs) return;
std::set<Instruction *>::const_iterator iCurrent = UnsafeGetElemPtrs->find(MAI);
if (iCurrent == UnsafeGetElemPtrs->end()) {
#if 0
std::cerr << "statically proved safe : Not inserting checks " << *MAI << "\n";
#endif
return;
}
#if 0
// Find all unsafe GEPs within the basic block that are identical save for
// their last index
std::set<Instruction *> RelatedGEPs;
std::set<Instruction *>::iterator UGI = UnsafeGetElemPtrs->begin(),
UGE = UnsafeGetElemPtrs->end();
if (isa<ConstantInt>(MAI->getOperand((MAI->getNumOperands() - 1))))
for (;UGI != UGE; ++UGI) {
Instruction * I = *UGI;
GetElementPtrInst * GEP = dyn_cast<GetElementPtrInst>(I);
if (!GEP) continue;
if (GEP->getPointerOperand() != MAI->getPointerOperand()) continue;
if (GEP->getNumOperands() != MAI->getNumOperands()) continue;
if (!(isa<ConstantInt>(GEP->getOperand((GEP->getNumOperands() - 1))))) continue;
bool identical = true;
for (unsigned index = 0; index < GEP->getNumOperands() - 1; ++index) {
if (GEP->getOperand(index) != MAI->getOperand(index)) {
identical = false;
break;
}
}
if (identical)
RelatedGEPs.insert (GEP);
}
std::cerr << "LLVA: RelatedGEP: " << RelatedGEPs.size() << std::endl;
#endif
if (InsertPoolChecksForArrays) {
Function *F = MAI->getParent()->getParent();
GetElementPtrInst *GEP = MAI;
// Now we need to decide if we need to pass in the alignmnet
//for the poolcheck
// if (getDSNodeOffset(GEP->getPointerOperand(), F)) {
// std::cerr << " we don't handle middle of structs yet\n";
//assert(!getDSNodeOffset(GEP->getPointerOperand(), F) && " we don't handle middle of structs yet\n");
// ++MissChecks;
// continue;
// }
#ifndef LLVA_KERNEL
PA::FuncInfo *FI = paPass->getFuncInfoOrClone(*F);
Instruction *Casted = GEP;
if (!FI->ValueMap.empty()) {
assert(FI->ValueMap.count(GEP) && "Instruction not in the value map \n");
Instruction *temp = dyn_cast<Instruction>(FI->ValueMap[GEP]);
assert(temp && " Instruction not there in the Value map");
Casted = temp;
}
if (GetElementPtrInst *GEPNew = dyn_cast<GetElementPtrInst>(Casted)) {
Value *PH = getPoolHandle(GEP, F, *FI);
if (PH && isa<ConstantPointerNull>(PH)) return;
if (!PH) {
Value *PointerOperand = GEPNew->getPointerOperand();
if (ConstantExpr *cExpr = dyn_cast<ConstantExpr>(PointerOperand)) {
if (cExpr->getOpcode() == Instruction::Cast)
PointerOperand = cExpr->getOperand(0);
}
if (GlobalVariable *GV = dyn_cast<GlobalVariable>(PointerOperand)) {
if (const ArrayType *AT = dyn_cast<ArrayType>(GV->getType()->getElementType())) {
// We need to insert an actual check. It could be a select
// instruction.
// First get the size.
// This only works for one or two dimensional arrays.
if (GEPNew->getNumOperands() == 2) {
Value *secOp = GEPNew->getOperand(1);
if (secOp->getType() != Type::IntTy) {
secOp = new CastInst(secOp, Type::IntTy,
secOp->getName()+".ec.casted", Casted);
}
const Type* csiType = Type::getPrimitiveType(Type::IntTyID);
std::vector<Value *> args(1,secOp);
args.push_back(ConstantInt::get(csiType,AT->getNumElements()));
new CallInst(ExactCheck,args,"", Casted);
DEBUG(std::cerr << "Inserted exact check call Instruction \n");
return;
} else if (GEPNew->getNumOperands() == 3) {
if (ConstantInt *COP = dyn_cast<ConstantInt>(GEPNew->getOperand(1))) {
// FIXME: assuming that the first array index is 0
assert((COP->getZExtValue() == 0) && "non zero array index\n");
Value * secOp = GEPNew->getOperand(2);
if (secOp->getType() != Type::IntTy) {
secOp = new CastInst(secOp, Type::IntTy,
secOp->getName()+".ec2.casted", Casted);
}
std::vector<Value *> args(1,secOp);
const Type* csiType = Type::getPrimitiveType(Type::IntTyID);
args.push_back(ConstantInt::get(csiType,AT->getNumElements()));
new CallInst(ExactCheck, args, "", Casted->getNext());
return;
} else {
// Handle non constant index two dimensional arrays later
abort();
}
} else {
// Handle Multi dimensional cases later
DEBUG(std::cerr << "WARNING: Handle multi dimensional globals later\n");
(*iCurrent)->dump();
}
}
DEBUG(std::cerr << " Global variable ok \n");
}
// These must be real unknowns and they will be handled anyway
// std::cerr << " WARNING, DID NOT HANDLE \n";
// (*iCurrent)->dump();
return;
} else {
if (Casted->getType() != PointerType::get(Type::SByteTy)) {
Casted = new CastInst(Casted,PointerType::get(Type::SByteTy),
(Casted)->getName()+".pc.casted",
(Casted)->getNext());
}
std::vector<Value *> args(1, PH);
args.push_back(Casted);
// Insert it
new CallInst(PoolCheck,args, "",Casted->getNext());
DEBUG(std::cerr << "inserted instrcution \n");
}
}
#else
//
// Get the pool handle associated with the pointer operand.
//
Value *PH = getPoolHandle(GEP->getPointerOperand(), F);
GetElementPtrInst *GEPNew = GEP;
Instruction *Casted = GEP;
DSGraph & TDG = TDPass->getDSGraph(*F);
DSNode * Node = TDG.getNodeForValue(GEP).getNode();
DEBUG(std::cerr << "LLVA: addGEPChecks: Pool " << PH << " Node ");
DEBUG(std::cerr << Node << std::endl);
Value *PointerOperand = GEPNew->getPointerOperand();
if (ConstantExpr *cExpr = dyn_cast<ConstantExpr>(PointerOperand)) {
if (cExpr->getOpcode() == Instruction::Cast)
PointerOperand = cExpr->getOperand(0);
}
if (GlobalVariable *GV = dyn_cast<GlobalVariable>(PointerOperand)) {
if (const ArrayType *AT = dyn_cast<ArrayType>(GV->getType()->getElementType())) {
// we need to insert an actual check
// It could be a select instruction
// First get the size
// This only works for one or two dimensional arrays
if (GEPNew->getNumOperands() == 2) {
Value *secOp = GEPNew->getOperand(1);
#ifdef LLVA_KERNEL
//
// Determine whether the exactcheck() will have constant integer
// arguments. If so, then we can evaluate them statically and avoid
// inserting the run-time check.
//
if (ConstantInt * Index = dyn_cast<ConstantInt>(secOp)) {
int index = Index->getSExtValue();
assert ((index < 0) && "exactcheck will fail at runtime");
if (index < AT->getNumElements())
return;
assert (0 && "exactcheck out of range");
}
#endif
if (secOp->getType() != Type::IntTy) {
secOp = new CastInst(secOp, Type::IntTy,
secOp->getName()+".ec3.casted", Casted);
}
std::vector<Value *> args(1,secOp);
const Type* csiType = Type::getPrimitiveType(Type::IntTyID);
args.push_back(ConstantInt::get(csiType,AT->getNumElements()));
new CallInst(ExactCheck,args,"", Casted);
// DEBUG(std::cerr << "Inserted exact check call Instruction \n");
return;
} else if (GEPNew->getNumOperands() == 3) {
if (ConstantInt *COP = dyn_cast<ConstantInt>(GEPNew->getOperand(1))) {
//FIXME assuming that the first array index is 0
assert((COP->getZExtValue() == 0) && "non zero array index\n");
Value * secOp = GEPNew->getOperand(2);
#ifdef LLVA_KERNEL
//
// Determine whether the exactcheck() will have constant integer
// arguments. If so, then we can evaluate them statically and avoid
// inserting the run-time check.
//
if (ConstantInt * Index = dyn_cast<ConstantInt>(secOp)) {
int index = Index->getSExtValue();
assert ((index < 0) && "exactcheck will fail at runtime");
if (index < AT->getNumElements())
return;
assert (0 && "exactcheck out of range");
}
#endif
if (secOp->getType() != Type::IntTy) {
secOp = new CastInst(secOp, Type::IntTy,
secOp->getName()+".ec4.casted", Casted);
}
std::vector<Value *> args(1,secOp);
const Type* csiType = Type::getPrimitiveType(Type::IntTyID);
args.push_back(ConstantInt::get(csiType,AT->getNumElements()));
new CallInst(ExactCheck,args,"", Casted->getNext());
return;
} else {
//Handle non constant index two dimensional arrays later
abort();
}
} else {
//Handle Multi dimensional cases later
std::cerr << "WARNING: Handle multi dimensional globals later\n";
(*iCurrent)->dump();
++MissedMultDimArrayChecks;
}
DEBUG(std::cerr << " Global variable ok \n");
}
}
//
// We cannot insert an exactcheck(). Insert a pool check.
//
//
if (!PH) {
#if 0
std::cerr << "missing a GEP check for" << *MAI << "alloca case?\n";
#endif
++NullChecks;
if (!PH) ++MissedNullChecks;
// Don't bother to insert the NULL check unless the user asked
if (!EnableNullChecks)
return;
PH = Constant::getNullValue(PointerType::get(Type::SByteTy));
} else {
assert ((isa<GlobalValue>(PH)) && "MetaPool Handle is not a global!");
}
//
// If this is a complete node, insert a poolcheck.
// If this is an icomplete node, insert a poolcheckarray.
//
Instruction *InsertPt = Casted->getNext();
if (Casted->getType() != PointerType::get(Type::SByteTy)) {
Casted = new CastInst(Casted,PointerType::get(Type::SByteTy),
(Casted)->getName()+".pc2.casted",InsertPt);
}
Instruction *CastedPointerOperand = new CastInst(PointerOperand,
PointerType::get(Type::SByteTy),
PointerOperand->getName()+".casted",InsertPt);
Instruction *CastedPH = new CastInst(PH,
PointerType::get(Type::SByteTy),
"ph",InsertPt);
if (Node->isIncomplete()) {
std::vector<Value *> args(1, CastedPH);
args.push_back(CastedPointerOperand);
args.push_back(Casted);
CallInst(PoolCheckArray,args, "",InsertPt);
} else {
std::vector<Value *> args(1, CastedPH);
args.push_back(Casted);
new CallInst(PoolCheck,args, "",InsertPt);
}
#endif
} else {
// Insert accurate bounds checks for arrays (as opposed to poolchecks)
//
// Attempt to insert a standard exactcheck() call for the GEP.
//
if (insertExactCheck (MAI))
return;
//Exact poolchecks
if (const PointerType *PT = dyn_cast<PointerType>(MAI->getPointerOperand()->getType())) {
#if 0
if (const StructType *ST = dyn_cast<StructType>(PT->getElementType())) {
#else
const StructType *ST = dyn_cast<StructType>(PT->getElementType());
if (0) {
#endif
//It is a struct type with pointers
//for each pointer with struct typ
//we need to watchg out for arrays inside structs
if (ConstantInt *COP = dyn_cast<ConstantInt>(MAI->getOperand(1))) {
//FIXME assuming that the first index is safe
//assert((COP->getRawValue() == 0) && "non zero array index\n");
bool allconstant = true;
for (unsigned i = 2; i < MAI->getNumOperands(); ++i) {
if (!isa<Constant>(MAI->getOperand(i))) {
allconstant = false;
break;
}
}
if (!allconstant) {
if (MAI->getNumOperands() == 4) {
if (ConstantInt *COPi = dyn_cast<ConstantInt>(MAI->getOperand(2))) {
const Type *stel = ST->getElementType(COPi->getZExtValue());
if (const ArrayType *elAT = dyn_cast<ArrayType>(stel)) {
//Need to factor this in to separate method!!!
Value * secOp = MAI->getOperand(3);
Value *indexTypeSize = ConstantInt::get(Type::UIntTy, TD->getTypeSize(secOp->getType()));
#ifdef LLVA_KERNEL
//
// Determine whether the exactcheck() will have constant integer
// arguments. If so, then we can evaluate them statically and avoid
// inserting the run-time check.
//
if (ConstantInt * Index = dyn_cast<ConstantInt>(secOp)) {
int index = Index->getSExtValue();
assert ((index < 0) && "exactcheck will fail at runtime");
if (index < TD->getTypeSize(elAT))
return;
assert (0 && "exactcheck out of range");
}
#endif
if (secOp->getType() != Type::IntTy) {
secOp = new CastInst(secOp, Type::IntTy,
secOp->getName()+".casted", MAI);
}
// secOp = BinaryOperator::create(Instruction::Mul, indexTypeSize, secOp,"indextmp", MAI);
std::vector<Value *> args(1,secOp);
Value *AllocSize =
ConstantInt::get(Type::IntTy, TD->getTypeSize(elAT));
/*
if (AI->isArrayAllocation())
AllocSize = BinaryOperator::create(Instruction::Mul,
AllocSize,
AI->getOperand(0), "sizetmp", MAI);
*/
// args.push_back(ConstantInt::get(csiType,elAT->getNumElements()));
args.push_back(AllocSize);
new CallInst(ExactCheck,args,"",MAI);
} else {
//non array, non constant value
abort();
}
} else {
// non-constant value, not possible
abort();
}
} else {
#if 0
//FIXME this is a less precise check than possible
// std::cerr << "WARNING : did not handle array within a struct precisely, num operands != 4\n";
Instruction *InsertPt = MAI->getNext();
Type *VoidPtrType = PointerType::get(Type::SByteTy);
Value *MAIPSbyte = new CastInst(MAI->getPointerOperand(),
VoidPtrType,
MAI->getPointerOperand()->getName()+".casted",InsertPt);
Value *MAISbyte = new CastInst(MAI,
VoidPtrType,
MAI->getName()+".casted",InsertPt);
std::vector<Value *> args(1,MAIPSbyte);
args.push_back(MAISbyte);
Value *AllocSize =
ConstantInt::get(Type::UIntTy, TD->getTypeSize(ST));
args.push_back(AllocSize);
new CallInst(ExactCheck2,args,"",InsertPt);
#endif
}
} else {
std::cerr << "Not all args constant: " << *MAI << std::endl;
}
} else {
std::cerr << "HandleLikeArray: " << *MAI << std::endl;
goto HandleThisLikeArray;
}
} else {
HandleThisLikeArray:
if (AllocaInst *AI = dyn_cast<AllocaInst>(MAI->getPointerOperand())) {
//we can put an exact check here
if (1 || (MAI->getNumOperands() == 3)) {
if (ConstantInt *COP = dyn_cast<ConstantInt>(MAI->getOperand(1))) {
//FIXME assuming that the first array index is 0
#if 0
assert((COP->getZExtValue() == 0) && "non zero array index\n");
#else
if (COP->getZExtValue() == 0) {
#endif
Value * secOp = MAI->getOperand(2);
Value *indexTypeSize = ConstantInt::get(Type::UIntTy, TD->getTypeSize(secOp->getType()));
#ifdef LLVA_KERNEL
//
// Determine whether the exactcheck() will have constant integer
// arguments. If so, then we can evaluate them statically and avoid
// inserting the run-time check.
//
if (!(AI->isArrayAllocation()))
if (ConstantInt * Index = dyn_cast<ConstantInt>(secOp)) {
int index = Index->getSExtValue();
if ((index > 0) && (index < TD->getTypeSize(AI->getAllocatedType())))
return;
}
#endif
//Convert everything to bytes
if (secOp->getType() != Type::IntTy) {
secOp = new CastInst(secOp, Type::IntTy, secOp->getName()+".casted",
MAI);
}
// secOp = BinaryOperator::create(Instruction::Mul, indexTypeSize, secOp,"indextmp",MAI);
std::vector<Value *> args(1,secOp);
Value *AllocSize =
ConstantInt::get(Type::IntTy, TD->getTypeSize(AI->getAllocatedType()));
if (AI->isArrayAllocation())
AllocSize = BinaryOperator::create(Instruction::Mul,
AllocSize,
AI->getOperand(0), "sizetmp", MAI);
args.push_back(AllocSize);
CallInst *newCI = new CallInst(ExactCheck,args,"", MAI);
} else {
std::cerr << "COP not zero: " << *MAI << std::endl;
}
} else {
std::cerr << "Bad COP: " << *MAI << std::endl;
}
} else {
std::cerr << " num operands != 3: " << *MAI << std::endl;
abort();
}
} else {
// Now check if the GEP is inside a loop with monotonically increasing
//loop bounds
//We use the LoopInfo Pass this
#if 0
Loop *L = LI->getLoopFor(MAI->getParent());
bool monotonicOpt = false;
if (L && (MAI->getNumOperands() == 2)) {
bool HasConstantItCount = isa<SCEVConstant>(scevPass->getIterationCount(L));
Value *vIndex = MAI->getOperand(1);
if (Instruction *Index = dyn_cast<Instruction>(vIndex)) {
//If it is not an instruction then it must already be loop invariant
if (L->isLoopInvariant(MAI->getPointerOperand())) {
SCEVHandle SH = scevPass->getSCEV(Index);
if (SH->hasComputableLoopEvolution(L) || // Varies predictably
HasConstantItCount) {
if (SCEVAddRecExpr *AR = dyn_cast<SCEVAddRecExpr>(SH))
if (AR->isAffine()) {
SCEVHandle EntryValue = AR->getStart();
// EntryValue->getValueRange().dump();
// Index->dump();
SCEVHandle ExitValue = scevPass->getSCEVAtScope(Index, L->getParentLoop());
BasicBlock *Preheader = L->getLoopPreheader();
if (!isa<SCEVCouldNotCompute>(ExitValue)) {
SCEVExpander Rewriter(*scevPass, *LI);
Instruction *ptIns = Preheader->getTerminator();
Value *NewVal = Rewriter.expandCodeFor(ExitValue, ptIns,
Index->getType());
// NewVal->dump();
if (!isa<SCEVCouldNotCompute>(EntryValue)) {
Value *NewVal2 = Rewriter.expandCodeFor(EntryValue, ptIns,
Index->getType());
// NewVal2->dump();
//Inserted the values now insert GEPs and add checks
std::vector<Value *> gepargs1(1,NewVal);
GetElementPtrInst *GEPUpper =
new GetElementPtrInst(MAI->getPointerOperand(), gepargs1, MAI->getName()+"upbc", ptIns);
insertBoundsCheck (MAI, GEPUpper->getPointerOperand(), GEPUpper, ptIns);
std::vector<Value *> gepargs2(1,NewVal2);
GetElementPtrInst *GEPLower =
new GetElementPtrInst(MAI->getPointerOperand(), gepargs2, MAI->getName()+"lobc", ptIns);
insertBoundsCheck (MAI, GEPLower->getPointerOperand(), GEPLower, ptIns);
monotonicOpt = true;
++MonotonicOpts;
}
}
}
}
}
}
}
if (!monotonicOpt) {
//
// Insert a bounds check and use its return value in all subsequent
// uses.
//
Instruction *nextIns = MAI->getNext();
insertBoundsCheck (MAI, MAI->getPointerOperand(), MAI, nextIns);
}
#endif
}
}
} else {
std::cerr << "GEP does not have pointer type arg" << *MAI << std::endl;
abort();
}
}
}
void InsertPoolChecks::addGetActualValue(SetCondInst *SCI, unsigned operand) {
//we know that the operand is a pointer type
Value *op = SCI->getOperand(operand);
Function *F = SCI->getParent()->getParent();
#ifndef LLVA_KERNEL
if (!equivPass->ContainsDSGraphFor(*F)) {
//some times the ECGraphs doesnt contain F
//for newly created cloned functions
PA::FuncInfo *FI = paPass->getFuncInfoOrClone(*F);
op = FI->MapValueToOriginal(op);
if (!op) return; //abort();
}
#endif
Function *Fnew = F;
Value *PH = 0;
if (Argument *arg = dyn_cast<Argument>(op)) {
Fnew = arg->getParent();
PH = getPoolHandle(op, Fnew);
} else if (Instruction *Inst = dyn_cast<Instruction>(op)) {
Fnew = Inst->getParent()->getParent();
PH = getPoolHandle(op, Fnew);
} else if (isa<Constant>(op)) {
return;
// abort();
} else if (!isa<ConstantPointerNull>(op)) {
//has to be a global
abort();
}
op = SCI->getOperand(operand);
if (!isa<ConstantPointerNull>(op)) {
if (PH) {
if (1) { //HACK fixed
Type *VoidPtrType = PointerType::get(Type::SByteTy);
Value *PHVptr = new CastInst(PH, VoidPtrType,
PH->getName()+".casted", SCI);
Value *OpVptr = op;
if (op->getType() != VoidPtrType)
OpVptr = new CastInst(op, VoidPtrType,
op->getName()+".casted", SCI);
std::vector<Value *> args = make_vector(PHVptr, OpVptr,0);
CallInst *CI = new CallInst(GetActualValue, args,"getval", SCI);
CastInst *CastBack = new CastInst(CI, op->getType(), op->getName()+".castback",SCI);
SCI->setOperand(operand, CastBack);
}
} else {
//It shouldn't work if PH is not null
}
}
}
void InsertPoolChecks::TransformFunction (Function & F) {
#ifndef LLVA_KERNEL
PA::FuncInfo * PAFI = paPass->getFuncInfoOrClone(F);
if (PAFI->Clone && PAFI->Clone != &F) {
//no need to transform
return;
}
#endif
inst_iterator I = inst_begin(F);
while (I != inst_end(F)) {
Instruction *iLocal = &*I;
if (SetCondInst *SCI = dyn_cast<SetCondInst>(iLocal)) {
//If it is neq, eq,
if ((SCI->getOpcode() == BinaryOperator::SetEQ) || (SCI->getOpcode() == BinaryOperator::SetNE)) {
//for all the pointer operands replace them by the getactualvalue
assert((SCI->getNumOperands() == 2) && "nmber of operands for SCI different from 2 ");
if (isa<PointerType>(SCI->getOperand(0)->getType())) {
//we need to insert a call to getactualvalue
//First get the poolhandle for the pointer
// TODO: We don't have a working getactualvalue(), so don't waste
// time calling it.
#if 0
if ((!isa<ConstantPointerNull>(SCI->getOperand(0))) && (!isa<ConstantPointerNull>(SCI->getOperand(1)))) {
addGetActualValue(SCI, 0);
addGetActualValue(SCI, 1);
}
#endif
}
}
} else if (isa<CastInst>(iLocal)) {
//Some times the getelementptr is an argument of cast instruction
// and we don't want to miss a run-time check there
if (isa<GetElementPtrInst>(iLocal->getOperand(0))) {
iLocal = cast<Instruction>(iLocal->getOperand(0));
}
} //
// we need to handle
// alloca instructions
// getelement ptrs
// load store checks
if (isa<GetElementPtrInst>(iLocal)) {
GetElementPtrInst *MAI = cast<GetElementPtrInst>(iLocal);
++I;
std::set<Instruction *> CheckSet;
AggregateGEPs (MAI, CheckSet);
for (std::set<Instruction *>::iterator GEP = CheckSet.begin();
GEP != CheckSet.end(); ++GEP) {
Instruction * I = *GEP;
GetElementPtrInst * GEPI = dyn_cast<GetElementPtrInst>(I);
handleGetElementPtr(GEPI);
}
continue;
} else if (AllocaInst *AI = dyn_cast<AllocaInst>(iLocal)) {
AllocaInst * AIOrig = AI;
if (!DisableStackChecks) {
#ifndef LLVA_KERNEL
if (!equivPass->ContainsDSGraphFor(F)) {
//some times the ECGraphs doesnt contain F
//for newly created cloned functions
PA::FuncInfo *FI = paPass->getFuncInfoOrClone(F);
Value *temp = FI->MapValueToOriginal(AI);
if (temp)
AIOrig = dyn_cast<AllocaInst>(temp);
else
continue;
assert(AIOrig && " Instruction not in value map (clone)\n");
}
#endif
++I;
registerAllocaInst(AI, AIOrig);
continue;
}
} else if (CallInst *CI = dyn_cast<CallInst>(iLocal)) {
++I;
handleCallInst(CI);
continue;
}
//
// Move to the next instruction.
//
++I;
}
}
void InsertPoolChecks::registerAllocaInst(AllocaInst *AI, AllocaInst *AIOrig) {
//
// Get the pool handle for the node that this contributes to...
//
Function *FOrig = AIOrig->getParent()->getParent();
DSNode *Node = getDSNode(AIOrig, FOrig);
if (!Node) return;
assert ((Node->isAllocaNode()) && "DSNode for alloca is missing stack flag!");
//
// Only register the stack allocation if it may be the subject of a run-time
// check. This can only occur when the object is used like an array because:
// 1) GEP checks are only done when accessing arrays.
// 2) Load/Store checks are only done on collapsed nodes (which appear to be
// used like arrays).
//
if (!(Node->isArray()))
return;
//
// Determine if any use (direct or indirect) escapes this function. If not,
// then none of the checks will consult the MetaPool, and we can forego
// registering the alloca.
//
bool MustRegisterAlloca = false;
std::vector<Value *> AllocaWorkList;
AllocaWorkList.push_back (AI);
while ((!MustRegisterAlloca) && (AllocaWorkList.size())) {
Value * V = AllocaWorkList.back();
AllocaWorkList.pop_back();
Value::use_iterator UI = V->use_begin();
for (; UI != V->use_end(); ++UI) {
// We cannot handle PHI nodes or Select instructions
if (isa<PHINode>(UI) || isa<SelectInst>(UI)) {
MustRegisterAlloca = true;
continue;
}
// The pointer escapes if it's stored to memory somewhere.
StoreInst * SI;
if ((SI = dyn_cast<StoreInst>(UI)) && (SI->getOperand(0) == V)) {
MustRegisterAlloca = true;
continue;
}
// GEP instructions are okay, but need to be added to the worklist
if (isa<GetElementPtrInst>(UI)) {
AllocaWorkList.push_back (*UI);
continue;
}
// Cast instructions are okay as long as they cast to another pointer
// type
if (CastInst * CI = dyn_cast<CastInst>(UI)) {
if (isa<PointerType>(CI->getType())) {
AllocaWorkList.push_back (*UI);
continue;
} else {
MustRegisterAlloca = true;
continue;
}
}
if (ConstantExpr *cExpr = dyn_cast<ConstantExpr>(UI)) {
if (cExpr->getOpcode() == Instruction::Cast) {
AllocaWorkList.push_back (*UI);
continue;
} else {
MustRegisterAlloca = true;
continue;
}
}
CallInst * CI1;
if (CI1 = dyn_cast<CallInst>(UI)) {
if (!(CI1->getCalledFunction())) {
MustRegisterAlloca = true;
continue;
}
std::string FuncName = CI1->getCalledFunction()->getName();
if (FuncName == "exactcheck3") {
AllocaWorkList.push_back (*UI);
continue;
} else if ((FuncName == "llvm.memcpy.i32") ||
(FuncName == "llvm.memcpy.i64") ||
(FuncName == "llvm.memset.i32") ||
(FuncName == "llvm.memset.i64") ||
(FuncName == "llvm.memmove.i32") ||
(FuncName == "llvm.memmove.i64") ||
(FuncName == "llva_memcpy") ||
(FuncName == "llva_memset") ||
(FuncName == "llva_strncpy") ||
(FuncName == "llva_invokememcpy") ||
(FuncName == "llva_invokestrncpy") ||
(FuncName == "llva_invokememset") ||
(FuncName == "memcmp")) {
continue;
} else {
MustRegisterAlloca = true;
continue;
}
}
}
}
if (!MustRegisterAlloca) {
++SavedRegAllocs;
return;
}
//
// Insert the alloca registration.
//
Value *PH = getPoolHandle(AIOrig, FOrig);
if (PH == 0 || isa<ConstantPointerNull>(PH)) return;
Value *AllocSize =
ConstantInt::get(Type::UIntTy, TD->getTypeSize(AI->getAllocatedType()));
if (AI->isArrayAllocation())
AllocSize = BinaryOperator::create(Instruction::Mul, AllocSize,
AI->getOperand(0), "sizetmp", AI);
// Insert object registration at the end of allocas.
Instruction *iptI = AI->getNext();
if (AI->getParent() == (&(AI->getParent()->getParent()->getEntryBlock()))) {
BasicBlock::iterator InsertPt = AI->getParent()->begin();
while (&(*(InsertPt)) != AI)
++InsertPt;
while (isa<AllocaInst>(InsertPt))
++InsertPt;
iptI = InsertPt;
}
//
// Insert a call to register the object.
//
Instruction *Casted = new CastInst(AI, PointerType::get(Type::SByteTy),
AI->getName()+".casted", iptI);
Value *CastedPH = new CastInst(PH,
PointerType::get(Type::SByteTy),
"allocph",Casted);
new CallInst(StackRegister,
make_vector(CastedPH, Casted, AllocSize,0),
"", iptI);
//
// Insert a call to unregister the object whenever the function can exit.
//
for (Function::iterator BB = AI->getParent()->getParent()->begin();
BB != AI->getParent()->getParent()->end();
++BB) {
iptI = BB->getTerminator();
if (isa<ReturnInst>(iptI) || isa<UnwindInst>(iptI))
new CallInst(StackFree,
make_vector(CastedPH, Casted, 0),
"", iptI);
}
// Update statistics
++StackRegisters;
}
//
// Method: insertAlignmentCheck()
//
// Description:
// Insert an alignment check for the specified value.
//
void
InsertPoolChecks::insertAlignmentCheck (LoadInst * LI) {
// Get the function containing the load instruction
Function * F = LI->getParent()->getParent();
// Get the DSNode for the result of the load instruction. If it is type
// unknown, then no alignment check is needed.
DSNode * LoadResultNode = getDSNode (LI,F);
if (!(LoadResultNode && (!(LoadResultNode->isNodeCompletelyFolded())))) {
return;
}
//
// Get the pool handle for the node.
//
Value *PH = getPoolHandle(LI, F);
if (!PH) return;
//
// If the node is incomplete or unknown, then only perform the check if
// checks to incomplete or unknown are allowed.
//
Function * ThePoolCheckFunction = PoolCheckAlign;
if ((LoadResultNode->isUnknownNode()) || (LoadResultNode->isIncomplete())) {
if (EnableUnknownChecks) {
ThePoolCheckFunction = PoolCheckAlignUI;
} else {
++MissedIncompleteChecks;
return;
}
}
//
// A check is needed. Scan through the links of the DSNode of the load's
// pointer operand; we need to determine the offset for the alignment check.
//
DSNode * Node = getDSNode (LI->getPointerOperand(), F);
if (!Node) return;
for (unsigned i = 0 ; i < Node->getNumLinks(); ++i) {
DSNodeHandle & LinkNode = Node->getLink(i);
if (LinkNode.getNode() == LoadResultNode) {
// Insertion point for this check is *after* the load.
Instruction * InsertPt = LI->getNext();
// Create instructions to cast the checked pointer and the checked pool
// into sbyte pointers.
Value *CastVI = castTo (LI, PointerType::get(Type::SByteTy), InsertPt);
Value *CastPHI = castTo (PH, PointerType::get(Type::SByteTy), InsertPt);
// Create the call to poolcheck
std::vector<Value *> args(1,CastPHI);
args.push_back(CastVI);
args.push_back (ConstantInt::get(Type::UIntTy, LinkNode.getOffset()));
new CallInst (PoolCheckAlign,args, "", InsertPt);
// Update the statistics
++AlignLSChecks;
break;
}
}
}
#ifdef LLVA_KERNEL
//
// Method: addLSChecks()
//
// Description:
// Insert a poolcheck() into the code for a load or store instruction.
//
void InsertPoolChecks::addLSChecks(Value *V, Instruction *I, Function *F) {
// Get the DSNode for the pointer to check
DSNode * Node = getDSNode (V,F);
//
// Do not perform any checks if there is no DSNode, if the node is not folded,
// or if the node is incomplete.
//
if (!(Node && Node->isNodeCompletelyFolded()))
return;
//
// If the node is not registered, don't bother to check it.
//
if (!(isNodeRegistered (Node)))
return;
//
// We will perform checks on incomplete or unknown nodes, but we must accept
// the possibility that the object will not be found.
//
Function * ThePoolCheckFunction = PoolCheck;
if ((Node->isUnknownNode()) || (Node->isIncomplete())) {
if (EnableUnknownChecks) {
ThePoolCheckFunction = PoolCheckUI;
} else {
++MissedIncompleteChecks;
return;
}
}
//
// This may be a load instruction that loads a pointer that:
// 1) Points to a type known pool, and
// 2) Loaded from a type unknown pool
//
// If this is the case, we need to perform an alignment check on the result
// of the load. Do that here.
//
if (LoadInst * LI = dyn_cast<LoadInst>(I)) {
insertAlignmentCheck (LI);
}
//
// Do not perform a load/store check if the pointer used for this operation
// has already been checked.
//
if (findCheckedPointer(V)) {
++SavedPoolChecks;
return;
}
// Get the pool handle associated with this pointer. If there is no pool
// handle, use a NULL pointer value and let the runtime deal with it.
Value *PH = getPoolHandle(V, F);
if (!PH) {
// Update the number of poolchecks that won't do anything
++NullChecks;
// Update the stats on why there will be no check
++MissedNullChecks;
// Don't bother to insert the NULL check unless the user requested it
if (!EnableNullChecks)
return;
PH = Constant::getNullValue(PointerType::get(Type::SByteTy));
} else {
// This will be a full check; update the stats.
assert (isa<GlobalValue>(PH));
++FullChecks;
}
// Create instructions to cast the checked pointer and the checked pool
// into sbyte pointers.
Value *CastVI = castTo (V, PointerType::get(Type::SByteTy), I);
Value *CastPHI = castTo (PH, PointerType::get(Type::SByteTy), I);
// Create the call to poolcheck
std::vector<Value *> args(1,CastPHI);
args.push_back(CastVI);
new CallInst (ThePoolCheckFunction ,args, "", I);
}
void InsertPoolChecks::addLoadStoreChecks (Function & FR) {
Function *F = &FR;
for (inst_iterator I = inst_begin(F), E = inst_end(F); I != E; ++I) {
if (LoadInst *LI = dyn_cast<LoadInst>(&*I)) {
Value *P = LI->getPointerOperand();
addLSChecks(P, LI, F);
} else if (StoreInst *SI = dyn_cast<StoreInst>(&*I)) {
Value *P = SI->getPointerOperand();
addLSChecks(P, SI, F);
} else if (CallInst * CI = dyn_cast<CallInst>(&*I)) {
if (Function * CalledFunc = CI->getCalledFunction()) {
if ((CalledFunc->getName() == "llva_atomic_compare_and_swap") ||
(CalledFunc->getName() == "llva_atomic_cas_lw") ||
(CalledFunc->getName() == "llva_atomic_cas_h") ||
(CalledFunc->getName() == "llva_atomic_cas_b") ||
(CalledFunc->getName() == "llva_atomic_fetch_add_store") ||
(CalledFunc->getName() == "llva_atomic_and") ||
(CalledFunc->getName() == "llva_atomic_or")) {
Value * P = CI->getOperand(1);
addLSChecks (P, CI, F);
}
}
}
}
}
#else
void InsertPoolChecks::addLSChecks(Value *Vnew, const Value *V, Instruction *I, Function *F) {
PA::FuncInfo *FI = paPass->getFuncInfoOrClone(*F);
Value *PH = getPoolHandle(V, F, *FI );
DSNode* Node = getDSNode(V, F);
if (!PH) {
return;
} else {
if (PH && isa<ConstantPointerNull>(PH)) {
//we have a collapsed/Unknown pool
Value *PH = getPoolHandle(V, F, *FI, true);
if (dyn_cast<CallInst>(I)) {
// GEt the globals list corresponding to the node
return;
std::vector<Function *> FuncList;
Node->addFullFunctionList(FuncList);
std::vector<Function *>::iterator flI= FuncList.begin(), flE = FuncList.end();
unsigned num = FuncList.size();
if (flI != flE) {
const Type* csiType = Type::getPrimitiveType(Type::UIntTyID);
Value *NumArg = ConstantInt::get(csiType, num);
CastInst *CastVI =
new CastInst(Vnew,
PointerType::get(Type::SByteTy), "casted", I);
std::vector<Value *> args(1, NumArg);
args.push_back(CastVI);
for (; flI != flE ; ++flI) {
Function *func = *flI;
CastInst *CastfuncI =
new CastInst(func,
PointerType::get(Type::SByteTy), "casted", I);
args.push_back(CastfuncI);
}
new CallInst(FunctionCheck, args,"", I);
}
} else {
CastInst *CastVI =
new CastInst(Vnew,
PointerType::get(Type::SByteTy), "casted", I);
CastInst *CastPHI =
new CastInst(PH,
PointerType::get(Type::SByteTy), "casted", I);
std::vector<Value *> args(1,CastPHI);
args.push_back(CastVI);
new CallInst(PoolCheck,args,"", I);
}
}
}
}
void InsertPoolChecks::addLoadStoreChecks(Module &M){
Module::iterator mI = M.begin(), mE = M.end();
for ( ; mI != mE; ++mI) {
Function *F = mI;
//here we check that we only do this on original functions
//and not the cloned functions, the cloned functions may not have the
//DSG
bool isClonedFunc = false;
if (paPass->getFuncInfo(*F))
isClonedFunc = false;
else
isClonedFunc = true;
Function *Forig = F;
PA::FuncInfo *FI = paPass->getFuncInfoOrClone(*F);
if (isClonedFunc) {
Forig = paPass->getOrigFunctionFromClone(F);
}
//we got the original function
for (inst_iterator I = inst_begin(F), E = inst_end(F); I != E; ++I) {
if (LoadInst *LI = dyn_cast<LoadInst>(&*I)) {
//we need to get the LI from the original function
Value *P = LI->getPointerOperand();
if (isClonedFunc) {
assert(FI->NewToOldValueMap.count(LI) && " not in the value map \n");
const LoadInst *temp = dyn_cast<LoadInst>(FI->NewToOldValueMap[LI]);
assert(temp && " Instruction not there in the NewToOldValue map");
const Value *Ptr = temp->getPointerOperand();
addLSChecks(P, Ptr, LI, Forig);
} else {
addLSChecks(P, P, LI, Forig);
}
} else if (StoreInst *SI = dyn_cast<StoreInst>(&*I)) {
Value *P = SI->getPointerOperand();
if (isClonedFunc) {
assert(FI->NewToOldValueMap.count(SI) && " not in the value map \n");
const StoreInst *temp = dyn_cast<StoreInst>(FI->NewToOldValueMap[SI]);
assert(temp && " Instruction not there in the NewToOldValue map");
const Value *Ptr = temp->getPointerOperand();
addLSChecks(P, Ptr, SI, Forig);
} else {
addLSChecks(P, P, SI, Forig);
}
} else if (CallInst *CI = dyn_cast<CallInst>(&*I)) {
Value *FunctionOp = CI->getOperand(0);
if (!isa<Function>(FunctionOp)) {
if (isClonedFunc) {
assert(FI->NewToOldValueMap.count(CI) && " not in the value map \n");
const CallInst *temp = dyn_cast<CallInst>(FI->NewToOldValueMap[CI]);
assert(temp && " Instruction not there in the NewToOldValue map");
const Value* FunctionOp1 = temp->getOperand(0);
addLSChecks(FunctionOp, FunctionOp1, CI, Forig);
} else {
addLSChecks(FunctionOp, FunctionOp, CI, Forig);
}
}
}
}
}
}
#endif
DSNode* InsertPoolChecks::getDSNode(const Value *V, Function *F) {
#ifndef LLVA_KERNEL
DSGraph &TDG = equivPass->getDSGraph(*F);
#else
DSGraph &TDG = TDPass->getDSGraph(*F);
#endif
DSNode *DSN = TDG.getNodeForValue((Value *)V).getNode();
return DSN;
}
unsigned InsertPoolChecks::getDSNodeOffset(const Value *V, Function *F) {
#ifndef LLVA_KERNEL
DSGraph &TDG = equivPass->getDSGraph(*F);
#else
DSGraph &TDG = TDPass->getDSGraph(*F);
#endif
return TDG.getNodeForValue((Value *)V).getOffset();
}
#ifndef LLVA_KERNEL
Value *InsertPoolChecks::getPoolHandle(const Value *V, Function *F, PA::FuncInfo &FI, bool collapsed) {
const DSNode *Node = getDSNode(V,F);
// Get the pool handle for this DSNode...
// assert(!Node->isUnknownNode() && "Unknown node \n");
Type *VoidPtrType = PointerType::get(Type::SByteTy);
Type *PoolDescType = ArrayType::get(VoidPtrType, 50);
Type *PoolDescPtrTy = PointerType::get(PoolDescType);
if (!Node) {
return 0; //0 means there is no isse with the value, otherwise there will be a callnode
}
if (Node->isUnknownNode()) {
//FIXME this should be in a top down pass or propagated like collapsed pools below
if (!collapsed) {
assert(!getDSNodeOffset(V, F) && " we don't handle middle of structs yet\n");
return Constant::getNullValue(PoolDescPtrTy);
}
}
std::map<const DSNode*, Value*>::iterator I = FI.PoolDescriptors.find(Node);
map <Function *, set<Value *> > &
CollapsedPoolPtrs = efPass->CollapsedPoolPtrs;
if (I != FI.PoolDescriptors.end()) {
// Check that the node pointed to by V in the TD DS graph is not
// collapsed
if (!collapsed && CollapsedPoolPtrs.count(F)) {
Value *v = I->second;
if (CollapsedPoolPtrs[F].find(I->second) !=
CollapsedPoolPtrs[F].end()) {
#ifdef DEBUG
std::cerr << "Collapsed pools \n";
#endif
return Constant::getNullValue(PoolDescPtrTy);
} else {
return v;
}
} else {
return I->second;
}
}
return 0;
}
#else
Value *
InsertPoolChecks::getPoolHandle(const Value *V, Function *F) {
DSGraph &TDG = TDPass->getDSGraph(*F);
DSNode *Node = TDG.getNodeForValue((Value *)V).getNode();
// Register that we will need allocations with this DSNode registered.
if (Node)
PHNeeded.insert (Node);
// Get the pool handle for this DSNode...
// assert(!Node->isUnknownNode() && "Unknown node \n");
// if (Node->isUnknownNode()) {
// return 0;
// }
return getPD (Node, *F->getParent());
}
#endif