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 package org.graalvm.compiler.nodes.calc; 24 25 import org.graalvm.compiler.core.common.type.ArithmeticOpTable; 26 import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp; 27 import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp.Sub; 28 import org.graalvm.compiler.core.common.type.IntegerStamp; 29 import org.graalvm.compiler.core.common.type.Stamp; 30 import org.graalvm.compiler.core.common.type.StampFactory; 31 import org.graalvm.compiler.graph.NodeClass; 32 import org.graalvm.compiler.graph.spi.CanonicalizerTool; 33 import org.graalvm.compiler.lir.gen.ArithmeticLIRGeneratorTool; 34 import org.graalvm.compiler.nodeinfo.NodeInfo; 35 import org.graalvm.compiler.nodes.ConstantNode; 36 import org.graalvm.compiler.nodes.ValueNode; 37 import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; 38 import org.graalvm.compiler.nodes.util.GraphUtil; 39 40 import jdk.vm.ci.meta.Constant; 41 import jdk.vm.ci.meta.PrimitiveConstant; 42 43 @NodeInfo(shortName = "-") 44 public class SubNode extends BinaryArithmeticNode<Sub> implements NarrowableArithmeticNode { 45 46 public static final NodeClass<SubNode> TYPE = NodeClass.create(SubNode.class); 47 48 public SubNode(ValueNode x, ValueNode y) { 49 this(TYPE, x, y); 50 } 51 52 protected SubNode(NodeClass<? extends SubNode> c, ValueNode x, ValueNode y) { 53 super(c, ArithmeticOpTable::getSub, x, y); 54 } 55 56 public static ValueNode create(ValueNode x, ValueNode y) { 57 BinaryOp<Sub> op = ArithmeticOpTable.forStamp(x.stamp()).getSub(); 58 Stamp stamp = op.foldStamp(x.stamp(), y.stamp()); 59 ConstantNode tryConstantFold = tryConstantFold(op, x, y, stamp); 60 if (tryConstantFold != null) { 61 return tryConstantFold; 62 } else { 63 return new SubNode(x, y); 64 } 65 } 66 67 @SuppressWarnings("hiding") 68 @Override 69 public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) { 70 ValueNode ret = super.canonical(tool, forX, forY); 71 if (ret != this) { 72 return ret; 73 } 74 75 BinaryOp<Sub> op = getOp(forX, forY); 76 if (GraphUtil.unproxify(forX) == GraphUtil.unproxify(forY)) { 77 Constant zero = op.getZero(forX.stamp()); 78 if (zero != null) { 79 return ConstantNode.forPrimitive(stamp(), zero); 80 } 81 } 82 boolean associative = op.isAssociative(); 83 if (associative) { 84 if (forX instanceof AddNode) { 85 AddNode x = (AddNode) forX; 86 if (x.getY() == forY) { 87 // (a + b) - b 88 return x.getX(); 89 } 90 if (x.getX() == forY) { 91 // (a + b) - a 92 return x.getY(); 93 } 94 } else if (forX instanceof SubNode) { 95 SubNode x = (SubNode) forX; 96 if (x.getX() == forY) { 97 // (a - b) - a 98 return new NegateNode(x.getY()); 99 } 100 } 101 if (forY instanceof AddNode) { 102 AddNode y = (AddNode) forY; 103 if (y.getX() == forX) { 104 // a - (a + b) 105 return new NegateNode(y.getY()); 106 } 107 if (y.getY() == forX) { 108 // b - (a + b) 109 return new NegateNode(y.getX()); 110 } 111 } else if (forY instanceof SubNode) { 112 SubNode y = (SubNode) forY; 113 if (y.getX() == forX) { 114 // a - (a - b) 115 return y.getY(); 116 } 117 } 118 } 119 if (forY.isConstant()) { 120 Constant c = forY.asConstant(); 121 if (op.isNeutral(c)) { 122 return forX; 123 } 124 if (associative) { 125 BinaryNode reassociated = reassociate(this, ValueNode.isConstantPredicate(), forX, forY); 126 if (reassociated != this) { 127 return reassociated; 128 } 129 } 130 if (c instanceof PrimitiveConstant && ((PrimitiveConstant) c).getJavaKind().isNumericInteger()) { 131 long i = ((PrimitiveConstant) c).asLong(); 132 if (i < 0 || ((IntegerStamp) StampFactory.forKind(forY.getStackKind())).contains(-i)) { 133 // Adding a negative is more friendly to the backend since adds are 134 // commutative, so prefer add when it fits. 135 return BinaryArithmeticNode.add(forX, ConstantNode.forIntegerStamp(stamp(), -i)); 136 } 137 } 138 } else if (forX.isConstant()) { 139 Constant c = forX.asConstant(); 140 if (ArithmeticOpTable.forStamp(stamp()).getAdd().isNeutral(c)) { 141 /* 142 * Note that for floating point numbers, + and - have different neutral elements. We 143 * have to test for the neutral element of +, because we are doing this 144 * transformation: 0 - x == (-x) + 0 == -x. 145 */ 146 return new NegateNode(forY); 147 } 148 if (associative) { 149 return reassociate(this, ValueNode.isConstantPredicate(), forX, forY); 150 } 151 } 152 if (forY instanceof NegateNode) { 153 return BinaryArithmeticNode.add(forX, ((NegateNode) forY).getValue()); 154 } 155 return this; 156 } 157 158 @Override 159 public void generate(NodeLIRBuilderTool nodeValueMap, ArithmeticLIRGeneratorTool gen) { 160 nodeValueMap.setResult(this, gen.emitSub(nodeValueMap.operand(getX()), nodeValueMap.operand(getY()), false)); 161 } 162 }