view graal/GraalCompiler/src/com/sun/c1x/opt/BlockMerger.java @ 2509:16b9a8b5ad39

Renamings Runtime=>GraalRuntime and Compiler=>GraalCompiler
author Thomas Wuerthinger <thomas@wuerthinger.net>
date Wed, 27 Apr 2011 11:50:44 +0200
parents graal/Compiler/src/com/sun/c1x/opt/BlockMerger.java@9ec15d6914ca
children
line wrap: on
line source

/*
 * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */
package com.sun.c1x.opt;

import com.sun.c1x.*;
import com.sun.c1x.graph.*;
import com.sun.c1x.ir.*;
import com.sun.c1x.value.*;
import com.sun.c1x.value.FrameState.*;

/**
 * This class implements block merging, which combines adjacent basic blocks into a larger
 * basic block, and block skipping, which removes empty blocks that end in a Goto with
 * their target.
 *
 * @author Ben L. Titzer
 */
public class BlockMerger implements BlockClosure {

    private final BlockBegin startBlock;
    private final IR ir;

    public BlockMerger(IR ir) {
        this.ir = ir;
        startBlock = ir.startBlock;
        startBlock.iteratePreOrder(this);
    }

    public void apply(BlockBegin block) {
        while (block.end() instanceof Goto && block != startBlock) {
            BlockEnd end = block.end();
            BlockBegin sux = end.defaultSuccessor();

            assert end.successors().size() == 1 : "end must have exactly one successor";
            assert !sux.isExceptionEntry() : "should not have Goto to exception entry";

            if (!end.isSafepoint()) {
                if (sux.numberOfPreds() == 1) {
                    // the successor has only one predecessor, merge it into this block
                    mergeBlocks(block, sux, end);
                    C1XMetrics.BlocksMerged++;
                    continue;
                } else if (C1XOptions.OptBlockSkipping && block.next() == end && !block.isExceptionEntry()) {
                    // the successor has multiple predecessors, but this block is empty
                    skipBlock(block, sux, end);
                    break;
                }
            }
            break;
        }
    }

    private void skipBlock(BlockBegin block, final BlockBegin sux, BlockEnd oldEnd) {
        final FrameState oldState = oldEnd.stateAfter();
        assert sux.stateBefore().scope() == oldState.scope();
        boolean hasAtLeastOnePhi = block.stateBefore().forEachPhi(block, new PhiProcedure() {
            public boolean doPhi(Phi phi) {
                return false;
            }
        });

        if (hasAtLeastOnePhi) {
            // can't skip a block that has phis
            return;
        }
        for (final BlockBegin pred : block.predecessors()) {
            final FrameState predState = pred.end().stateAfter();
            if (predState.scope() != oldState.scope() || predState.stackSize() != oldState.stackSize()) {
                // scopes would not match after skipping this block
                // XXX: if phi's were smarter about scopes, this would not be necessary
                return;
            }
            boolean atLeastOneSuxPhiMergesFromAnotherBlock = !sux.stateBefore().forEachPhi(sux, new PhiProcedure() {
                public boolean doPhi(Phi phi) {
                    if (phi.inputIn(sux.stateBefore()) != phi.inputIn(pred.end().stateAfter())) {
                        return false;
                    }
                    return true;
                }
            });

            if (atLeastOneSuxPhiMergesFromAnotherBlock) {
                return;
            }
        }
        ir.replaceBlock(block, sux);
        C1XMetrics.BlocksSkipped++;
    }

    private void mergeBlocks(BlockBegin block, BlockBegin sux, BlockEnd oldEnd) {
        BlockEnd newEnd;
        // find instruction before oldEnd & append first instruction of sux block
        Instruction prev = oldEnd.prev(block);
        Instruction next = sux.next();
        assert !(prev instanceof BlockEnd) : "must not be a BlockEnd";
        prev.setNext(next, next.bci());
        BlockUtil.disconnectFromGraph(sux);
        newEnd = sux.end();
        block.setEnd(newEnd);
        // add exception handlers of deleted block, if any
        for (BlockBegin xhandler : sux.exceptionHandlerBlocks()) {
            block.addExceptionHandler(xhandler);

            // also substitute predecessor of exception handler
            assert xhandler.isPredecessor(sux) : "missing predecessor";
            xhandler.removePredecessor(sux);
            if (!xhandler.isPredecessor(block)) {
                xhandler.addPredecessor(block);
            }
        }
    }
}