AddNode.java revision 12651:6ef01bd40ce2
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 */
23package org.graalvm.compiler.nodes.calc;
24
25import org.graalvm.compiler.core.common.type.ArithmeticOpTable;
26import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp;
27import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp.Add;
28import org.graalvm.compiler.core.common.type.Stamp;
29import org.graalvm.compiler.graph.NodeClass;
30import org.graalvm.compiler.graph.spi.Canonicalizable.BinaryCommutative;
31import org.graalvm.compiler.graph.spi.CanonicalizerTool;
32import org.graalvm.compiler.lir.gen.ArithmeticLIRGeneratorTool;
33import org.graalvm.compiler.nodeinfo.NodeInfo;
34import org.graalvm.compiler.nodes.ConstantNode;
35import org.graalvm.compiler.nodes.ValueNode;
36import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
37
38import jdk.vm.ci.meta.Constant;
39import jdk.vm.ci.meta.Value;
40
41@NodeInfo(shortName = "+")
42public class AddNode extends BinaryArithmeticNode<Add> implements NarrowableArithmeticNode, BinaryCommutative<ValueNode> {
43
44    public static final NodeClass<AddNode> TYPE = NodeClass.create(AddNode.class);
45
46    public AddNode(ValueNode x, ValueNode y) {
47        this(TYPE, x, y);
48    }
49
50    protected AddNode(NodeClass<? extends AddNode> c, ValueNode x, ValueNode y) {
51        super(c, ArithmeticOpTable::getAdd, x, y);
52    }
53
54    public static ValueNode create(ValueNode x, ValueNode y) {
55        BinaryOp<Add> op = ArithmeticOpTable.forStamp(x.stamp()).getAdd();
56        Stamp stamp = op.foldStamp(x.stamp(), y.stamp());
57        ConstantNode tryConstantFold = tryConstantFold(op, x, y, stamp);
58        if (tryConstantFold != null) {
59            return tryConstantFold;
60        } else {
61            return new AddNode(x, y).maybeCommuteInputs();
62        }
63    }
64
65    @Override
66    public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
67        ValueNode ret = super.canonical(tool, forX, forY);
68        if (ret != this) {
69            return ret;
70        }
71
72        if (forX.isConstant() && !forY.isConstant()) {
73            // we try to swap and canonicalize
74            ValueNode improvement = canonical(tool, forY, forX);
75            if (improvement != this) {
76                return improvement;
77            }
78            // if this fails we only swap
79            return new AddNode(forY, forX);
80        }
81        BinaryOp<Add> op = getOp(forX, forY);
82        boolean associative = op.isAssociative();
83        if (associative) {
84            if (forX instanceof SubNode) {
85                SubNode sub = (SubNode) forX;
86                if (sub.getY() == forY) {
87                    // (a - b) + b
88                    return sub.getX();
89                }
90            }
91            if (forY instanceof SubNode) {
92                SubNode sub = (SubNode) forY;
93                if (sub.getY() == forX) {
94                    // b + (a - b)
95                    return sub.getX();
96                }
97            }
98        }
99        if (forY.isConstant()) {
100            Constant c = forY.asConstant();
101            if (op.isNeutral(c)) {
102                return forX;
103            }
104            if (associative) {
105                // canonicalize expressions like "(a + 1) + 2"
106                BinaryNode reassociated = reassociate(this, ValueNode.isConstantPredicate(), forX, forY);
107                if (reassociated != this) {
108                    return reassociated;
109                }
110            }
111        }
112        if (forX instanceof NegateNode) {
113            return BinaryArithmeticNode.sub(forY, ((NegateNode) forX).getValue());
114        } else if (forY instanceof NegateNode) {
115            return BinaryArithmeticNode.sub(forX, ((NegateNode) forY).getValue());
116        }
117        return this;
118    }
119
120    @Override
121    public void generate(NodeLIRBuilderTool nodeValueMap, ArithmeticLIRGeneratorTool gen) {
122        Value op1 = nodeValueMap.operand(getX());
123        assert op1 != null : getX() + ", this=" + this;
124        Value op2 = nodeValueMap.operand(getY());
125        if (shouldSwapInputs(nodeValueMap)) {
126            Value tmp = op1;
127            op1 = op2;
128            op2 = tmp;
129        }
130        nodeValueMap.setResult(this, gen.emitAdd(op1, op2, false));
131    }
132}
133