bool LazyValueInfoCache::solveBlockValueConstantRange(LVILatticeVal &BBLV, Instruction *BBI, BasicBlock *BB) { // Figure out the range of the LHS. If that fails, bail. if (!hasBlockValue(BBI->getOperand(0), BB)) { BlockValueStack.push(std::make_pair(BB, BBI->getOperand(0))); return false; } LVILatticeVal LHSVal = getBlockValue(BBI->getOperand(0), BB); if (!LHSVal.isConstantRange()) { BBLV.markOverdefined(); return true; } ConstantRange LHSRange = LHSVal.getConstantRange(); ConstantRange RHSRange(1); IntegerType *ResultTy = cast<IntegerType>(BBI->getType()); if (isa<BinaryOperator>(BBI)) { if (ConstantInt *RHS = dyn_cast<ConstantInt>(BBI->getOperand(1))) { RHSRange = ConstantRange(RHS->getValue()); } else { BBLV.markOverdefined(); return true; } } // NOTE: We're currently limited by the set of operations that ConstantRange // can evaluate symbolically. Enhancing that set will allows us to analyze // more definitions. LVILatticeVal Result; switch (BBI->getOpcode()) { case Instruction::Add: Result.markConstantRange(LHSRange.add(RHSRange)); break; case Instruction::Sub: Result.markConstantRange(LHSRange.sub(RHSRange)); break; case Instruction::Mul: Result.markConstantRange(LHSRange.multiply(RHSRange)); break; case Instruction::UDiv: Result.markConstantRange(LHSRange.udiv(RHSRange)); break; case Instruction::Shl: Result.markConstantRange(LHSRange.shl(RHSRange)); break; case Instruction::LShr: Result.markConstantRange(LHSRange.lshr(RHSRange)); break; case Instruction::Trunc: Result.markConstantRange(LHSRange.truncate(ResultTy->getBitWidth())); break; case Instruction::SExt: Result.markConstantRange(LHSRange.signExtend(ResultTy->getBitWidth())); break; case Instruction::ZExt: Result.markConstantRange(LHSRange.zeroExtend(ResultTy->getBitWidth())); break; case Instruction::BitCast: Result.markConstantRange(LHSRange); break; case Instruction::And: Result.markConstantRange(LHSRange.binaryAnd(RHSRange)); break; case Instruction::Or: Result.markConstantRange(LHSRange.binaryOr(RHSRange)); break; // Unhandled instructions are overdefined. default: DEBUG(dbgs() << " compute BB '" << BB->getName() << "' - overdefined because inst def found.\n"); Result.markOverdefined(); break; } BBLV = Result; return true; }
LVILatticeVal LVIQuery::getBlockValue(BasicBlock *BB) { // See if we already have a value for this block. LVILatticeVal BBLV = getCachedEntryForBlock(BB); // If we've already computed this block's value, return it. if (!BBLV.isUndefined()) { DEBUG(dbgs() << " reuse BB '" << BB->getName() << "' val=" << BBLV <<'\n'); return BBLV; } // Otherwise, this is the first time we're seeing this block. Reset the // lattice value to overdefined, so that cycles will terminate and be // conservatively correct. BBLV.markOverdefined(); Cache[BB] = BBLV; Instruction *BBI = dyn_cast<Instruction>(Val); if (BBI == 0 || BBI->getParent() != BB) { LVILatticeVal Result; // Start Undefined. // If this is a pointer, and there's a load from that pointer in this BB, // then we know that the pointer can't be NULL. bool NotNull = false; if (Val->getType()->isPointerTy()) { for (BasicBlock::iterator BI = BB->begin(), BE = BB->end();BI != BE;++BI){ LoadInst *L = dyn_cast<LoadInst>(BI); if (L && L->getPointerAddressSpace() == 0 && L->getPointerOperand()->getUnderlyingObject() == Val->getUnderlyingObject()) { NotNull = true; break; } } } unsigned NumPreds = 0; // Loop over all of our predecessors, merging what we know from them into // result. for (pred_iterator PI = pred_begin(BB), E = pred_end(BB); PI != E; ++PI) { Result.mergeIn(getEdgeValue(*PI, BB)); // If we hit overdefined, exit early. The BlockVals entry is already set // to overdefined. if (Result.isOverdefined()) { DEBUG(dbgs() << " compute BB '" << BB->getName() << "' - overdefined because of pred.\n"); // If we previously determined that this is a pointer that can't be null // then return that rather than giving up entirely. if (NotNull) { const PointerType *PTy = cast<PointerType>(Val->getType()); Result = LVILatticeVal::getNot(ConstantPointerNull::get(PTy)); } return Result; } ++NumPreds; } // If this is the entry block, we must be asking about an argument. The // value is overdefined. if (NumPreds == 0 && BB == &BB->getParent()->front()) { assert(isa<Argument>(Val) && "Unknown live-in to the entry block"); Result.markOverdefined(); return Result; } // Return the merged value, which is more precise than 'overdefined'. assert(!Result.isOverdefined()); return Cache[BB] = Result; } // If this value is defined by an instruction in this block, we have to // process it here somehow or return overdefined. if (PHINode *PN = dyn_cast<PHINode>(BBI)) { LVILatticeVal Result; // Start Undefined. // Loop over all of our predecessors, merging what we know from them into // result. for (pred_iterator PI = pred_begin(BB), E = pred_end(BB); PI != E; ++PI) { Value* PhiVal = PN->getIncomingValueForBlock(*PI); Result.mergeIn(Parent.getValueOnEdge(PhiVal, *PI, BB)); // If we hit overdefined, exit early. The BlockVals entry is already set // to overdefined. if (Result.isOverdefined()) { DEBUG(dbgs() << " compute BB '" << BB->getName() << "' - overdefined because of pred.\n"); return Result; } } // Return the merged value, which is more precise than 'overdefined'. assert(!Result.isOverdefined()); return Cache[BB] = Result; } assert(Cache[BB].isOverdefined() && "Recursive query changed our cache?"); // We can only analyze the definitions of certain classes of instructions // (integral binops and casts at the moment), so bail if this isn't one. LVILatticeVal Result; if ((!isa<BinaryOperator>(BBI) && !isa<CastInst>(BBI)) || !BBI->getType()->isIntegerTy()) { DEBUG(dbgs() << " compute BB '" << BB->getName() << "' - overdefined because inst def found.\n"); Result.markOverdefined(); return Result; } // FIXME: We're currently limited to binops with a constant RHS. This should // be improved. BinaryOperator *BO = dyn_cast<BinaryOperator>(BBI); if (BO && !isa<ConstantInt>(BO->getOperand(1))) { DEBUG(dbgs() << " compute BB '" << BB->getName() << "' - overdefined because inst def found.\n"); Result.markOverdefined(); return Result; } // Figure out the range of the LHS. If that fails, bail. LVILatticeVal LHSVal = Parent.getValueInBlock(BBI->getOperand(0), BB); if (!LHSVal.isConstantRange()) { Result.markOverdefined(); return Result; } ConstantInt *RHS = 0; ConstantRange LHSRange = LHSVal.getConstantRange(); ConstantRange RHSRange(1); const IntegerType *ResultTy = cast<IntegerType>(BBI->getType()); if (isa<BinaryOperator>(BBI)) { RHS = dyn_cast<ConstantInt>(BBI->getOperand(1)); if (!RHS) { Result.markOverdefined(); return Result; } RHSRange = ConstantRange(RHS->getValue(), RHS->getValue()+1); } // NOTE: We're currently limited by the set of operations that ConstantRange // can evaluate symbolically. Enhancing that set will allows us to analyze // more definitions. switch (BBI->getOpcode()) { case Instruction::Add: Result.markConstantRange(LHSRange.add(RHSRange)); break; case Instruction::Sub: Result.markConstantRange(LHSRange.sub(RHSRange)); break; case Instruction::Mul: Result.markConstantRange(LHSRange.multiply(RHSRange)); break; case Instruction::UDiv: Result.markConstantRange(LHSRange.udiv(RHSRange)); break; case Instruction::Shl: Result.markConstantRange(LHSRange.shl(RHSRange)); break; case Instruction::LShr: Result.markConstantRange(LHSRange.lshr(RHSRange)); break; case Instruction::Trunc: Result.markConstantRange(LHSRange.truncate(ResultTy->getBitWidth())); break; case Instruction::SExt: Result.markConstantRange(LHSRange.signExtend(ResultTy->getBitWidth())); break; case Instruction::ZExt: Result.markConstantRange(LHSRange.zeroExtend(ResultTy->getBitWidth())); break; case Instruction::BitCast: Result.markConstantRange(LHSRange); break; case Instruction::And: Result.markConstantRange(LHSRange.binaryAnd(RHSRange)); break; case Instruction::Or: Result.markConstantRange(LHSRange.binaryOr(RHSRange)); break; // Unhandled instructions are overdefined. default: DEBUG(dbgs() << " compute BB '" << BB->getName() << "' - overdefined because inst def found.\n"); Result.markOverdefined(); break; } return Cache[BB] = Result; }