bool ReduceCrashingBlocks::TestBlocks(std::vector<const BasicBlock*> &BBs) { // Clone the program to try hacking it apart... Module *M = CloneModule(BD.getProgram()); // Convert list to set for fast lookup... std::set<BasicBlock*> Blocks; for (unsigned i = 0, e = BBs.size(); i != e; ++i) { // Convert the basic block from the original module to the new module... const Function *F = BBs[i]->getParent(); Function *CMF = M->getFunction(F->getName()); assert(CMF && "Function not in module?!"); assert(CMF->getFunctionType() == F->getFunctionType() && "wrong type?"); // Get the mapped basic block... Function::iterator CBI = CMF->begin(); std::advance(CBI, std::distance(F->begin(), Function::const_iterator(BBs[i]))); Blocks.insert(CBI); } std::cout << "Checking for crash with only these blocks:"; unsigned NumPrint = Blocks.size(); if (NumPrint > 10) NumPrint = 10; for (unsigned i = 0, e = NumPrint; i != e; ++i) std::cout << " " << BBs[i]->getName(); if (NumPrint < Blocks.size()) std::cout << "... <" << Blocks.size() << " total>"; std::cout << ": "; // Loop over and delete any hack up any blocks that are not listed... for (Module::iterator I = M->begin(), E = M->end(); I != E; ++I) for (Function::iterator BB = I->begin(), E = I->end(); BB != E; ++BB) if (!Blocks.count(BB) && BB->getTerminator()->getNumSuccessors()) { // Loop over all of the successors of this block, deleting any PHI nodes // that might include it. for (succ_iterator SI = succ_begin(BB), E = succ_end(BB); SI != E; ++SI) (*SI)->removePredecessor(BB); if (BB->getTerminator()->getType() != Type::VoidTy) BB->getTerminator()->replaceAllUsesWith( Constant::getNullValue(BB->getTerminator()->getType())); // Delete the old terminator instruction... BB->getInstList().pop_back(); // Add a new return instruction of the appropriate type... const Type *RetTy = BB->getParent()->getReturnType(); new ReturnInst(RetTy == Type::VoidTy ? 0 : Constant::getNullValue(RetTy), BB); } // The CFG Simplifier pass may delete one of the basic blocks we are // interested in. If it does we need to take the block out of the list. Make // a "persistent mapping" by turning basic blocks into <function, name> pairs. // This won't work well if blocks are unnamed, but that is just the risk we // have to take. std::vector<std::pair<Function*, std::string> > BlockInfo; for (std::set<BasicBlock*>::iterator I = Blocks.begin(), E = Blocks.end(); I != E; ++I) BlockInfo.push_back(std::make_pair((*I)->getParent(), (*I)->getName())); // Now run the CFG simplify pass on the function... PassManager Passes; Passes.add(createCFGSimplificationPass()); Passes.add(createVerifierPass()); Passes.run(*M); // Try running on the hacked up program... if (TestFn(BD, M)) { BD.setNewProgram(M); // It crashed, keep the trimmed version... // Make sure to use basic block pointers that point into the now-current // module, and that they don't include any deleted blocks. BBs.clear(); for (unsigned i = 0, e = BlockInfo.size(); i != e; ++i) { ValueSymbolTable &ST = BlockInfo[i].first->getValueSymbolTable(); Value* V = ST.lookup(BlockInfo[i].second); if (V && V->getType() == Type::LabelTy) BBs.push_back(cast<BasicBlock>(V)); } return true; } delete M; // It didn't crash, try something else. return false; }