Range Range::widen(const Range& Other) const { RANGE_DEBUG(dbgs() << "widen() :: " << *this << " :: " << Other << "\n"); if (Other.getLower() == Expr::GetBottomValue() || Other.getUpper() == Expr::GetBottomValue()) { if (Other.getLower() != Other.getUpper()) dbgs() << "widen() :: " << *this << " :: " << Other << "\n"; assert(Other.getLower() == Other.getUpper() && "Inconsistent state"); RANGE_DEBUG(dbgs() << "widen() = " << *this << "\n"); return *this; } if (getLower() == Expr::GetBottomValue() || getUpper() == Expr::GetBottomValue()) { assert(getLower() == getUpper() && "Inconsistent state"); RANGE_DEBUG(dbgs() << "widen() = " << Other << "\n"); return Other; } Expr Lower = Other.getLower() == getLower() ? getLower() : Expr::GetMinusInfValue(); Expr Upper = Other.getUpper() == getUpper() ? getUpper() : Expr::GetPlusInfValue(); RANGE_DEBUG(dbgs() << "widen() = " << Range(Lower, Upper) << "\n"); return Range(Lower, Upper); }
Range Range::operator/(const Range& Other) const { if (Other.getLower().isStrictlyPositive() || getLower().isStrictlyPositive()) return Range(getUpper() / Other.getUpper(), getLower() / Other.getUpper()); if (Other.getLower().isNegative() || getLower().isNegative()) return Range(getLower() / Other.getLower(), getUpper() / Other.getUpper()); return GetInfRange(); }
Range Range::operator*(const Range& Other) const { //errs() << "MUL: " << *this << " * " << Other << "\n"; if (Other.getLower().isNegative() || getLower().isNegative()) { //errs() << "NEG\n"; return Range(getUpper() * Other.getUpper(), getLower() * Other.getUpper()); } if (Other.getLower().isNonNegative() || getLower().isNonNegative()) { //errs() << "POS\n"; return Range(getLower() * Other.getLower(), getUpper() * Other.getUpper()); } return GetInfRange(); }
/* * function join * * Here we perform the join operation in the interval lattice, * using Cousot's widening operator. We join the current abstract state * with the new_abstract_state and update the current abstract state of * the node. * * This function returns true if the current abstract state has changed. */ bool llvm::RangeAnalysis::join(GraphNode* Node, Range new_abstract_state){ //Do not widen the range of a value that has an initial value if (!getInitialState(Node).isMaxRange()) { return false; } Range oldInterval = out_state[Node]; Range newInterval = new_abstract_state; APInt oldLower = oldInterval.getLower(); APInt oldUpper = oldInterval.getUpper(); APInt newLower = newInterval.getLower(); APInt newUpper = newInterval.getUpper(); if (oldInterval.isUnknown()) out_state[Node] = newInterval; else { if (widening_count[Node] < MaxIterationCount) { out_state[Node] = oldInterval.unionWith(newInterval); widening_count[Node]++; } else { //Widening APInt oldLower = oldInterval.getLower(); APInt oldUpper = oldInterval.getUpper(); APInt newLower = newInterval.getLower(); APInt newUpper = newInterval.getUpper(); if (newLower.slt(oldLower)) if (newUpper.sgt(oldUpper)) out_state[Node] = Range(Min, Max); else out_state[Node] = Range(Min, oldUpper); else if (newUpper.sgt(oldUpper)) out_state[Node] = Range(oldLower, Max); } } bool hasChanged = oldInterval != out_state[Node]; return hasChanged; }
/* * function meet * * Here we perform the meet operation in the interval lattice, * using Cousot's narrowing operator. We meet the current abstract state * with the new_abstract_state and update the current abstract state of * the node. * * This function returns true if the current abstract state has changed. */ bool llvm::RangeAnalysis::meet(GraphNode* Node, Range new_abstract_state){ Range oldInterval = out_state[Node]; APInt oLower = out_state[Node].getLower(); APInt oUpper = out_state[Node].getUpper(); Range newInterval = new_abstract_state; APInt nLower = newInterval.getLower(); APInt nUpper = newInterval.getUpper(); if (narrowing_count[Node] < MaxIterationCount) { if (oLower.eq(Min) && nLower.ne(Min)) { out_state[Node] = Range(nLower, oUpper); } else { APInt smin = APIntOps::smin(oLower, nLower); if (oLower.ne(smin)) { out_state[Node] = Range(smin, oUpper); } } if (oUpper.eq(Max) && nUpper.ne(Max)) { out_state[Node] = Range(out_state[Node].getLower(), nUpper); } else { APInt smax = APIntOps::smax(oUpper, nUpper); if (oUpper.ne(smax)) { out_state[Node] = Range(out_state[Node].getLower(), smax); } } } if (SigmaOpNode* Sigma = dyn_cast<SigmaOpNode>(Node)){ if (branchConstraints.count(Sigma) > 0) { out_state[Node] = out_state[Node].intersectWith(branchConstraints[Sigma]->getRange()); } } bool hasChanged = oldInterval != out_state[Node]; if (hasChanged) narrowing_count[Node]++; return hasChanged; }
Range Range::meet(const Range& Other) const { // errs() << "MEET: " << Other << ", " << *this << "\n"; return Range(Other.getLower().min(getLower()), Other.getUpper().max(getUpper())); }
Range Range::operator-(const Range& Other) const { return Range(getLower() - Other.getUpper(), getUpper() - Other.getLower()); }
bool Range::operator!=(const Range& other) const { return getLower().ne(other.getLower()) || getUpper().ne(other.getUpper()); }
bool Range::operator==(const Range& other) const { return getLower().eq(other.getLower()) && getUpper().eq(other.getUpper()); }
// Applies the narrowing operations void RangeBasedPointerAnalysis::applyNarrowing() { for(auto i : RangedPointers) { for(auto j = i.second->addr_begin(), je = i.second->addr_end(); j != je; j++) { Address* a = *j; if(!(*j)->Narrowing_Ops.empty()) { Range narrowed = Range(a->getOffset()->getLower(), a->getOffset()->getUpper()); std::pair<bool,bool> growth; if(narrowed.getUpper().isEQ(Expr::getPlusInf(*SI))) growth.second = true; if(narrowed.getLower().isEQ(Expr::getMinusInf(*SI))) growth.first = true; for(auto z : a->Narrowing_Ops) { if(z.second->cmp_op == CmpInst::ICMP_EQ) { //errs() << "=\n"; RangedPointer* rp = RangedPointers[z.second->cmp_v]; for(auto w = rp->addr_begin(), we = rp->addr_end(); w != we; w++) { Expr dw = (*w)->getOffset()->getLower() + z.second->context->getUpper(); if(!narrowed.getUpper().isConstant() and !dw.isConstant()) narrowed.setUpper(narrowed.getUpper().min(dw)); else if(gt(narrowed.getUpper(), dw)) narrowed.setUpper(dw); //narrowed.setUpper(narrowed.getUpper().min(dw)); Expr up = (*w)->getOffset()->getUpper() + z.second->context->getLower(); if(!narrowed.getLower().isConstant() and !up.isConstant()) narrowed.setLower(narrowed.getLower().max(up)); else if(lt(narrowed.getLower(), up)) narrowed.setLower(up); //narrowed.setLower(narrowed.getLower().max(up)); } } else if(z.second->cmp_op == CmpInst::ICMP_NE) { //errs() << "!=\n"; RangedPointer* rp = RangedPointers[z.second->cmp_v]; for(auto w = rp->addr_begin(), we = rp->addr_end(); w != we; w++) { if(a->widened) { if(growth.second) { Expr dw = (*w)->getOffset()->getLower() + z.second->context->getUpper(); if(!narrowed.getUpper().isConstant() and !dw.isConstant()) narrowed.setUpper(narrowed.getUpper().min(dw - 1)); else if(ge(narrowed.getUpper(), dw)) narrowed.setUpper(dw - 1); //narrowed.setUpper(narrowed.getUpper().min(dw - 1)); } else if(growth.first) { Expr up = (*w)->getOffset()->getUpper() + z.second->context->getLower(); if(!narrowed.getLower().isConstant() and !up.isConstant()) narrowed.setLower(narrowed.getLower().max(up + 1)); else if(le(narrowed.getLower(), up)) narrowed.setLower(up + 1); //narrowed.setLower(narrowed.getLower().max(up + 1)); } } } } else if(z.second->cmp_op == CmpInst::ICMP_SLT) { //errs() << "<\n"; RangedPointer* rp = RangedPointers[z.second->cmp_v]; for(auto w = rp->addr_begin(), we = rp->addr_end(); w != we; w++) { Expr dw = (*w)->getOffset()->getLower() + z.second->context->getUpper(); if(!narrowed.getUpper().isConstant() and !dw.isConstant()) narrowed.setUpper(narrowed.getUpper().min(dw - 1)); else if(ge(narrowed.getUpper(), dw)) narrowed.setUpper(dw - 1); //narrowed.setUpper(narrowed.getUpper().min(dw - 1)); } } else if(z.second->cmp_op == CmpInst::ICMP_SLE) { //errs() << "<=\n"; RangedPointer* rp = RangedPointers[z.second->cmp_v]; for(auto w = rp->addr_begin(), we = rp->addr_end(); w != we; w++) { Expr dw = (*w)->getOffset()->getLower() + z.second->context->getUpper(); if(!narrowed.getUpper().isConstant() and !dw.isConstant()) narrowed.setUpper(narrowed.getUpper().min(dw)); else if(gt(narrowed.getUpper(), dw)) narrowed.setUpper(dw); //narrowed.setUpper(narrowed.getUpper().min(dw)); } } else if(z.second->cmp_op == CmpInst::ICMP_SGT) { //errs() << ">\n"; RangedPointer* rp = RangedPointers[z.second->cmp_v]; for(auto w = rp->addr_begin(), we = rp->addr_end(); w != we; w++) { Expr up = (*w)->getOffset()->getUpper() + z.second->context->getLower(); if(!narrowed.getLower().isConstant() and !up.isConstant()) narrowed.setLower(narrowed.getLower().max(up + 1)); else if(le(narrowed.getLower(), up)) narrowed.setLower(up + 1); //narrowed.setLower(narrowed.getLower().max(up + 1)); } } else if(z.second->cmp_op == CmpInst::ICMP_SGE) { //errs() << ">=\n"; RangedPointer* rp = RangedPointers[z.second->cmp_v]; for(auto w = rp->addr_begin(), we = rp->addr_end(); w != we; w++) { Expr up = (*w)->getOffset()->getUpper() + z.second->context->getLower(); if(!narrowed.getLower().isConstant() and !up.isConstant()) narrowed.setLower(narrowed.getLower().max(up)); else if(lt(narrowed.getLower(), up)) narrowed.setLower(up); //narrowed.setLower(narrowed.getLower().max(up)); } } } a->Narrowing_Ops.clear(); a->setOffset(narrowed.getLower(), narrowed.getUpper()); } } } }
// addEdgesFor // Creates a node for I and inserts edges from the created node to the // appropriate node of other values. void IneqGraph::addEdgesFor(Instruction *I) { if (I->getType()->isPointerTy()) return; Range RI = RA->getRange(I); if (!RI.getLower().isMinSignedValue()) addMayEdge(AlfaConst, I, -RI.getLower().getSExtValue()); if (!RI.getUpper().isMaxSignedValue()) addMayEdge(I, AlfaConst, RI.getUpper().getSExtValue()); // TODO: Handle multiplication, remainder and division instructions. switch (I->getOpcode()) { case Instruction::SExt: case Instruction::ZExt: case Instruction::Trunc: case Instruction::BitCast: addMayEdge(I, I->getOperand(0), 0); addMayEdge(I->getOperand(0), I, 0); break; case Instruction::Add: // a = b + c // ==> a <= b + sup(c) // ==> a <= c + sup(b) // ==> b <= a - inf(c) // ==> c <= a - inf(b) { Value *A = I->getOperand(0); Value *B = I->getOperand(1); Range AR = RA->getRange(A); Range BR = RA->getRange(B); if (!isa<ConstantInt>(B) && !AR.getUpper().isMaxSignedValue()) addMayEdge(I, B, AR.getUpper()); if (!isa<ConstantInt>(A) && !BR.getUpper().isMaxSignedValue()) addMayEdge(I, A, BR.getUpper()); if (!isa<ConstantInt>(A) && !BR.getLower().isMinSignedValue()) addMayEdge(A, I, -BR.getUpper()); if (!isa<ConstantInt>(B) && !AR.getLower().isMinSignedValue()) addMayEdge(B, I, -AR.getUpper()); break; } case Instruction::Sub: // a = b - c // ==> a <= b - inf(c) { Value *A = I->getOperand(0); Value *B = I->getOperand(1); Range AR = RA->getRange(A); Range BR = RA->getRange(B); if (!isa<ConstantInt>(A) && !BR.getLower().isMinSignedValue()) addMayEdge(I, A, -BR.getLower()); break; } case Instruction::Br: // if (a > b) { // a1 = sigma(a) // b1 = sigma(b) { BranchInst *BI = cast<BranchInst>(I); ICmpInst *Cmp = dyn_cast<ICmpInst>(I->getOperand(0)); if (!Cmp) break; Value *L = Cmp->getOperand(0); DEBUG(dbgs() << "IneqGraph: L: " << *L << "\n"); Value *R = Cmp->getOperand(1); DEBUG(dbgs() << "IneqGraph: R: " << *R << "\n"); Value *LSigma = VS->findSigma(L, BI->getSuccessor(0), BI->getParent()); DEBUG(dbgs() << "IneqGraph: LSigma: " << *LSigma << "\n"); Value *RSigma = VS->findSigma(R, BI->getSuccessor(0), BI->getParent()); DEBUG(dbgs() << "IneqGraph: RSigma: " << *RSigma << "\n"); Value *LSExtSigma = VS->findSExtSigma(L, BI->getSuccessor(0), BI->getParent()); DEBUG(dbgs() << "IneqGraph: LSExtSigma: " << *LSExtSigma << "\n"); Value *RSExtSigma = VS->findSExtSigma(R, BI->getSuccessor(0), BI->getParent()); DEBUG(dbgs() << "IneqGraph: RSExtSigma: " << *RSExtSigma << "\n"); switch (Cmp->getPredicate()) { case ICmpInst::ICMP_SLT: DEBUG(dbgs() << "IneqGraph: SLT:\n"); if (!isa<ConstantInt>(R) && LSigma) { if (RSigma) addMayEdge(LSigma, RSigma, -1); if (RSExtSigma) addMayEdge(LSigma, RSExtSigma, -1); } if (!isa<ConstantInt>(R) && LSExtSigma && LSExtSigma != LSigma) { if (RSigma) addMayEdge(LSExtSigma, RSigma, -1); if (RSExtSigma) addMayEdge(LSExtSigma, RSExtSigma, -1); } break; case ICmpInst::ICMP_SLE: DEBUG(dbgs() << "IneqGraph: SLE:\n"); if (!isa<ConstantInt>(R) && LSigma && RSigma) addMayEdge(LSigma, RSigma, 0); if (!isa<ConstantInt>(R) && (LSExtSigma != LSigma || RSExtSigma != RSigma)) addMayEdge(LSExtSigma, RSExtSigma, 0); break; default: break; } break; } case Instruction::PHI: { PHINode *Phi = cast<PHINode>(I); for (unsigned Idx = 0; Idx < Phi->getNumIncomingValues(); ++Idx) { addMustEdge(Phi, Phi->getIncomingValue(Idx), 0); } break; } case Instruction::Call: { CallInst *CI = cast<CallInst>(I); if (Function *F = CI->getCalledFunction()) { unsigned Idx = 0; for (Function::arg_iterator AI = F->arg_begin(), AE = F->arg_end(); AI != AE; ++AI, ++Idx) { addMustEdge(&(*AI), CI->getArgOperand(Idx), 0); } } break; } } }
/* * method computeStats * * computes the statistics that require the processing to be complete. */ void llvm::RangeAnalysis::computeStats(){ for(DepGraph::iterator It = depGraph->begin(), Iend = depGraph->end(); It != Iend; It++){ GraphNode* Node = *It; bool isIntegerVariable = false; unsigned int currentBitWidth; //We only count precision statistics of VarNodes and MemNodes if (isa<OpNode>(Node)) { numOps++; continue; } if (isa<MemNode>(Node)) { numMems++; } else if (VarNode* VN = dyn_cast<VarNode>(Node)){ Value* V = VN->getValue(); if (isa<ConstantInt>(V)){ numConstants++; } else { //Only Variables are considered for bitwidth reduction isIntegerVariable = V->getType()->isIntegerTy(); numVars++; if(isIntegerVariable){ currentBitWidth = V->getType()->getPrimitiveSizeInBits(); usedBits += currentBitWidth; } } } else assert(false && "Unknown Node Type"); assert(out_state.count(Node) && "Node not found in the list of computed ranges."); Range CR = out_state[Node]; // If range is unknown, we have total needed bits if (CR.isUnknown()) { ++numUnknown; if (isIntegerVariable) needBits += currentBitWidth; continue; } // If range is empty, we have 0 needed bits if (CR.isEmpty()) { ++numEmpty; continue; } if (CR.getLower().eq(Min)) { if (CR.getUpper().eq(Max)) { ++numMaxRange; } else { ++numMinInfC; } } else if (CR.getUpper().eq(Max)) { ++numCPlusInf; } else { ++numCC; } //Compute needed bits >> only for variables if (isIntegerVariable) { unsigned ub, lb; if (CR.getLower().isNegative()) { APInt abs = CR.getLower().abs(); lb = abs.getActiveBits() + 1; } else { lb = CR.getLower().getActiveBits() + 1; } if (CR.getUpper().isNegative()) { APInt abs = CR.getUpper().abs(); ub = abs.getActiveBits() + 1; } else { ub = CR.getUpper().getActiveBits() + 1; } unsigned nBits = lb > ub ? lb : ub; // If both bounds are positive, decrement needed bits by 1 if (!CR.getLower().isNegative() && !CR.getUpper().isNegative()) { --nBits; } if (nBits < currentBitWidth) { needBits += nBits; } else { needBits += currentBitWidth; } } } double totalB = usedBits; double needB = needBits; double reduction = (double) (totalB - needB) * 100 / totalB; percentReduction = (unsigned int) reduction; }