view graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/loop/LoopTransformDataResolver.java @ 5214:1020e363a05d

Loop peeling
author Gilles Duboscq <duboscq@ssw.jku.at>
date Mon, 09 Apr 2012 19:59:01 +0200
parents
children a60d1ed97bd0
line wrap: on
line source

/*
 * Copyright (c) 2012, 2012, 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.oracle.graal.compiler.loop;

import java.util.*;
import java.util.Map.Entry;

import com.oracle.graal.graph.*;
import com.oracle.graal.graph.NodeClass.NodeClassIterator;
import com.oracle.graal.graph.NodeClass.Position;
import com.oracle.graal.nodes.*;



public class LoopTransformDataResolver {
    private List<ResolvableSuperBlock> resolvables = new LinkedList<>();

    private abstract static class ResolvableSuperBlock {
        final SuperBlock block;
        public ResolvableSuperBlock(SuperBlock block) {
            this.block = block;
        }
        public abstract void resolve();
    }

    private static class PeeledResolvableSuperBlock extends ResolvableSuperBlock{
        final SuperBlock peel;
        final boolean nextIteration;
        public PeeledResolvableSuperBlock(SuperBlock peeled, SuperBlock peel, boolean nextIteration) {
            super(peeled);
            this.peel = peel;
            this.nextIteration = nextIteration;
        }
        @Override
        public void resolve() {
            if (nextIteration) {
                SuperBlock peeled = block;
                LoopBeginNode loopBegin = (LoopBeginNode) peeled.getEntry();
                Map<Node, Node> dup = peel.getDuplicationMapping();
                List<PhiNode> newPhis = new LinkedList<>();
                for (PhiNode phi : loopBegin.phis().snapshot()) {
                    ValueNode first = null;
                    if (loopBegin.loopEnds().count() == 1) {
                        ValueNode b = phi.valueAt(loopBegin.loopEnds().first()); // back edge value
                        first = prim(b); // corresponding value in the peel
                    } else {
                        Map<EndNode, LoopEndNode> reverseEnds = new HashMap<>(); // map peel's exit to the corresponding loop exits
                        MergeNode merge = null; // look for the merge if the peel's exits
                        for (LoopEndNode end : loopBegin.loopEnds()) {
                            EndNode newEnd = (EndNode) dup.get(end);
                            if (newEnd != null) {
                                reverseEnds.put(newEnd, end);
                                if (prim(phi.valueAt(end)) != null) {
                                    merge = newEnd.merge();
                                }
                            }
                        }
                        if (merge != null) { // found values of interest (backedge values that exist in the peel)
                            PhiNode firstPhi = loopBegin.graph().add(new PhiNode(phi.kind(), merge, phi.type()));
                            for (EndNode end : merge.forwardEnds()) {
                                LoopEndNode loopEnd = reverseEnds.get(end);
                                ValueNode prim = prim(phi.valueAt(loopEnd));
                                assert prim != null;
                                firstPhi.addInput(prim);
                            }
                            first = firstPhi;
                            merge.stateAfter().replaceFirstInput(phi, firstPhi); // fix the merge's state after (see SuperBlock.mergeExits)
                        }
                    }
                    if (first != null) { // create a new phi (we don't patch the old one since some usages of the old one may still be valid)
                        PhiNode newPhi = loopBegin.graph().add(new PhiNode(phi.kind(), loopBegin, phi.type()));
                        newPhi.addInput(first);
                        for (LoopEndNode end : loopBegin.orderedLoopEnds()) {
                            newPhi.addInput(phi.valueAt(end));
                        }
                        dup.put(phi, newPhi);
                        newPhis.add(newPhi);
                        for (Node usage : phi.usages().snapshot()) {
                            if (dup.get(usage) != null) { // patch only usages that should use the new phi ie usages that were peeled
                                usage.replaceFirstInput(phi, newPhi);
                            }
                        }
                    }
                }
                // check new phis to see if they have as input some old phis, replace those inputs with the new corresponding phis
                for (PhiNode phi : newPhis) {
                    for (int i = 0; i < phi.valueCount(); i++) {
                        ValueNode v = phi.valueAt(i);
                        if (loopBegin.isPhiAtMerge(v)) {
                            PhiNode newV = (PhiNode) dup.get(v);
                            if (newV != null) {
                                phi.setValueAt(i, newV);
                            }
                        }
                    }
                }
            }
        }

        /**
         * Gets the corresponding value in the peel.
         * @param b original value
         * @return corresponding value in the peel
         */
        public ValueNode prim(ValueNode b) {
            SuperBlock peeled = block;
            LoopBeginNode loopBegin = (LoopBeginNode) peeled.getEntry();
            Map<Node, Node> dup = peel.getDuplicationMapping();
            if (loopBegin.isPhiAtMerge(b)) {
                PhiNode phi = (PhiNode) b;
                return phi.valueAt(loopBegin.forwardEnd());
            } else {
                ValueNode v = (ValueNode) dup.get(b);
                if (v == null && nextIteration) {
                    // may not be right in inversion case
                    return b;
                }
                return v;
            }
        }
    }

    private static class PeelResolvableSuperBlock extends ResolvableSuperBlock{
        final SuperBlock peeled;
        public PeelResolvableSuperBlock(SuperBlock peel, SuperBlock peeled) {
            super(peel);
            this.peeled = peeled;
        }
        @Override
        public void resolve() {
            SuperBlock peel = block;
            LoopBeginNode loopBegin = (LoopBeginNode) peeled.getEntry();
            for (Entry<Node, Node> entry : peel.getDuplicationMapping().entrySet()) {
                Node oriNode = entry.getKey();
                Node newNode = entry.getValue();
                for (NodeClassIterator iter = oriNode.inputs().iterator(); iter.hasNext();) {
                    Position pos = iter.nextPosition();
                    if (pos.isValidFor(newNode, oriNode) && pos.get(newNode) == null) {
                        Node oriInput = pos.get(oriNode);
                        // oriInput is not checked against null because oriNode.inputs().iterator() only iterates over non-null pos/input
                        Node v;
                        if (loopBegin.isPhiAtMerge(oriInput)) {
                            PhiNode phi = (PhiNode) oriInput;
                            v = phi.valueAt(loopBegin.forwardEnd());
                        } else {
                            v = oriInput;
                        }
                        pos.set(newNode, v);
                    }
                }
            }
        }
    }

    public class WholeLoop {
        private final SuperBlock from;
        public WholeLoop(SuperBlock from) {
            this.from = from;
        }
        public void peeled(SuperBlock peel) {
            resolvables.add(new PeelResolvableSuperBlock(peel, from));
            resolvables.add(new PeeledResolvableSuperBlock(from, peel, true));
        }

    }

    public void resolve() {
        for (ResolvableSuperBlock resolvable : this.resolvables) {
            resolvable.resolve();
        }
    }

    public WholeLoop wholeLoop(SuperBlock block) {
        return new WholeLoop(block);
    }
}