bool SpeculativeExecutionPass::considerHoistingFromTo( BasicBlock &FromBlock, BasicBlock &ToBlock) { SmallSet<const Instruction *, 8> NotHoisted; const auto AllPrecedingUsesFromBlockHoisted = [&NotHoisted](User *U) { for (Value* V : U->operand_values()) { if (Instruction *I = dyn_cast<Instruction>(V)) { if (NotHoisted.count(I) > 0) return false; } } return true; }; unsigned TotalSpeculationCost = 0; for (auto& I : FromBlock) { const unsigned Cost = ComputeSpeculationCost(&I, *TTI); if (Cost != UINT_MAX && isSafeToSpeculativelyExecute(&I) && AllPrecedingUsesFromBlockHoisted(&I)) { TotalSpeculationCost += Cost; if (TotalSpeculationCost > SpecExecMaxSpeculationCost) return false; // too much to hoist } else { NotHoisted.insert(&I); if (NotHoisted.size() > SpecExecMaxNotHoisted) return false; // too much left behind } } if (TotalSpeculationCost == 0) return false; // nothing to hoist for (auto I = FromBlock.begin(); I != FromBlock.end();) { // We have to increment I before moving Current as moving Current // changes the list that I is iterating through. auto Current = I; ++I; if (!NotHoisted.count(&*Current)) { Current->moveBefore(ToBlock.getTerminator()); } } return true; }
// // Check if instruction is invariant. // bool LicmPass::isInvariant(const Loop* loop, Invariants& invariants, Instruction* instr) { // Must also satisfy these conditions to ensure safety of movement. if (!isSafeToSpeculativelyExecute(instr) || instr->mayReadFromMemory() || isa<LandingPadInst>(instr)) { return false; } // See if all operands are invariant. for (User::op_iterator OI = instr->op_begin(), OE = instr->op_end(); OI != OE; ++OI) { Value *operand = *OI; if (!isInvariant(loop, invariants, operand)) { return false; } } // Satisfies all conditions. return true; }