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();
}
Ejemplo n.º 2
0
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();
}
Ejemplo n.º 3
0
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;
            }
        }
    }
}
Ejemplo n.º 4
0
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;
}