/// optimizeCheck - replace the given check CallInst with the check's fast /// version if all the source memory objects can be found and it is obvious /// that none of them have been freed at the point where the check is made. /// Returns the new call if possible and NULL otherwise. /// /// This currently works only with memory objects that can't be freed: /// * global variables /// * allocas that trivially have function scope /// * byval arguments /// bool ExactCheckOpt::optimizeCheck(CallInst *CI, CheckInfoType *Info) { // Examined values SmallSet<Value*, 16> Visited; // Potential memory objects SmallSet<Value*, 4> Objects; std::queue<Value*> Q; // Start from the the pointer operand Value *StartPtr = CI->getArgOperand(Info->PtrArgNo)->stripPointerCasts(); Q.push(StartPtr); // Use BFS to find all potential memory objects while(!Q.empty()) { Value *o = Q.front()->stripPointerCasts(); Q.pop(); if(Visited.count(o)) continue; Visited.insert(o); if (ConstantExpr *CE = dyn_cast<ConstantExpr>(o)) { if (CE->getOpcode() == Instruction::GetElementPtr) { Q.push(CE->getOperand(0)); } else { // Exit early if any of the objects are unsupported. if (!isSimpleMemoryObject(o)) return false; Objects.insert(o); } } else if (GetElementPtrInst *GEP = dyn_cast<GetElementPtrInst>(o)) { Q.push(GEP->getPointerOperand()); // It is fine to ignore the case of indexing into null with a pointer // because that case is invalid for LLVM-aware objects such as allocas, // globals, and objects pointed to by noalias pointers. } else if(PHINode *PHI = dyn_cast<PHINode>(o)) { for (unsigned i = 0, num = PHI->getNumIncomingValues(); i != num; ++i) Q.push(PHI->getIncomingValue(i)); } else if (SelectInst *SI = dyn_cast<SelectInst>(o)) { Q.push(SI->getTrueValue()); Q.push(SI->getFalseValue()); } else { // Exit early if any of the objects are unsupported. if (!isSimpleMemoryObject(o)) return false; Objects.insert(o); } } // Mapping from the initial value to the corresponding size and void pointer: // * memory object -> its size and pointer // * phi/select -> corresponding phi/select for the sizes and pointers // * anything else -> the corresponding size and pointer on the path std::map <Value*, PtrSizePair> M; Module &Mod = *CI->getParent()->getParent()->getParent(); Type *SizeTy = getSizeType(Info, Mod); // Add non-instruction non-constant allocation object pointers to the front // of the function's entry block. BasicBlock &EntryBlock = CI->getParent()->getParent()->getEntryBlock(); Instruction *FirstInsertionPoint = ++BasicBlock::iterator(EntryBlock.begin()); for (SmallSet<Value*, 16>::const_iterator It = Objects.begin(), E = Objects.end(); It != E; ++It) { // Obj is a memory object pointer: alloca, argument, load, callinst, etc. Value *Obj = *It; // Insert instruction-based allocation pointers just after the allocation. Instruction *InsertBefore = FirstInsertionPoint; if (Instruction *I = dyn_cast<Instruction>(Obj)) InsertBefore = ++BasicBlock::iterator(I); IRBuilder<> Builder(InsertBefore); SizeOffsetEvalType SizeOffset = ObjSizeEval->compute(Obj); assert(ObjSizeEval->bothKnown(SizeOffset)); assert(dyn_cast<ConstantInt>(SizeOffset.second)->isZero()); Value *Size = Builder.CreateIntCast(SizeOffset.first, SizeTy, /*isSigned=*/false); Value *Ptr = Builder.CreatePointerCast(Obj, VoidPtrTy); M[Obj] = std::make_pair(Ptr, Size); } // Create the rest of the size values and object pointers. // The phi nodes will be finished later. for (SmallSet<Value*, 16>::const_iterator I = Visited.begin(), E = Visited.end(); I != E; ++I) { getPtrAndSize(*I, SizeTy, M); } // Finalize the phi nodes. for (SmallSet<Value*, 16>::const_iterator I = Visited.begin(), E = Visited.end(); I != E; ++I) { if (PHINode *PHI = dyn_cast<PHINode>(*I)) { assert(M.count(PHI)); PHINode *PtrPHI = cast<PHINode>(M[PHI].first); PHINode *SizePHI = cast<PHINode>(M[PHI].second); for(unsigned i = 0, num = PHI->getNumIncomingValues(); i != num; ++i) { Value *IncomingValue = PHI->getIncomingValue(i)->stripPointerCasts(); assert(M.count(IncomingValue)); PtrPHI->addIncoming(M[IncomingValue].first, PHI->getIncomingBlock(i)); SizePHI->addIncoming(M[IncomingValue].second, PHI->getIncomingBlock(i)); } } } // Insert the fast version of the check just before the regular version. assert(M.count(StartPtr) && "The memory object and its size should be known"); createFastCheck(Info, CI, M[StartPtr].first, M[StartPtr].second); return true; }