1 /*
   2  * Copyright (c) 2011, 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 
  24 
  25 package org.graalvm.compiler.nodes.calc;
  26 
  27 import org.graalvm.compiler.core.common.type.ArithmeticOpTable;
  28 import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp;
  29 import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp.Add;
  30 import org.graalvm.compiler.core.common.type.Stamp;
  31 import org.graalvm.compiler.graph.NodeClass;
  32 import org.graalvm.compiler.graph.spi.Canonicalizable.BinaryCommutative;
  33 import org.graalvm.compiler.graph.spi.CanonicalizerTool;
  34 import org.graalvm.compiler.lir.gen.ArithmeticLIRGeneratorTool;
  35 import org.graalvm.compiler.nodeinfo.NodeInfo;
  36 import org.graalvm.compiler.nodes.ConstantNode;
  37 import org.graalvm.compiler.nodes.NodeView;
  38 import org.graalvm.compiler.nodes.ValueNode;
  39 import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
  40 
  41 import jdk.vm.ci.meta.Constant;
  42 import jdk.vm.ci.meta.Value;
  43 
  44 @NodeInfo(shortName = "+")
  45 public class AddNode extends BinaryArithmeticNode<Add> implements NarrowableArithmeticNode, BinaryCommutative<ValueNode> {
  46 
  47     public static final NodeClass<AddNode> TYPE = NodeClass.create(AddNode.class);
  48 
  49     public AddNode(ValueNode x, ValueNode y) {
  50         this(TYPE, x, y);
  51     }
  52 
  53     protected AddNode(NodeClass<? extends AddNode> c, ValueNode x, ValueNode y) {
  54         super(c, ArithmeticOpTable::getAdd, x, y);
  55     }
  56 
  57     public static ValueNode create(ValueNode x, ValueNode y, NodeView view) {
  58         BinaryOp<Add> op = ArithmeticOpTable.forStamp(x.stamp(view)).getAdd();
  59         Stamp stamp = op.foldStamp(x.stamp(view), y.stamp(view));
  60         ConstantNode tryConstantFold = tryConstantFold(op, x, y, stamp, view);
  61         if (tryConstantFold != null) {
  62             return tryConstantFold;
  63         }
  64         if (x.isConstant() && !y.isConstant()) {
  65             return canonical(null, op, y, x, view);
  66         } else {
  67             return canonical(null, op, x, y, view);
  68         }
  69     }
  70 
  71     private static ValueNode canonical(AddNode addNode, BinaryOp<Add> op, ValueNode forX, ValueNode forY, NodeView view) {
  72         AddNode self = addNode;
  73         boolean associative = op.isAssociative();
  74         if (associative) {
  75             if (forX instanceof SubNode) {
  76                 SubNode sub = (SubNode) forX;
  77                 if (sub.getY() == forY) {
  78                     // (a - b) + b
  79                     return sub.getX();
  80                 }
  81             }
  82             if (forY instanceof SubNode) {
  83                 SubNode sub = (SubNode) forY;
  84                 if (sub.getY() == forX) {
  85                     // b + (a - b)
  86                     return sub.getX();
  87                 }
  88             }
  89         }
  90         if (forY.isConstant()) {
  91             Constant c = forY.asConstant();
  92             if (op.isNeutral(c)) {
  93                 return forX;
  94             }
  95             if (associative && self != null) {
  96                 // canonicalize expressions like "(a + 1) + 2"
  97                 ValueNode reassociated = reassociate(self, ValueNode.isConstantPredicate(), forX, forY, view);
  98                 if (reassociated != self) {
  99                     return reassociated;
 100                 }
 101             }
 102         }
 103         if (forX instanceof NegateNode) {
 104             return BinaryArithmeticNode.sub(forY, ((NegateNode) forX).getValue(), view);
 105         } else if (forY instanceof NegateNode) {
 106             return BinaryArithmeticNode.sub(forX, ((NegateNode) forY).getValue(), view);
 107         }
 108         if (self == null) {
 109             self = (AddNode) new AddNode(forX, forY).maybeCommuteInputs();
 110         }
 111         return self;
 112     }
 113 
 114     @Override
 115     public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
 116         ValueNode ret = super.canonical(tool, forX, forY);
 117         if (ret != this) {
 118             return ret;
 119         }
 120 
 121         if (forX.isConstant() && !forY.isConstant()) {
 122             // we try to swap and canonicalize
 123             ValueNode improvement = canonical(tool, forY, forX);
 124             if (improvement != this) {
 125                 return improvement;
 126             }
 127             // if this fails we only swap
 128             return new AddNode(forY, forX);
 129         }
 130         BinaryOp<Add> op = getOp(forX, forY);
 131         NodeView view = NodeView.from(tool);
 132         return canonical(this, op, forX, forY, view);
 133     }
 134 
 135     @Override
 136     public void generate(NodeLIRBuilderTool nodeValueMap, ArithmeticLIRGeneratorTool gen) {
 137         Value op1 = nodeValueMap.operand(getX());
 138         assert op1 != null : getX() + ", this=" + this;
 139         Value op2 = nodeValueMap.operand(getY());
 140         if (shouldSwapInputs(nodeValueMap)) {
 141             Value tmp = op1;
 142             op1 = op2;
 143             op2 = tmp;
 144         }
 145         nodeValueMap.setResult(this, gen.emitAdd(op1, op2, false));
 146     }
 147 }