1 /* 2 * Copyright (c) 2011, 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.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.IntegerStamp; 31 import org.graalvm.compiler.core.common.type.Stamp; 32 import org.graalvm.compiler.graph.NodeClass; 33 import org.graalvm.compiler.graph.spi.Canonicalizable.BinaryCommutative; 34 import org.graalvm.compiler.graph.spi.CanonicalizerTool; 35 import org.graalvm.compiler.lir.gen.ArithmeticLIRGeneratorTool; 36 import org.graalvm.compiler.nodeinfo.NodeInfo; 37 import org.graalvm.compiler.nodes.ConstantNode; 38 import org.graalvm.compiler.nodes.NodeView; 39 import org.graalvm.compiler.nodes.ValueNode; 40 import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; 41 42 import jdk.vm.ci.code.CodeUtil; 43 import jdk.vm.ci.meta.Constant; 44 import jdk.vm.ci.meta.JavaConstant; 45 import jdk.vm.ci.meta.Value; 46 47 @NodeInfo(shortName = "+") 48 public class AddNode extends BinaryArithmeticNode<Add> implements NarrowableArithmeticNode, BinaryCommutative<ValueNode> { 49 50 public static final NodeClass<AddNode> TYPE = NodeClass.create(AddNode.class); 51 52 public AddNode(ValueNode x, ValueNode y) { 53 this(TYPE, x, y); 54 } 55 56 protected AddNode(NodeClass<? extends AddNode> c, ValueNode x, ValueNode y) { 57 super(c, ArithmeticOpTable::getAdd, x, y); 58 } 59 60 public static ValueNode create(ValueNode x, ValueNode y, NodeView view) { 61 BinaryOp<Add> op = ArithmeticOpTable.forStamp(x.stamp(view)).getAdd(); 62 Stamp stamp = op.foldStamp(x.stamp(view), y.stamp(view)); 63 ConstantNode tryConstantFold = tryConstantFold(op, x, y, stamp, view); 64 if (tryConstantFold != null) { 65 return tryConstantFold; 66 } 67 if (x.isConstant() && !y.isConstant()) { 68 return canonical(null, op, y, x, view); 69 } else { 70 return canonical(null, op, x, y, view); 71 } 72 } 73 74 private static ValueNode canonical(AddNode addNode, BinaryOp<Add> op, ValueNode forX, ValueNode forY, NodeView view) { 75 AddNode self = addNode; 76 boolean associative = op.isAssociative(); 77 if (associative) { 78 if (forX instanceof SubNode) { 79 SubNode sub = (SubNode) forX; 80 if (sub.getY() == forY) { 81 // (a - b) + b 82 return sub.getX(); 83 } 84 } 85 if (forY instanceof SubNode) { 86 SubNode sub = (SubNode) forY; 87 if (sub.getY() == forX) { 88 // b + (a - b) 89 return sub.getX(); 90 } 91 } 92 } 93 if (forY.isConstant()) { 94 Constant c = forY.asConstant(); 95 if (op.isNeutral(c)) { 96 return forX; 97 } 98 if (associative && self != null) { 99 // canonicalize expressions like "(a + 1) + 2" 100 ValueNode reassociated = reassociate(self, ValueNode.isConstantPredicate(), forX, forY, view); 101 if (reassociated != self) { 102 return reassociated; 103 } 104 } 105 106 // Attempt to optimize the pattern of an extend node between two add nodes. 107 if (c instanceof JavaConstant && (forX instanceof SignExtendNode || forX instanceof ZeroExtendNode)) { 108 IntegerConvertNode<?, ?> integerConvertNode = (IntegerConvertNode<?, ?>) forX; 109 ValueNode valueNode = integerConvertNode.getValue(); 110 long constant = ((JavaConstant) c).asLong(); 111 if (valueNode instanceof AddNode) { 112 AddNode addBeforeExtend = (AddNode) valueNode; 113 if (addBeforeExtend.getY().isConstant()) { 114 // There is a second add before the extend node that also has a constant as 115 // second operand. Therefore there will be canonicalizations triggered if we 116 // can move the add above the extension. For this we need to check whether 117 // the result of the addition is the same before the extension (which can be 118 // either zero extend or sign extend). 119 IntegerStamp beforeExtendStamp = (IntegerStamp) addBeforeExtend.stamp(view); 120 int bits = beforeExtendStamp.getBits(); 121 if (constant >= CodeUtil.minValue(bits) && constant <= CodeUtil.maxValue(bits)) { 122 IntegerStamp narrowConstantStamp = IntegerStamp.create(bits, constant, constant); 123 124 if (!IntegerStamp.addCanOverflow(narrowConstantStamp, beforeExtendStamp)) { 125 ConstantNode constantNode = ConstantNode.forIntegerStamp(narrowConstantStamp, constant); 126 if (forX instanceof SignExtendNode) { 127 return SignExtendNode.create(AddNode.create(addBeforeExtend, constantNode, view), integerConvertNode.getResultBits(), view); 128 } else { 129 assert forX instanceof ZeroExtendNode; 130 131 // Must check to not cross zero with the new add. 132 boolean crossesZeroPoint = true; 133 if (constant > 0) { 134 if (beforeExtendStamp.lowerBound() >= 0 || beforeExtendStamp.upperBound() < -constant) { 135 // We are good here. 136 crossesZeroPoint = false; 137 } 138 } else { 139 if (beforeExtendStamp.lowerBound() >= -constant || beforeExtendStamp.upperBound() < 0) { 140 // We are good here as well. 141 crossesZeroPoint = false; 142 } 143 } 144 if (!crossesZeroPoint) { 145 return ZeroExtendNode.create(AddNode.create(addBeforeExtend, constantNode, view), integerConvertNode.getResultBits(), view); 146 } 147 } 148 } 149 } 150 } 151 } 152 } 153 } 154 if (forX instanceof NegateNode) { 155 return BinaryArithmeticNode.sub(forY, ((NegateNode) forX).getValue(), view); 156 } else if (forY instanceof NegateNode) { 157 return BinaryArithmeticNode.sub(forX, ((NegateNode) forY).getValue(), view); 158 } 159 if (self == null) { 160 self = (AddNode) new AddNode(forX, forY).maybeCommuteInputs(); 161 } 162 return self; 163 } 164 165 @Override 166 public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) { 167 ValueNode ret = super.canonical(tool, forX, forY); 168 if (ret != this) { 169 return ret; 170 } 171 172 if (forX.isConstant() && !forY.isConstant()) { 173 // we try to swap and canonicalize 174 ValueNode improvement = canonical(tool, forY, forX); 175 if (improvement != this) { 176 return improvement; 177 } 178 // if this fails we only swap 179 return new AddNode(forY, forX); 180 } 181 BinaryOp<Add> op = getOp(forX, forY); 182 NodeView view = NodeView.from(tool); 183 return canonical(this, op, forX, forY, view); 184 } 185 186 @Override 187 public void generate(NodeLIRBuilderTool nodeValueMap, ArithmeticLIRGeneratorTool gen) { 188 Value op1 = nodeValueMap.operand(getX()); 189 assert op1 != null : getX() + ", this=" + this; 190 Value op2 = nodeValueMap.operand(getY()); 191 if (shouldSwapInputs(nodeValueMap)) { 192 Value tmp = op1; 193 op1 = op2; 194 op2 = tmp; 195 } 196 nodeValueMap.setResult(this, gen.emitAdd(op1, op2, false)); 197 } 198 }