1 /*
   2  * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 
  25 package org.graalvm.compiler.loop;
  26 
  27 import static org.graalvm.compiler.loop.MathUtil.add;
  28 import static org.graalvm.compiler.loop.MathUtil.sub;
  29 
  30 import org.graalvm.compiler.core.common.type.Stamp;
  31 import org.graalvm.compiler.debug.GraalError;
  32 import org.graalvm.compiler.nodes.NodeView;
  33 import org.graalvm.compiler.nodes.ValueNode;
  34 import org.graalvm.compiler.nodes.calc.AddNode;
  35 import org.graalvm.compiler.nodes.calc.BinaryArithmeticNode;
  36 import org.graalvm.compiler.nodes.calc.IntegerConvertNode;
  37 import org.graalvm.compiler.nodes.calc.NegateNode;
  38 import org.graalvm.compiler.nodes.calc.SubNode;
  39 
  40 public class DerivedOffsetInductionVariable extends DerivedInductionVariable {
  41 
  42     private final ValueNode offset;
  43     private final BinaryArithmeticNode<?> value;
  44 
  45     public DerivedOffsetInductionVariable(LoopEx loop, InductionVariable base, ValueNode offset, BinaryArithmeticNode<?> value) {
  46         super(loop, base);
  47         this.offset = offset;
  48         this.value = value;
  49     }
  50 
  51     public ValueNode getOffset() {
  52         return offset;
  53     }
  54 
  55     @Override
  56     public Direction direction() {
  57         return base.direction();
  58     }
  59 
  60     @Override
  61     public ValueNode valueNode() {
  62         return value;
  63     }
  64 
  65     @Override
  66     public boolean isConstantInit() {
  67         return offset.isConstant() && base.isConstantInit();
  68     }
  69 
  70     @Override
  71     public boolean isConstantStride() {
  72         return base.isConstantStride();
  73     }
  74 
  75     @Override
  76     public long constantInit() {
  77         return op(base.constantInit(), offset.asJavaConstant().asLong());
  78     }
  79 
  80     @Override
  81     public long constantStride() {
  82         if (value instanceof SubNode && base.valueNode() == value.getY()) {
  83             return -base.constantStride();
  84         }
  85         return base.constantStride();
  86     }
  87 
  88     @Override
  89     public ValueNode initNode() {
  90         return op(base.initNode(), offset);
  91     }
  92 
  93     @Override
  94     public ValueNode strideNode() {
  95         if (value instanceof SubNode && base.valueNode() == value.getY()) {
  96             return graph().addOrUniqueWithInputs(NegateNode.create(base.strideNode(), NodeView.DEFAULT));
  97         }
  98         return base.strideNode();
  99     }
 100 
 101     @Override
 102     public ValueNode extremumNode(boolean assumeLoopEntered, Stamp stamp) {
 103         return op(base.extremumNode(assumeLoopEntered, stamp), IntegerConvertNode.convert(offset, stamp, graph(), NodeView.DEFAULT));
 104     }
 105 
 106     @Override
 107     public ValueNode exitValueNode() {
 108         return op(base.exitValueNode(), offset);
 109     }
 110 
 111     @Override
 112     public boolean isConstantExtremum() {
 113         return offset.isConstant() && base.isConstantExtremum();
 114     }
 115 
 116     @Override
 117     public long constantExtremum() {
 118         return op(base.constantExtremum(), offset.asJavaConstant().asLong());
 119     }
 120 
 121     private long op(long b, long o) {
 122         if (value instanceof AddNode) {
 123             return b + o;
 124         }
 125         if (value instanceof SubNode) {
 126             if (base.valueNode() == value.getX()) {
 127                 return b - o;
 128             } else {
 129                 assert base.valueNode() == value.getY();
 130                 return o - b;
 131             }
 132         }
 133         throw GraalError.shouldNotReachHere();
 134     }
 135 
 136     private ValueNode op(ValueNode b, ValueNode o) {
 137         if (value instanceof AddNode) {
 138             return add(graph(), b, o);
 139         }
 140         if (value instanceof SubNode) {
 141             if (base.valueNode() == value.getX()) {
 142                 return sub(graph(), b, o);
 143             } else {
 144                 assert base.valueNode() == value.getY();
 145                 return sub(graph(), o, b);
 146             }
 147         }
 148         throw GraalError.shouldNotReachHere();
 149     }
 150 
 151     @Override
 152     public void deleteUnusedNodes() {
 153     }
 154 
 155     @Override
 156     public String toString() {
 157         return String.format("DerivedOffsetInductionVariable base (%s) %s %s", base, value.getNodeClass().shortName(), offset);
 158     }
 159 }