void breakCriticalEdges(Procedure& proc) { BlockInsertionSet insertionSet(proc); for (BasicBlock* block : proc) { // Non-void terminals that are the moral equivalent of jumps trigger critical edge breaking // because of fixSSA's demoteValues. if (block->numSuccessors() <= 1 && block->last()->type() == Void) continue; for (BasicBlock*& successor : block->successorBlocks()) { if (successor->numPredecessors() <= 1) continue; BasicBlock* pad = insertionSet.insertBefore(successor, successor->frequency()); pad->appendNew<Value>(proc, Jump, successor->at(0)->origin()); pad->setSuccessors(FrequentedBlock(successor)); pad->addPredecessor(block); successor->replacePredecessor(block, pad); successor = pad; } } if (insertionSet.execute()) proc.invalidateCFG(); }
void breakCriticalEdges(Code& code) { BlockInsertionSet insertionSet(code); for (BasicBlock* block : code) { if (block->numSuccessors() <= 1) continue; for (BasicBlock*& successor : block->successorBlocks()) { if (successor->numPredecessors() <= 1) continue; BasicBlock* pad = insertionSet.insertBefore(successor, successor->frequency()); pad->append(Jump, successor->at(0).origin); pad->setSuccessors(successor); pad->addPredecessor(block); successor->replacePredecessor(block, pad); successor = pad; } } insertionSet.execute(); }
void BasicBlock::disasm() { if (isDisasmed()) return; setDisasmed(true); DISASM MyDisasm = insts[0]; insts.pop_back(); //printf("\t\tStart BasicBlock::disasm 0x%llx\n", (ADDR)this); while (1){ // Fix SecurityBlock MyDisasm.SecurityBlock = func->getEnd() - MyDisasm.EIP; // disasm int len = Disasm(&MyDisasm); if (len == OUT_OF_BLOCK) { puts("\t\t\tOUT_OF_BLOCK : Disasm finished"); return; }else if (len == UNKNOWN_OPCODE) { fprintf(stderr, "unknown opcode\n"); return; }else { if((MyDisasm.Instruction.Category&0xffff)==CONTROL_TRANSFER && MyDisasm.Instruction.BranchType) { switch (MyDisasm.Instruction.BranchType) { case CallType: break; case JO: case JC: case JE: case JA: case JS: case JP: case JL: case JG: //case JB: case JECXZ: case JNO: case JNC: case JNE: case JNA: case JNS: case JNP: case JNL: case JNG: //case JNB: { ADDR mAddr = MyDisasm.EIP + len; if ((ADDR)-1 != func->getVirAddr(mAddr)) { BasicBlock *succ = func->findBasicBlock(mAddr); addSuccessor(succ); succ->addPredecessor(this); } } case JmpType: if (MyDisasm.Instruction.AddrValue != 0) { ADDR mAddr = func->getMapAddr(MyDisasm.Instruction.AddrValue); if ((ADDR)-1 != mAddr) { BasicBlock *succ = func->findBasicBlock(mAddr); addSuccessor(succ); succ->addPredecessor(this); } } case RetType: //puts("\t\t\tCONTROL_TRANSFER : Disasm finished"); //char buf[1024]; //printf("\t\t%s\n\n", toString(buf, sizeof(buf))); insts.push_back(MyDisasm); return; default: fprintf(stderr, "unknown branchtype %d (0x%llx) in Basic Block 0x%llx\n", MyDisasm.Instruction.BranchType, (ADDR)MyDisasm.VirtualAddr, getFirstInstAddr()); return; } } insts.push_back(MyDisasm); MyDisasm.EIP = MyDisasm.EIP + len; MyDisasm.VirtualAddr = MyDisasm.VirtualAddr + len; if(MyDisasm.EIP >= func->getEnd()){ //puts("\t\t\tFUNCTION END : Disasm finished"); char buf[1024]; //printf("\t\t%s\n\n", toString(buf, sizeof(buf))); return; } } } }
bool simplifyCFG(Code& code) { const bool verbose = false; PhaseScope phaseScope(code, "simplifyCFG"); // We have three easy simplification rules: // // 1) If a successor is a block that just jumps to another block, then jump directly to // that block. // // 2) If all successors are the same and the operation has no effects, then use a jump // instead. // // 3) If you jump to a block that is not you and has one predecessor, then merge. // // Note that because of the first rule, this phase may introduce critical edges. That's fine. // If you need broken critical edges, then you have to break them yourself. bool result = false; for (;;) { if (verbose) { dataLog("Air before an iteration of simplifyCFG:\n"); dataLog(code); } bool changed = false; for (BasicBlock* block : code) { // We rely on predecessors being conservatively correct. Verify this here. if (shouldValidateIRAtEachPhase()) { for (BasicBlock* block : code) { for (BasicBlock* successor : block->successorBlocks()) RELEASE_ASSERT(successor->containsPredecessor(block)); } } // We don't care about blocks that don't have successors. if (!block->numSuccessors()) continue; // First check if any of the successors of this block can be forwarded over. for (BasicBlock*& successor : block->successorBlocks()) { if (successor != block && successor->size() == 1 && successor->last().opcode == Jump) { BasicBlock* newSuccessor = successor->successorBlock(0); if (newSuccessor != successor) { if (verbose) { dataLog( "Replacing ", pointerDump(block), "->", pointerDump(successor), " with ", pointerDump(block), "->", pointerDump(newSuccessor), "\n"); } // Note that we do not do replacePredecessor() because the block we're // skipping will still have newSuccessor as its successor. newSuccessor->addPredecessor(block); successor = newSuccessor; changed = true; } } } // Now check if the block's terminal can be replaced with a jump. if (block->numSuccessors() > 1) { // The terminal must not have weird effects. if (!block->last().hasArgEffects() && !block->last().hasNonArgNonControlEffects()) { // All of the successors must be the same. bool allSame = true; BasicBlock* firstSuccessor = block->successorBlock(0); for (unsigned i = 1; i < block->numSuccessors(); ++i) { if (block->successorBlock(i) != firstSuccessor) { allSame = false; break; } } if (allSame) { if (verbose) dataLog("Changing ", pointerDump(block), "'s terminal to a Jump.\n"); block->last() = Inst(Jump, block->last().origin); block->successors().resize(1); block->successors()[0].frequency() = FrequencyClass::Normal; changed = true; } } } // Finally handle jumps to a block with one predecessor. if (block->numSuccessors() == 1) { BasicBlock* successor = block->successorBlock(0); if (successor != block && successor->numPredecessors() == 1) { RELEASE_ASSERT(successor->predecessor(0) == block); // We can merge the two blocks because the predecessor only jumps to the successor // and the successor is only reachable from the predecessor. // Remove the terminal. Value* origin = block->insts().takeLast().origin; // Append the full contents of the successor to the predecessor. block->insts().reserveCapacity(block->size() + successor->size()); for (Inst& inst : *successor) block->appendInst(WTFMove(inst)); // Make sure that our successors are the successor's successors. block->successors() = WTFMove(successor->successors()); // Make sure that the successor has nothing left in it except an oops. successor->resize(1); successor->last() = Inst(Oops, origin); successor->successors().clear(); // Ensure that the predecessors of block's new successors know what's up. for (BasicBlock* newSuccessor : block->successorBlocks()) newSuccessor->replacePredecessor(successor, block); if (verbose) dataLog("Merged ", pointerDump(block), "->", pointerDump(successor), "\n"); changed = true; } } } if (!changed) break; result = true; code.resetReachability(); } return result; }