1 /*
   2  * Copyright (c) 2013, 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.replacements.nodes.arithmetic;
  24 
  25 import static org.graalvm.compiler.core.common.type.IntegerStamp.addOverflowsNegatively;
  26 import static org.graalvm.compiler.core.common.type.IntegerStamp.addOverflowsPositively;
  27 import static org.graalvm.compiler.core.common.type.IntegerStamp.carryBits;
  28 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2;
  29 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_2;
  30 
  31 import org.graalvm.compiler.core.common.type.IntegerStamp;
  32 import org.graalvm.compiler.core.common.type.Stamp;
  33 import org.graalvm.compiler.core.common.type.StampFactory;
  34 import org.graalvm.compiler.graph.NodeClass;
  35 import org.graalvm.compiler.graph.spi.CanonicalizerTool;
  36 import org.graalvm.compiler.nodeinfo.NodeInfo;
  37 import org.graalvm.compiler.nodes.AbstractBeginNode;
  38 import org.graalvm.compiler.nodes.ConstantNode;
  39 import org.graalvm.compiler.nodes.ValueNode;
  40 import org.graalvm.compiler.nodes.calc.AddNode;
  41 import org.graalvm.compiler.nodes.spi.LoweringTool;
  42 
  43 import jdk.vm.ci.code.CodeUtil;
  44 import jdk.vm.ci.meta.JavaConstant;
  45 import jdk.vm.ci.meta.JavaKind;
  46 
  47 /**
  48  * Node representing an exact integer addition that will throw an {@link ArithmeticException} in
  49  * case the addition would overflow the 32 bit range.
  50  */
  51 @NodeInfo(cycles = CYCLES_2, size = SIZE_2)
  52 public final class IntegerAddExactNode extends AddNode implements IntegerExactArithmeticNode {
  53     public static final NodeClass<IntegerAddExactNode> TYPE = NodeClass.create(IntegerAddExactNode.class);
  54 
  55     public IntegerAddExactNode(ValueNode x, ValueNode y) {
  56         super(TYPE, x, y);
  57         setStamp(x.stamp().unrestricted());
  58         assert x.stamp().isCompatible(y.stamp()) && x.stamp() instanceof IntegerStamp;
  59     }
  60 
  61     @Override
  62     public boolean inferStamp() {
  63         /*
  64          * Note: it is not allowed to use the foldStamp method of the regular add node as we do not
  65          * know the result stamp of this node if we do not know whether we may deopt. If we know we
  66          * can never overflow we will replace this node with its non overflow checking counterpart
  67          * anyway.
  68          */
  69         return false;
  70     }
  71 
  72     @Override
  73     public Stamp foldStamp(Stamp stampX, Stamp stampY) {
  74         IntegerStamp a = (IntegerStamp) stampX;
  75         IntegerStamp b = (IntegerStamp) stampY;
  76 
  77         int bits = a.getBits();
  78         assert bits == b.getBits();
  79 
  80         long defaultMask = CodeUtil.mask(bits);
  81         long variableBits = (a.downMask() ^ a.upMask()) | (b.downMask() ^ b.upMask());
  82         long variableBitsWithCarry = variableBits | (carryBits(a.downMask(), b.downMask()) ^ carryBits(a.upMask(), b.upMask()));
  83         long newDownMask = (a.downMask() + b.downMask()) & ~variableBitsWithCarry;
  84         long newUpMask = (a.downMask() + b.downMask()) | variableBitsWithCarry;
  85 
  86         newDownMask &= defaultMask;
  87         newUpMask &= defaultMask;
  88 
  89         long newLowerBound;
  90         long newUpperBound;
  91         boolean lowerOverflowsPositively = addOverflowsPositively(a.lowerBound(), b.lowerBound(), bits);
  92         boolean upperOverflowsPositively = addOverflowsPositively(a.upperBound(), b.upperBound(), bits);
  93         boolean lowerOverflowsNegatively = addOverflowsNegatively(a.lowerBound(), b.lowerBound(), bits);
  94         boolean upperOverflowsNegatively = addOverflowsNegatively(a.upperBound(), b.upperBound(), bits);
  95         if (lowerOverflowsPositively) {
  96             newLowerBound = CodeUtil.maxValue(bits);
  97         } else if (lowerOverflowsNegatively) {
  98             newLowerBound = CodeUtil.minValue(bits);
  99         } else {
 100             newLowerBound = CodeUtil.signExtend((a.lowerBound() + b.lowerBound()) & defaultMask, bits);
 101         }
 102 
 103         if (upperOverflowsPositively) {
 104             newUpperBound = CodeUtil.maxValue(bits);
 105         } else if (upperOverflowsNegatively) {
 106             newUpperBound = CodeUtil.minValue(bits);
 107         } else {
 108             newUpperBound = CodeUtil.signExtend((a.upperBound() + b.upperBound()) & defaultMask, bits);
 109         }
 110 
 111         IntegerStamp limit = StampFactory.forInteger(bits, newLowerBound, newUpperBound);
 112         newUpMask &= limit.upMask();
 113         newUpperBound = CodeUtil.signExtend(newUpperBound & newUpMask, bits);
 114         newDownMask |= limit.downMask();
 115         newLowerBound |= newDownMask;
 116         return new IntegerStamp(bits, newLowerBound, newUpperBound, newDownMask, newUpMask);
 117     }
 118 
 119     @Override
 120     public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
 121         ValueNode result = findSynonym(forX, forY);
 122         if (result == null) {
 123             return this;
 124         } else {
 125             return result;
 126         }
 127     }
 128 
 129     private static ValueNode findSynonym(ValueNode forX, ValueNode forY) {
 130         if (forX.isConstant() && !forY.isConstant()) {
 131             return new IntegerAddExactNode(forY, forX);
 132         }
 133         if (forX.isConstant()) {
 134             ConstantNode constantNode = canonicalXconstant(forX, forY);
 135             if (constantNode != null) {
 136                 return constantNode;
 137             }
 138         } else if (forY.isConstant()) {
 139             long c = forY.asJavaConstant().asLong();
 140             if (c == 0) {
 141                 return forX;
 142             }
 143         }
 144         return null;
 145     }
 146 
 147     private static ConstantNode canonicalXconstant(ValueNode forX, ValueNode forY) {
 148         JavaConstant xConst = forX.asJavaConstant();
 149         JavaConstant yConst = forY.asJavaConstant();
 150         if (xConst != null && yConst != null) {
 151             assert xConst.getJavaKind() == yConst.getJavaKind();
 152             try {
 153                 if (xConst.getJavaKind() == JavaKind.Int) {
 154                     return ConstantNode.forInt(Math.addExact(xConst.asInt(), yConst.asInt()));
 155                 } else {
 156                     assert xConst.getJavaKind() == JavaKind.Long;
 157                     return ConstantNode.forLong(Math.addExact(xConst.asLong(), yConst.asLong()));
 158                 }
 159             } catch (ArithmeticException ex) {
 160                 // The operation will result in an overflow exception, so do not canonicalize.
 161             }
 162         }
 163         return null;
 164     }
 165 
 166     @Override
 167     public IntegerExactArithmeticSplitNode createSplit(AbstractBeginNode next, AbstractBeginNode deopt) {
 168         return graph().add(new IntegerAddExactSplitNode(stamp(), getX(), getY(), next, deopt));
 169     }
 170 
 171     @Override
 172     public void lower(LoweringTool tool) {
 173         IntegerExactArithmeticSplitNode.lower(tool, this);
 174     }
 175 }