1 /*
   2  * Copyright (c) 2012, 2015, 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 package org.graalvm.compiler.loop;
  24 
  25 import static org.graalvm.compiler.loop.MathUtil.add;
  26 import static org.graalvm.compiler.loop.MathUtil.sub;
  27 
  28 import org.graalvm.compiler.core.common.type.Stamp;
  29 import org.graalvm.compiler.debug.GraalError;
  30 import org.graalvm.compiler.nodes.ValueNode;
  31 import org.graalvm.compiler.nodes.calc.AddNode;
  32 import org.graalvm.compiler.nodes.calc.BinaryArithmeticNode;
  33 import org.graalvm.compiler.nodes.calc.IntegerConvertNode;
  34 import org.graalvm.compiler.nodes.calc.NegateNode;
  35 import org.graalvm.compiler.nodes.calc.SubNode;
  36 
  37 public class DerivedOffsetInductionVariable extends DerivedInductionVariable {
  38 
  39     private final ValueNode offset;
  40     private final BinaryArithmeticNode<?> value;
  41 
  42     public DerivedOffsetInductionVariable(LoopEx loop, InductionVariable base, ValueNode offset, BinaryArithmeticNode<?> value) {
  43         super(loop, base);
  44         this.offset = offset;
  45         this.value = value;
  46     }
  47 
  48     public ValueNode getOffset() {
  49         return offset;
  50     }
  51 
  52     @Override
  53     public Direction direction() {
  54         return base.direction();
  55     }
  56 
  57     @Override
  58     public ValueNode valueNode() {
  59         return value;
  60     }
  61 
  62     @Override
  63     public boolean isConstantInit() {
  64         return offset.isConstant() && base.isConstantInit();
  65     }
  66 
  67     @Override
  68     public boolean isConstantStride() {
  69         return base.isConstantStride();
  70     }
  71 
  72     @Override
  73     public long constantInit() {
  74         return op(base.constantInit(), offset.asJavaConstant().asLong());
  75     }
  76 
  77     @Override
  78     public long constantStride() {
  79         if (value instanceof SubNode && base.valueNode() == value.getY()) {
  80             return -base.constantStride();
  81         }
  82         return base.constantStride();
  83     }
  84 
  85     @Override
  86     public ValueNode initNode() {
  87         return op(base.initNode(), offset);
  88     }
  89 
  90     @Override
  91     public ValueNode strideNode() {
  92         if (value instanceof SubNode && base.valueNode() == value.getY()) {
  93             return graph().unique(new NegateNode(base.strideNode()));
  94         }
  95         return base.strideNode();
  96     }
  97 
  98     @Override
  99     public ValueNode extremumNode(boolean assumePositiveTripCount, Stamp stamp) {
 100         return op(base.extremumNode(assumePositiveTripCount, stamp), IntegerConvertNode.convert(offset, stamp, graph()));
 101     }
 102 
 103     @Override
 104     public ValueNode exitValueNode() {
 105         return op(base.exitValueNode(), offset);
 106     }
 107 
 108     @Override
 109     public boolean isConstantExtremum() {
 110         return offset.isConstant() && base.isConstantExtremum();
 111     }
 112 
 113     @Override
 114     public long constantExtremum() {
 115         return op(base.constantExtremum(), offset.asJavaConstant().asLong());
 116     }
 117 
 118     private long op(long b, long o) {
 119         if (value instanceof AddNode) {
 120             return b + o;
 121         }
 122         if (value instanceof SubNode) {
 123             if (base.valueNode() == value.getX()) {
 124                 return b - o;
 125             } else {
 126                 assert base.valueNode() == value.getY();
 127                 return o - b;
 128             }
 129         }
 130         throw GraalError.shouldNotReachHere();
 131     }
 132 
 133     private ValueNode op(ValueNode b, ValueNode o) {
 134         if (value instanceof AddNode) {
 135             return add(graph(), b, o);
 136         }
 137         if (value instanceof SubNode) {
 138             if (base.valueNode() == value.getX()) {
 139                 return sub(graph(), b, o);
 140             } else {
 141                 assert base.valueNode() == value.getY();
 142                 return sub(graph(), o, b);
 143             }
 144         }
 145         throw GraalError.shouldNotReachHere();
 146     }
 147 
 148     @Override
 149     public void deleteUnusedNodes() {
 150     }
 151 
 152     @Override
 153     public String toString() {
 154         return String.format("DerivedOffsetInductionVariable base (%s) %s %s", base, value.getNodeClass().shortName(), offset);
 155     }
 156 }