< prev index next >

src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/arithmetic/IntegerAddExactNode.java

Print this page


   1 /*
   2  * Copyright (c) 2013, 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.replacements.nodes.arithmetic;
  26 
  27 import static org.graalvm.compiler.core.common.type.IntegerStamp.addOverflowsNegatively;
  28 import static org.graalvm.compiler.core.common.type.IntegerStamp.addOverflowsPositively;
  29 import static org.graalvm.compiler.core.common.type.IntegerStamp.carryBits;
  30 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2;
  31 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_2;
  32 
  33 import org.graalvm.compiler.core.common.type.IntegerStamp;
  34 import org.graalvm.compiler.core.common.type.Stamp;
  35 import org.graalvm.compiler.core.common.type.StampFactory;
  36 import org.graalvm.compiler.graph.NodeClass;
  37 import org.graalvm.compiler.graph.spi.CanonicalizerTool;
  38 import org.graalvm.compiler.nodeinfo.InputType;
  39 import org.graalvm.compiler.nodeinfo.NodeInfo;
  40 import org.graalvm.compiler.nodes.AbstractBeginNode;
  41 import org.graalvm.compiler.nodes.ConstantNode;
  42 import org.graalvm.compiler.nodes.NodeView;
  43 import org.graalvm.compiler.nodes.ValueNode;
  44 import org.graalvm.compiler.nodes.calc.AddNode;
  45 import org.graalvm.compiler.nodes.extended.AnchoringNode;
  46 import org.graalvm.compiler.nodes.spi.LoweringTool;
  47 
  48 import jdk.vm.ci.code.CodeUtil;
  49 import jdk.vm.ci.meta.JavaConstant;
  50 import jdk.vm.ci.meta.JavaKind;
  51 import jdk.vm.ci.meta.SpeculationLog.SpeculationReason;

  52 
  53 /**
  54  * Node representing an exact integer addition that will throw an {@link ArithmeticException} in
  55  * case the addition would overflow the 32 bit range.
  56  */
  57 @NodeInfo(cycles = CYCLES_2, size = SIZE_2)
  58 public final class IntegerAddExactNode extends AddNode implements IntegerExactArithmeticNode {
  59     public static final NodeClass<IntegerAddExactNode> TYPE = NodeClass.create(IntegerAddExactNode.class);
  60 
  61     @OptionalInput(InputType.Anchor) protected AnchoringNode anchor;
  62     protected final SpeculationReason speculation;
  63 
  64     public IntegerAddExactNode(ValueNode x, ValueNode y, SpeculationReason speculation) {
  65         super(TYPE, x, y);
  66         setStamp(x.stamp(NodeView.DEFAULT).unrestricted());
  67         assert x.stamp(NodeView.DEFAULT).isCompatible(y.stamp(NodeView.DEFAULT)) && x.stamp(NodeView.DEFAULT) instanceof IntegerStamp;
  68         this.speculation = speculation;
  69     }
  70 
  71     @Override
  72     public boolean inferStamp() {
  73         /*
  74          * Note: it is not allowed to use the foldStamp method of the regular add node as we do not
  75          * know the result stamp of this node if we do not know whether we may deopt. If we know we
  76          * can never overflow we will replace this node with its non overflow checking counterpart
  77          * anyway.
  78          */
  79         return false;
  80     }
  81 
  82     @Override
  83     public Stamp foldStamp(Stamp stampX, Stamp stampY) {
  84         IntegerStamp a = (IntegerStamp) stampX;
  85         IntegerStamp b = (IntegerStamp) stampY;
  86 
  87         int bits = a.getBits();
  88         assert bits == b.getBits();


 112 
 113         if (upperOverflowsPositively) {
 114             newUpperBound = CodeUtil.maxValue(bits);
 115         } else if (upperOverflowsNegatively) {
 116             newUpperBound = CodeUtil.minValue(bits);
 117         } else {
 118             newUpperBound = CodeUtil.signExtend((a.upperBound() + b.upperBound()) & defaultMask, bits);
 119         }
 120 
 121         IntegerStamp limit = StampFactory.forInteger(bits, newLowerBound, newUpperBound);
 122         newUpMask &= limit.upMask();
 123         newUpperBound = CodeUtil.signExtend(newUpperBound & newUpMask, bits);
 124         newDownMask |= limit.downMask();
 125         newLowerBound |= newDownMask;
 126         return IntegerStamp.create(bits, newLowerBound, newUpperBound, newDownMask, newUpMask);
 127     }
 128 
 129     @Override
 130     public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
 131         if (forX.isConstant() && !forY.isConstant()) {
 132             return new IntegerAddExactNode(forY, forX, speculation).canonical(tool);
 133         }
 134         if (forX.isConstant()) {
 135             ConstantNode constantNode = canonicalXconstant(forX, forY);
 136             if (constantNode != null) {
 137                 return constantNode;
 138             }
 139         } else if (forY.isConstant()) {
 140             long c = forY.asJavaConstant().asLong();
 141             if (c == 0) {
 142                 return forX;
 143             }
 144         }
 145         if (!IntegerStamp.addCanOverflow((IntegerStamp) forX.stamp(NodeView.DEFAULT), (IntegerStamp) forY.stamp(NodeView.DEFAULT))) {
 146             return new AddNode(forX, forY).canonical(tool);
 147         }
 148         return this;
 149     }
 150 
 151     private static ConstantNode canonicalXconstant(ValueNode forX, ValueNode forY) {
 152         JavaConstant xConst = forX.asJavaConstant();
 153         JavaConstant yConst = forY.asJavaConstant();
 154         if (xConst != null && yConst != null) {
 155             assert xConst.getJavaKind() == yConst.getJavaKind();
 156             try {
 157                 if (xConst.getJavaKind() == JavaKind.Int) {
 158                     return ConstantNode.forInt(Math.addExact(xConst.asInt(), yConst.asInt()));
 159                 } else {
 160                     assert xConst.getJavaKind() == JavaKind.Long;
 161                     return ConstantNode.forLong(Math.addExact(xConst.asLong(), yConst.asLong()));
 162                 }
 163             } catch (ArithmeticException ex) {
 164                 // The operation will result in an overflow exception, so do not canonicalize.
 165             }


 166         }
 167         return null;
 168     }
 169 
 170     @Override
 171     public IntegerExactArithmeticSplitNode createSplit(AbstractBeginNode next, AbstractBeginNode deopt) {
 172         return graph().add(new IntegerAddExactSplitNode(stamp(NodeView.DEFAULT), getX(), getY(), next, deopt));
 173     }
 174 
 175     @Override
 176     public SpeculationReason getSpeculation() {
 177         return speculation;
 178     }
 179 
 180     @Override
 181     public AnchoringNode getAnchor() {
 182         return anchor;
 183     }
 184 
 185     @Override
 186     public void setAnchor(AnchoringNode x) {
 187         updateUsagesInterface(this.anchor, x);
 188         this.anchor = x;
 189     }
 190 
 191     @Override
 192     public void lower(LoweringTool tool) {
 193         IntegerExactArithmeticSplitNode.lower(tool, this);

 194     }
 195 }
   1 /*
   2  * Copyright (c) 2013, 2019, 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.replacements.nodes.arithmetic;
  26 
  27 import static org.graalvm.compiler.core.common.type.IntegerStamp.addOverflowsNegatively;
  28 import static org.graalvm.compiler.core.common.type.IntegerStamp.addOverflowsPositively;
  29 import static org.graalvm.compiler.core.common.type.IntegerStamp.carryBits;
  30 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2;
  31 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_2;
  32 
  33 import org.graalvm.compiler.core.common.type.IntegerStamp;
  34 import org.graalvm.compiler.core.common.type.Stamp;
  35 import org.graalvm.compiler.core.common.type.StampFactory;
  36 import org.graalvm.compiler.graph.NodeClass;
  37 import org.graalvm.compiler.graph.spi.CanonicalizerTool;
  38 import org.graalvm.compiler.nodeinfo.InputType;
  39 import org.graalvm.compiler.nodeinfo.NodeInfo;

  40 import org.graalvm.compiler.nodes.ConstantNode;
  41 import org.graalvm.compiler.nodes.NodeView;
  42 import org.graalvm.compiler.nodes.ValueNode;
  43 import org.graalvm.compiler.nodes.calc.AddNode;


  44 
  45 import jdk.vm.ci.code.CodeUtil;
  46 import jdk.vm.ci.meta.JavaConstant;
  47 import jdk.vm.ci.meta.JavaKind;
  48 import org.graalvm.compiler.nodes.extended.GuardedNode;
  49 import org.graalvm.compiler.nodes.extended.GuardingNode;
  50 
  51 /**
  52  * Node representing an exact integer addition that will throw an {@link ArithmeticException} in
  53  * case the addition would overflow the 32 bit range.
  54  */
  55 @NodeInfo(cycles = CYCLES_2, size = SIZE_2)
  56 public final class IntegerAddExactNode extends AddNode implements GuardedNode, IntegerExactArithmeticNode {
  57     public static final NodeClass<IntegerAddExactNode> TYPE = NodeClass.create(IntegerAddExactNode.class);
  58 
  59     @Input(InputType.Guard) protected GuardingNode guard;

  60 
  61     public IntegerAddExactNode(ValueNode x, ValueNode y, GuardingNode guard) {
  62         super(TYPE, x, y);
  63         setStamp(x.stamp(NodeView.DEFAULT).unrestricted());
  64         assert x.stamp(NodeView.DEFAULT).isCompatible(y.stamp(NodeView.DEFAULT)) && x.stamp(NodeView.DEFAULT) instanceof IntegerStamp;
  65         this.guard = guard;
  66     }
  67 
  68     @Override
  69     public boolean inferStamp() {
  70         /*
  71          * Note: it is not allowed to use the foldStamp method of the regular add node as we do not
  72          * know the result stamp of this node if we do not know whether we may deopt. If we know we
  73          * can never overflow we will replace this node with its non overflow checking counterpart
  74          * anyway.
  75          */
  76         return false;
  77     }
  78 
  79     @Override
  80     public Stamp foldStamp(Stamp stampX, Stamp stampY) {
  81         IntegerStamp a = (IntegerStamp) stampX;
  82         IntegerStamp b = (IntegerStamp) stampY;
  83 
  84         int bits = a.getBits();
  85         assert bits == b.getBits();


 109 
 110         if (upperOverflowsPositively) {
 111             newUpperBound = CodeUtil.maxValue(bits);
 112         } else if (upperOverflowsNegatively) {
 113             newUpperBound = CodeUtil.minValue(bits);
 114         } else {
 115             newUpperBound = CodeUtil.signExtend((a.upperBound() + b.upperBound()) & defaultMask, bits);
 116         }
 117 
 118         IntegerStamp limit = StampFactory.forInteger(bits, newLowerBound, newUpperBound);
 119         newUpMask &= limit.upMask();
 120         newUpperBound = CodeUtil.signExtend(newUpperBound & newUpMask, bits);
 121         newDownMask |= limit.downMask();
 122         newLowerBound |= newDownMask;
 123         return IntegerStamp.create(bits, newLowerBound, newUpperBound, newDownMask, newUpMask);
 124     }
 125 
 126     @Override
 127     public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
 128         if (forX.isConstant() && !forY.isConstant()) {
 129             return new IntegerAddExactNode(forY, forX, guard).canonical(tool);
 130         }
 131         if (forX.isConstant() && forY.isConstant()) {
 132             return canonicalXYconstant(forX, forY);



 133         } else if (forY.isConstant()) {
 134             long c = forY.asJavaConstant().asLong();
 135             if (c == 0) {
 136                 return forX;
 137             }
 138         }
 139         if (!IntegerStamp.addCanOverflow((IntegerStamp) forX.stamp(NodeView.DEFAULT), (IntegerStamp) forY.stamp(NodeView.DEFAULT))) {
 140             return new AddNode(forX, forY).canonical(tool);
 141         }
 142         return this;
 143     }
 144 
 145     private ValueNode canonicalXYconstant(ValueNode forX, ValueNode forY) {
 146         JavaConstant xConst = forX.asJavaConstant();
 147         JavaConstant yConst = forY.asJavaConstant();
 148         assert xConst.getJavaKind() == yConst.getJavaKind();
 149         try {
 150             if (xConst.getJavaKind() == JavaKind.Int) {
 151                 return ConstantNode.forInt(Math.addExact(xConst.asInt(), yConst.asInt()));
 152             } else {
 153                 assert xConst.getJavaKind() == JavaKind.Long;
 154                 return ConstantNode.forLong(Math.addExact(xConst.asLong(), yConst.asLong()));




 155             }
 156         } catch (ArithmeticException ex) {
 157             // The operation will result in an overflow exception, so do not canonicalize.
 158         }
 159         return this;















 160     }
 161 
 162     @Override
 163     public GuardingNode getGuard() {
 164         return guard;

 165     }
 166 
 167     @Override
 168     public void setGuard(GuardingNode guard) {
 169         updateUsagesInterface(this.guard, guard);
 170         this.guard = guard;
 171     }
 172 }
< prev index next >