/* * 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.phases; import java.util.*; import com.oracle.max.graal.compiler.util.*; import com.oracle.max.graal.compiler.util.LoopUtil.Loop; import com.oracle.max.graal.graph.*; import com.oracle.max.graal.nodes.*; import com.oracle.max.graal.nodes.calc.*; import com.oracle.max.graal.nodes.loop.*; import com.sun.cri.ci.*; /** * Looks for linear induction variables in loops. * Saves the information in the graph by replacing these induction variables computations with subclasses of {@link InductionVariableNode} : * <ul> * <li> {@link LoopCounterNode} is the iteration counter (from 0 to Niter)</li> * <li> {@link BasicInductionVariableNode} is an induction variable of the form {@code stride * loopCount + init}. Computed using a phi and an add node</li> * <li> {@link DerivedInductionVariableNode} is an induction variable of the form {@code scale * base + offset} where base is an other of {@link InductionVariableNode}. Computed using multiply and add</li> * </ul> * This phase works in collaboration with {@link RemoveInductionVariablesPhase} which will convert the {@link InductionVariableNode}s back to phis and arithmetic nodes. */ public class FindInductionVariablesPhase extends Phase { @Override protected void run(StructuredGraph graph) { List<Loop> loops = LoopUtil.computeLoops(graph); for (Loop loop : loops) { findInductionVariables(loop); } } private void findInductionVariables(Loop loop) { LoopBeginNode loopBegin = loop.loopBegin(); NodeBitMap loopNodes = loop.nodes(); for (PhiNode phi : loopBegin.phis().snapshot()) { ValueNode init = phi.valueAt(loopBegin.forwardEdge()); ValueNode backEdge = phi.valueAt(loopBegin.loopEnd()); if (loopNodes.isNew(init) || loopNodes.isNew(backEdge)) { continue; } if (loopNodes.isMarked(backEdge)) { BinaryNode binary; if (backEdge instanceof IntegerAddNode || backEdge instanceof IntegerSubNode) { binary = (BinaryNode) backEdge; } else { continue; } ValueNode stride; if (binary.x() == phi) { stride = binary.y(); } else if (binary.y() == phi) { stride = binary.x(); } else { continue; } if (loopNodes.isNotNewNotMarked(stride)) { Graph graph = loopBegin.graph(); if (backEdge instanceof IntegerSubNode) { stride = graph.unique(new NegateNode(stride)); } CiKind kind = phi.kind(); LoopCounterNode counter = loopBegin.loopCounter(kind); BasicInductionVariableNode biv1 = null; BasicInductionVariableNode biv2 = null; if (phi.usages().size() > 1) { biv1 = graph.add(new BasicInductionVariableNode(kind, init, stride, counter)); phi.replaceAndDelete(biv1); } else { phi.replaceFirstInput(binary, null); phi.safeDelete(); } if (backEdge.usages().size() > 0) { biv2 = graph.add(new BasicInductionVariableNode(kind, IntegerArithmeticNode.add(init, stride), stride, counter)); backEdge.replaceAndDelete(biv2); } else { backEdge.safeDelete(); } if (biv1 != null) { findDerivedInductionVariable(biv1, kind, loopNodes); } if (biv2 != null) { findDerivedInductionVariable(biv2, kind, loopNodes); } } } } } private void findDerivedInductionVariable(BasicInductionVariableNode biv, CiKind kind, NodeBitMap loopNodes) { for (Node usage : biv.usages().snapshot()) { ValueNode scale = scale(usage, biv, loopNodes); ValueNode offset = null; Node node = null; if (scale == null) { if (usage instanceof IntegerAddNode) { IntegerAddNode add = (IntegerAddNode) usage; if (add.x() == biv || (scale = scale(add.x(), biv, loopNodes)) != null) { offset = add.y(); } else if (add.y() == biv || (scale = scale(add.y(), biv, loopNodes)) != null) { offset = add.x(); } if (offset != null) { if (loopNodes.isNotNewNotMarked(offset)) { node = add; } else { offset = null; } } } } else { node = usage; } if (scale != null || offset != null) { if (scale == null) { scale = ConstantNode.forIntegerKind(kind, 1, biv.graph()); } else if (offset == null) { offset = ConstantNode.forIntegerKind(kind, 0, biv.graph()); } DerivedInductionVariableNode div = biv.graph().add(new DerivedInductionVariableNode(kind, offset, scale, biv)); node.replaceAndDelete(div); } } } private ValueNode scale(Node n, BasicInductionVariableNode biv, NodeBitMap loopNodes) { if (n instanceof IntegerMulNode) { IntegerMulNode mul = (IntegerMulNode) n; ValueNode scale = null; if (mul.x() == biv) { scale = mul.y(); } else if (mul.y() == biv) { scale = mul.x(); } if (scale != null && loopNodes.isNotNewNotMarked(scale)) { return scale; } } return null; } }