001/* 002 * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. 003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 004 * 005 * This code is free software; you can redistribute it and/or modify it 006 * under the terms of the GNU General Public License version 2 only, as 007 * published by the Free Software Foundation. 008 * 009 * This code is distributed in the hope that it will be useful, but WITHOUT 010 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 011 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 012 * version 2 for more details (a copy is included in the LICENSE file that 013 * accompanied this code). 014 * 015 * You should have received a copy of the GNU General Public License version 016 * 2 along with this work; if not, write to the Free Software Foundation, 017 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 018 * 019 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 020 * or visit www.oracle.com if you need additional information or have any 021 * questions. 022 */ 023package com.oracle.graal.replacements.nodes.arithmetic; 024 025import jdk.internal.jvmci.code.*; 026import jdk.internal.jvmci.meta.*; 027 028import com.oracle.graal.compiler.common.type.*; 029import com.oracle.graal.graph.*; 030import com.oracle.graal.graph.spi.*; 031import com.oracle.graal.nodeinfo.*; 032import com.oracle.graal.nodes.*; 033import com.oracle.graal.nodes.calc.*; 034import com.oracle.graal.nodes.spi.*; 035 036import static com.oracle.graal.compiler.common.type.IntegerStamp.*; 037 038/** 039 * Node representing an exact integer addition that will throw an {@link ArithmeticException} in 040 * case the addition would overflow the 32 bit range. 041 */ 042@NodeInfo 043public final class IntegerAddExactNode extends AddNode implements IntegerExactArithmeticNode { 044 public static final NodeClass<IntegerAddExactNode> TYPE = NodeClass.create(IntegerAddExactNode.class); 045 046 public IntegerAddExactNode(ValueNode x, ValueNode y) { 047 super(TYPE, x, y); 048 setStamp(foldStamp(x.stamp(), y.stamp())); 049 assert x.stamp().isCompatible(y.stamp()) && x.stamp() instanceof IntegerStamp; 050 } 051 052 @Override 053 public boolean inferStamp() { 054 return updateStamp(foldStamp(x.stamp(), y.stamp())); 055 } 056 057 private static Stamp foldStamp(Stamp stamp1, Stamp stamp2) { 058 IntegerStamp a = (IntegerStamp) stamp1; 059 IntegerStamp b = (IntegerStamp) stamp2; 060 061 int bits = a.getBits(); 062 assert bits == b.getBits(); 063 064 long defaultMask = CodeUtil.mask(bits); 065 long variableBits = (a.downMask() ^ a.upMask()) | (b.downMask() ^ b.upMask()); 066 long variableBitsWithCarry = variableBits | (carryBits(a.downMask(), b.downMask()) ^ carryBits(a.upMask(), b.upMask())); 067 long newDownMask = (a.downMask() + b.downMask()) & ~variableBitsWithCarry; 068 long newUpMask = (a.downMask() + b.downMask()) | variableBitsWithCarry; 069 070 newDownMask &= defaultMask; 071 newUpMask &= defaultMask; 072 073 long newLowerBound; 074 long newUpperBound; 075 boolean lowerOverflowsPositively = addOverflowsPositively(a.lowerBound(), b.lowerBound(), bits); 076 boolean upperOverflowsPositively = addOverflowsPositively(a.upperBound(), b.upperBound(), bits); 077 boolean lowerOverflowsNegatively = addOverflowsNegatively(a.lowerBound(), b.lowerBound(), bits); 078 boolean upperOverflowsNegatively = addOverflowsNegatively(a.upperBound(), b.upperBound(), bits); 079 if (lowerOverflowsPositively) { 080 newLowerBound = CodeUtil.maxValue(bits); 081 } else if (lowerOverflowsNegatively) { 082 newLowerBound = CodeUtil.minValue(bits); 083 } else { 084 newLowerBound = CodeUtil.signExtend((a.lowerBound() + b.lowerBound()) & defaultMask, bits); 085 } 086 087 if (upperOverflowsPositively) { 088 newUpperBound = CodeUtil.maxValue(bits); 089 } else if (upperOverflowsNegatively) { 090 newUpperBound = CodeUtil.minValue(bits); 091 } else { 092 newUpperBound = CodeUtil.signExtend((a.upperBound() + b.upperBound()) & defaultMask, bits); 093 } 094 095 IntegerStamp limit = StampFactory.forInteger(bits, newLowerBound, newUpperBound); 096 newUpMask &= limit.upMask(); 097 newUpperBound = CodeUtil.signExtend(newUpperBound & newUpMask, bits); 098 newDownMask |= limit.downMask(); 099 newLowerBound |= newDownMask; 100 return new IntegerStamp(bits, newLowerBound, newUpperBound, newDownMask, newUpMask); 101 } 102 103 @Override 104 public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) { 105 ValueNode result = findSynonym(forX, forY); 106 if (result == null) { 107 return this; 108 } else { 109 return result; 110 } 111 } 112 113 private static ValueNode findSynonym(ValueNode forX, ValueNode forY) { 114 if (forX.isConstant() && !forY.isConstant()) { 115 return new IntegerAddExactNode(forY, forX); 116 } 117 if (forX.isConstant()) { 118 ConstantNode constantNode = canonicalXconstant(forX, forY); 119 if (constantNode != null) { 120 return constantNode; 121 } 122 } else if (forY.isConstant()) { 123 long c = forY.asJavaConstant().asLong(); 124 if (c == 0) { 125 return forX; 126 } 127 } 128 return null; 129 } 130 131 private static ConstantNode canonicalXconstant(ValueNode forX, ValueNode forY) { 132 JavaConstant xConst = forX.asJavaConstant(); 133 JavaConstant yConst = forY.asJavaConstant(); 134 if (xConst != null && yConst != null) { 135 assert xConst.getKind() == yConst.getKind(); 136 try { 137 if (xConst.getKind() == Kind.Int) { 138 return ConstantNode.forInt(Math.addExact(xConst.asInt(), yConst.asInt())); 139 } else { 140 assert xConst.getKind() == Kind.Long; 141 return ConstantNode.forLong(Math.addExact(xConst.asLong(), yConst.asLong())); 142 } 143 } catch (ArithmeticException ex) { 144 // The operation will result in an overflow exception, so do not canonicalize. 145 } 146 } 147 return null; 148 } 149 150 @Override 151 public IntegerExactArithmeticSplitNode createSplit(AbstractBeginNode next, AbstractBeginNode deopt) { 152 return graph().add(new IntegerAddExactSplitNode(stamp(), getX(), getY(), next, deopt)); 153 } 154 155 @Override 156 public void lower(LoweringTool tool) { 157 IntegerExactArithmeticSplitNode.lower(tool, this); 158 } 159}