bool LazyValueInfoCache::solveBlockValuePHINode(LVILatticeVal &BBLV, PHINode *PN, BasicBlock *BB) { LVILatticeVal Result; // Start Undefined. // Loop over all of our predecessors, merging what we know from them into // result. bool EdgesMissing = false; for (unsigned i = 0, e = PN->getNumIncomingValues(); i != e; ++i) { BasicBlock *PhiBB = PN->getIncomingBlock(i); Value *PhiVal = PN->getIncomingValue(i); LVILatticeVal EdgeResult; EdgesMissing |= !getEdgeValue(PhiVal, PhiBB, BB, EdgeResult); if (EdgesMissing) continue; Result.mergeIn(EdgeResult); // 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"); BBLV = Result; return true; } } if (EdgesMissing) return false; // Return the merged value, which is more precise than 'overdefined'. assert(!Result.isOverdefined() && "Possible PHI in entry block?"); BBLV = Result; return true; }
// If we can determine a constant range for the value Val in the context // provided by the instruction BBI, then merge it into BBLV. If we did find a // constant range, return true. void LazyValueInfoCache::mergeAssumeBlockValueConstantRange(Value *Val, LVILatticeVal &BBLV, Instruction *BBI) { BBI = BBI ? BBI : dyn_cast<Instruction>(Val); if (!BBI) return; for (auto &AssumeVH : AC->assumptions()) { if (!AssumeVH) continue; auto *I = cast<CallInst>(AssumeVH); if (!isValidAssumeForContext(I, BBI, DL, DT)) continue; Value *C = I->getArgOperand(0); if (ICmpInst *ICI = dyn_cast<ICmpInst>(C)) { LVILatticeVal Result; if (getValueFromFromCondition(Val, ICI, Result)) { if (BBLV.isOverdefined()) BBLV = Result; else BBLV.mergeIn(Result); } } } }
bool LazyValueInfoCache::solveBlockValueNonLocal(LVILatticeVal &BBLV, Value *Val, BasicBlock *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()) { if (isKnownNonNull(Val)) { NotNull = true; } else { Value *UnderlyingVal = GetUnderlyingObject(Val); // If 'GetUnderlyingObject' didn't converge, skip it. It won't converge // inside InstructionDereferencesPointer either. if (UnderlyingVal == GetUnderlyingObject(UnderlyingVal, NULL, 1)) { for (BasicBlock::iterator BI = BB->begin(), BE = BB->end(); BI != BE; ++BI) { if (InstructionDereferencesPointer(BI, UnderlyingVal)) { NotNull = true; break; } } } } } // If this is the entry block, we must be asking about an argument. The // value is overdefined. if (BB == &BB->getParent()->getEntryBlock()) { assert(isa<Argument>(Val) && "Unknown live-in to the entry block"); if (NotNull) { PointerType *PTy = cast<PointerType>(Val->getType()); Result = LVILatticeVal::getNot(ConstantPointerNull::get(PTy)); } else { Result.markOverdefined(); } BBLV = Result; return true; } // Loop over all of our predecessors, merging what we know from them into // result. bool EdgesMissing = false; for (pred_iterator PI = pred_begin(BB), E = pred_end(BB); PI != E; ++PI) { LVILatticeVal EdgeResult; EdgesMissing |= !getEdgeValue(Val, *PI, BB, EdgeResult); if (EdgesMissing) continue; Result.mergeIn(EdgeResult); // 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) { PointerType *PTy = cast<PointerType>(Val->getType()); Result = LVILatticeVal::getNot(ConstantPointerNull::get(PTy)); } BBLV = Result; return true; } } if (EdgesMissing) return false; // Return the merged value, which is more precise than 'overdefined'. assert(!Result.isOverdefined()); 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; }
bool LazyValueInfoCache::solveBlockValue(Value *Val, BasicBlock *BB) { if (isa<Constant>(Val)) return true; if (hasCachedValueInfo(Val, BB)) { // If we have a cached value, use that. DEBUG(dbgs() << " reuse BB '" << BB->getName() << "' val=" << getCachedValueInfo(Val, BB) << '\n'); // Since we're reusing a cached value, we don't need to update the // OverDefinedCache. The cache will have been properly updated whenever the // cached value was inserted. return true; } // Hold off inserting this value into the Cache in case we have to return // false and come back later. LVILatticeVal Res; Instruction *BBI = dyn_cast<Instruction>(Val); if (!BBI || BBI->getParent() != BB) { if (!solveBlockValueNonLocal(Res, Val, BB)) return false; insertResult(Val, BB, Res); return true; } if (PHINode *PN = dyn_cast<PHINode>(BBI)) { if (!solveBlockValuePHINode(Res, PN, BB)) return false; insertResult(Val, BB, Res); return true; } // If this value is a nonnull pointer, record it's range and bailout. PointerType *PT = dyn_cast<PointerType>(BBI->getType()); if (PT && isKnownNonNull(BBI)) { Res = LVILatticeVal::getNot(ConstantPointerNull::get(PT)); insertResult(Val, BB, Res); return true; } // If this is an instruction which supports range metadata, return the // implied range. TODO: This should be an intersection, not a union. Res.mergeIn(getFromRangeMetadata(BBI), DL); // 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"); Res.markOverdefined(); insertResult(Val, BB, Res); return true; } // 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"); Res.markOverdefined(); insertResult(Val, BB, Res); return true; } if (!solveBlockValueConstantRange(Res, BBI, BB)) return false; insertResult(Val, BB, Res); return true; }