/* * Copyright (c) 2011, 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.max.graal.compiler.util; import java.util.*; import com.oracle.max.graal.compiler.schedule.*; import com.oracle.max.graal.graph.*; import com.oracle.max.graal.graph.Node.Verbosity; import com.oracle.max.graal.nodes.*; import com.oracle.max.graal.nodes.PhiNode.PhiType; public class LoopUtil { public static class Loop { private final LoopBeginNode loopBegin; private NodeBitMap cfgNodes; private Loop parent; private NodeBitMap exits; private NodeBitMap inOrBefore; private NodeBitMap inOrAfter; private NodeBitMap nodes; public Loop(LoopBeginNode loopBegin, NodeBitMap nodes, NodeBitMap exits) { this.loopBegin = loopBegin; this.cfgNodes = nodes; this.exits = exits; } public LoopBeginNode loopBegin() { return loopBegin; } public NodeBitMap cfgNodes() { return cfgNodes; } public NodeBitMap nodes() { if (nodes == null) { nodes = loopBegin().graph().createNodeBitMap(); nodes.setUnion(inOrAfter()); nodes.setIntersect(inOrBefore()); } return nodes; } public Loop parent() { return parent; } public NodeBitMap exits() { return exits; } public void setParent(Loop parent) { this.parent = parent; } public boolean isChild(Loop loop) { return loop.parent != null && (loop.parent == this || loop.parent.isChild(this)); } public NodeBitMap inOrAfter() { if (inOrAfter == null) { inOrAfter = LoopUtil.inOrAfter(this); } return inOrAfter; } public NodeBitMap inOrBefore() { if (inOrBefore == null) { inOrBefore = LoopUtil.inOrBefore(this, inOrAfter()); } return inOrBefore; } public void invalidateCached() { inOrAfter = null; inOrBefore = null; nodes = null; } @Override public String toString() { return "Loop #" + loopBegin().toString(Verbosity.Id); } } public static List<Loop> computeLoops(StructuredGraph graph) { List<Loop> loops = new LinkedList<LoopUtil.Loop>(); for (LoopBeginNode loopBegin : graph.getNodes(LoopBeginNode.class)) { NodeBitMap cfgNodes = markUpCFG(loopBegin, loopBegin.loopEnd()); // computeLoopNodes(loopBegin); cfgNodes.mark(loopBegin); NodeBitMap exits = computeLoopExits(loopBegin, cfgNodes); loops.add(new Loop(loopBegin, cfgNodes, exits)); } for (Loop loop : loops) { for (Loop other : loops) { if (other != loop && other.cfgNodes().isMarked(loop.loopBegin())) { if (loop.parent() == null || loop.parent().cfgNodes().isMarked(other.loopBegin())) { loop.setParent(other); } } } } return loops; } public static NodeBitMap computeLoopExits(LoopBeginNode loopBegin, NodeBitMap cfgNodes) { Graph graph = loopBegin.graph(); NodeBitMap exits = graph.createNodeBitMap(); for (Node n : cfgNodes) { if (IdentifyBlocksPhase.trueSuccessorCount(n) > 1) { for (Node sux : n.cfgSuccessors()) { if (sux != null && !cfgNodes.isMarked(sux) && sux instanceof FixedNode) { exits.mark(sux); } } } } return exits; } public static NodeBitMap markUpCFG(LoopBeginNode loopBegin) { return markUpCFG(loopBegin, loopBegin.loopEnd()); } public static NodeBitMap markUpCFG(LoopBeginNode loopBegin, FixedNode from) { NodeFlood workCFG = loopBegin.graph().createNodeFlood(); workCFG.add(from); NodeBitMap loopNodes = loopBegin.graph().createNodeBitMap(); for (Node n : workCFG) { if (n == loopBegin) { continue; } loopNodes.mark(n); if (n instanceof LoopBeginNode) { workCFG.add(((LoopBeginNode) n).loopEnd()); } for (Node pred : n.cfgPredecessors()) { workCFG.add(pred); } } return loopNodes; } private static NodeBitMap inOrAfter(Loop loop) { return inOrAfter(loop, loop.cfgNodes()); } private static NodeBitMap inOrAfter(Loop loop, NodeBitMap cfgNodes) { return inOrAfter(loop, cfgNodes, true); } private static NodeBitMap inOrAfter(Loop loop, NodeBitMap cfgNodes, boolean full) { Graph graph = loop.loopBegin().graph(); NodeBitMap inOrAfter = graph.createNodeBitMap(); NodeFlood work = graph.createNodeFlood(); work.addAll(cfgNodes); for (Node n : work) { markWithState(n, inOrAfter); if (full) { for (Node sux : n.successors()) { if (sux != null) { work.add(sux); } } } for (Node usage : n.usages()) { if (usage instanceof PhiNode) { // filter out data graph cycles PhiNode phi = (PhiNode) usage; MergeNode merge = phi.merge(); if (merge instanceof LoopBeginNode) { LoopBeginNode phiLoop = (LoopBeginNode) merge; if (phi.valueAt(phiLoop.loopEnd()) == n) { continue; } } } work.add(usage); } } return inOrAfter; } private static NodeBitMap inOrBefore(Loop loop) { return inOrBefore(loop, inOrAfter(loop)); } private static NodeBitMap inOrBefore(Loop loop, NodeBitMap inOrAfter) { return inOrBefore(loop, inOrAfter, loop.cfgNodes()); } private static NodeBitMap inOrBefore(Loop loop, NodeBitMap inOrAfter, NodeBitMap cfgNodes) { return inOrBefore(loop, inOrAfter, cfgNodes, true); } private static NodeBitMap inOrBefore(Loop loop, NodeBitMap inOrAfter, NodeBitMap cfgNodes, boolean full) { Graph graph = loop.loopBegin().graph(); NodeBitMap inOrBefore = graph.createNodeBitMap(); NodeFlood work = graph.createNodeFlood(); work.addAll(cfgNodes); for (Node n : work) { inOrBefore.mark(n); if (full) { if (n.predecessor() != null) { work.add(n.predecessor()); } } if (n instanceof PhiNode) { // filter out data graph cycles PhiNode phi = (PhiNode) n; if (phi.type() == PhiType.Value) { int backIndex = -1; MergeNode merge = phi.merge(); if (merge instanceof LoopBeginNode && cfgNodes.isNotNewNotMarked(((LoopBeginNode) merge).loopEnd())) { LoopBeginNode phiLoop = (LoopBeginNode) merge; backIndex = phiLoop.phiPredecessorIndex(phiLoop.loopEnd()); } for (int i = 0; i < phi.valueCount(); i++) { if (i != backIndex) { work.add(phi.valueAt(i)); } } } } else { for (Node in : n.inputs()) { if (in != null) { work.add(in); } } if (full) { for (Node sux : n.cfgSuccessors()) { // go down into branches that are not 'inOfAfter' if (sux != null && !inOrAfter.isMarked(sux)) { work.add(sux); } } if (n instanceof LoopBeginNode && n != loop.loopBegin()) { Loop p = loop.parent; boolean isParent = false; while (p != null) { if (p.loopBegin() == n) { isParent = true; break; } p = p.parent; } if (!isParent) { work.add(((LoopBeginNode) n).loopEnd()); } } } if (cfgNodes.isNotNewMarked(n)) { //add all values from the exits framestates for (Node sux : n.cfgSuccessors()) { if (loop.exits().isNotNewMarked(sux) && sux instanceof StateSplit) { FrameState stateAfter = ((StateSplit) sux).stateAfter(); while (stateAfter != null) { for (Node in : stateAfter.inputs()) { if (!(in instanceof FrameState)) { work.add(in); } } stateAfter = stateAfter.outerFrameState(); } } } } if (n instanceof MergeNode) { //add phis & counters for (Node usage : n.usages()) { if (!(usage instanceof LoopEndNode)) { work.add(usage); } } } } } return inOrBefore; } private static void markWithState(Node n, NodeBitMap map) { map.mark(n); if (n instanceof StateSplit) { FrameState stateAfter = ((StateSplit) n).stateAfter(); while (stateAfter != null) { map.mark(stateAfter); stateAfter = stateAfter.outerFrameState(); } } } private static void clearWithState(Node n, NodeBitMap map) { map.clear(n); if (n instanceof StateSplit) { FrameState stateAfter = ((StateSplit) n).stateAfter(); while (stateAfter != null) { map.clear(stateAfter); stateAfter = stateAfter.outerFrameState(); } } } }