bool LLVMReachingDefsAnalysis::handleStoreInst(LLVMNode *storeNode, DefMap *df, PointsToSetT *&strong_update) { bool changed = false; llvm::StoreInst *SI = cast<StoreInst>(storeNode->getValue()); LLVMNode *ptrNode = getOperand(storeNode, SI->getPointerOperand(), 0); assert(ptrNode && "No pointer operand"); // update definitions PointsToSetT& S = ptrNode->getPointsTo(); // if we have only one concrete pointer (known pointer // with known offset), it is safe to do strong update if (S.size() == 1) { const Pointer& ptr = *S.begin(); // NOTE: we don't have good mechanism to diferentiate // heap-allocated objects yet, so if the pointer points to heap, // we must do weak update if (ptr.isKnown() && !ptr.offset.isUnknown() && !ptr.pointsToHeap()) { changed |= df->update(ptr, storeNode); strong_update = &S; return changed; } // else fall-through to weak update } // weak update for (const Pointer& ptr : ptrNode->getPointsTo()) changed |= df->add(ptr, storeNode); return changed; }
bool LLVMReachingDefsAnalysis::handleIntrinsicCall(LLVMNode *callNode, CallInst *CI, DefMap *df) { bool changed = false; IntrinsicInst *I = cast<IntrinsicInst>(CI); Value *dest; switch (I->getIntrinsicID()) { case Intrinsic::memmove: case Intrinsic::memcpy: case Intrinsic::memset: dest = I->getOperand(0); break; default: return handleUndefinedCall(callNode, CI, df); } LLVMNode *destNode = getOperand(callNode, dest, 1); assert(destNode && "No operand for intrinsic call"); for (const Pointer& ptr : destNode->getPointsTo()) { // we could compute all the concrete offsets, but // these functions usually set the whole memory, // so if we use UNKNOWN_OFFSET, the effect is the same changed |= df->add(Pointer(ptr.obj, UNKNOWN_OFFSET), callNode); } return changed; }
bool LLVMReachingDefsAnalysis::handleUndefinedCall(LLVMNode *callNode, CallInst *CI, DefMap *df) { bool changed = false; for (unsigned n = 1, e = callNode->getOperandsNum(); n < e; ++n) { Value *llvmOp = CI->getOperand(n - 1); if (!llvmOp->getType()->isPointerTy()) continue; if (isa<Constant>(llvmOp->stripInBoundsOffsets())) continue; LLVMNode *op = getOperand(callNode, llvmOp, n); assert(op && "unhandled pointer operand in undef call"); // with undefined call we must assume that any // memory that was passed via pointer was modified // and on unknown offset // XXX we should handle external globals too for (const Pointer& ptr : op->getPointsTo()) changed |= df->add(Pointer(ptr.obj, UNKNOWN_OFFSET), callNode); } return changed; }