001/*
002 * Copyright (c) 2011, 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.nodes.calc;
024
025import jdk.internal.jvmci.meta.*;
026
027import com.oracle.graal.compiler.common.type.*;
028import com.oracle.graal.compiler.common.type.ArithmeticOpTable.BinaryOp;
029import com.oracle.graal.compiler.common.type.ArithmeticOpTable.BinaryOp.Sub;
030import com.oracle.graal.graph.*;
031import com.oracle.graal.graph.spi.*;
032import com.oracle.graal.lir.gen.*;
033import com.oracle.graal.nodeinfo.*;
034import com.oracle.graal.nodes.*;
035import com.oracle.graal.nodes.spi.*;
036import com.oracle.graal.nodes.util.*;
037
038@NodeInfo(shortName = "-")
039public class SubNode extends BinaryArithmeticNode<Sub> implements NarrowableArithmeticNode {
040
041    public static final NodeClass<SubNode> TYPE = NodeClass.create(SubNode.class);
042
043    public SubNode(ValueNode x, ValueNode y) {
044        this(TYPE, x, y);
045    }
046
047    protected SubNode(NodeClass<? extends SubNode> c, ValueNode x, ValueNode y) {
048        super(c, ArithmeticOpTable::getSub, x, y);
049    }
050
051    public static ValueNode create(ValueNode x, ValueNode y) {
052        BinaryOp<Sub> op = ArithmeticOpTable.forStamp(x.stamp()).getSub();
053        Stamp stamp = op.foldStamp(x.stamp(), y.stamp());
054        ConstantNode tryConstantFold = tryConstantFold(op, x, y, stamp);
055        if (tryConstantFold != null) {
056            return tryConstantFold;
057        } else {
058            return new SubNode(x, y);
059        }
060    }
061
062    @SuppressWarnings("hiding")
063    @Override
064    public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
065        ValueNode ret = super.canonical(tool, forX, forY);
066        if (ret != this) {
067            return ret;
068        }
069
070        BinaryOp<Sub> op = getOp(forX, forY);
071        if (GraphUtil.unproxify(forX) == GraphUtil.unproxify(forY)) {
072            Constant zero = op.getZero(forX.stamp());
073            if (zero != null) {
074                return ConstantNode.forPrimitive(stamp(), zero);
075            }
076        }
077        boolean associative = op.isAssociative();
078        if (associative) {
079            if (forX instanceof AddNode) {
080                AddNode x = (AddNode) forX;
081                if (x.getY() == forY) {
082                    // (a + b) - b
083                    return x.getX();
084                }
085                if (x.getX() == forY) {
086                    // (a + b) - a
087                    return x.getY();
088                }
089            } else if (forX instanceof SubNode) {
090                SubNode x = (SubNode) forX;
091                if (x.getX() == forY) {
092                    // (a - b) - a
093                    return new NegateNode(x.getY());
094                }
095            }
096            if (forY instanceof AddNode) {
097                AddNode y = (AddNode) forY;
098                if (y.getX() == forX) {
099                    // a - (a + b)
100                    return new NegateNode(y.getY());
101                }
102                if (y.getY() == forX) {
103                    // b - (a + b)
104                    return new NegateNode(y.getX());
105                }
106            } else if (forY instanceof SubNode) {
107                SubNode y = (SubNode) forY;
108                if (y.getX() == forX) {
109                    // a - (a - b)
110                    return y.getY();
111                }
112            }
113        }
114        if (forY.isConstant()) {
115            Constant c = forY.asConstant();
116            if (op.isNeutral(c)) {
117                return forX;
118            }
119            if (associative) {
120                BinaryNode reassociated = reassociate(this, ValueNode.isConstantPredicate(), forX, forY);
121                if (reassociated != this) {
122                    return reassociated;
123                }
124            }
125            if (c instanceof PrimitiveConstant && ((PrimitiveConstant) c).getKind().isNumericInteger()) {
126                long i = ((PrimitiveConstant) c).asLong();
127                if (i < 0 || ((IntegerStamp) StampFactory.forKind(forY.getKind())).contains(-i)) {
128                    // Adding a negative is more friendly to the backend since adds are
129                    // commutative, so prefer add when it fits.
130                    return BinaryArithmeticNode.add(forX, ConstantNode.forIntegerStamp(stamp(), -i));
131                }
132            }
133        } else if (forX.isConstant()) {
134            Constant c = forX.asConstant();
135            if (ArithmeticOpTable.forStamp(stamp()).getAdd().isNeutral(c)) {
136                /*
137                 * Note that for floating point numbers, + and - have different neutral elements. We
138                 * have to test for the neutral element of +, because we are doing this
139                 * transformation: 0 - x == (-x) + 0 == -x.
140                 */
141                return new NegateNode(forY);
142            }
143            if (associative) {
144                return reassociate(this, ValueNode.isConstantPredicate(), forX, forY);
145            }
146        }
147        if (forY instanceof NegateNode) {
148            return BinaryArithmeticNode.add(forX, ((NegateNode) forY).getValue());
149        }
150        return this;
151    }
152
153    @Override
154    public void generate(NodeValueMap nodeValueMap, ArithmeticLIRGenerator gen) {
155        nodeValueMap.setResult(this, gen.emitSub(nodeValueMap.operand(getX()), nodeValueMap.operand(getY()), false));
156    }
157}