001/*
002 * Copyright (c) 2013, 2014, 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;
024
025import com.oracle.graal.graph.*;
026import com.oracle.graal.graph.spi.*;
027import com.oracle.graal.nodeinfo.*;
028
029@NodeInfo
030public final class ShortCircuitOrNode extends LogicNode implements IterableNodeType, Canonicalizable.Binary<LogicNode> {
031
032    public static final NodeClass<ShortCircuitOrNode> TYPE = NodeClass.create(ShortCircuitOrNode.class);
033    @Input(InputType.Condition) LogicNode x;
034    @Input(InputType.Condition) LogicNode y;
035    protected boolean xNegated;
036    protected boolean yNegated;
037    protected double shortCircuitProbability;
038
039    public ShortCircuitOrNode(LogicNode x, boolean xNegated, LogicNode y, boolean yNegated, double shortCircuitProbability) {
040        super(TYPE);
041        this.x = x;
042        this.xNegated = xNegated;
043        this.y = y;
044        this.yNegated = yNegated;
045        this.shortCircuitProbability = shortCircuitProbability;
046    }
047
048    public LogicNode getX() {
049        return x;
050    }
051
052    public LogicNode getY() {
053        return y;
054    }
055
056    public boolean isXNegated() {
057        return xNegated;
058    }
059
060    public boolean isYNegated() {
061        return yNegated;
062    }
063
064    /**
065     * Gets the probability that the {@link #getY() y} part of this binary node is <b>not</b>
066     * evaluated. This is the probability that this operator will short-circuit its execution.
067     */
068    public double getShortCircuitProbability() {
069        return shortCircuitProbability;
070    }
071
072    protected ShortCircuitOrNode canonicalizeNegation(LogicNode forX, LogicNode forY) {
073        LogicNode xCond = forX;
074        boolean xNeg = xNegated;
075        while (xCond instanceof LogicNegationNode) {
076            xCond = ((LogicNegationNode) xCond).getValue();
077            xNeg = !xNeg;
078        }
079
080        LogicNode yCond = forY;
081        boolean yNeg = yNegated;
082        while (yCond instanceof LogicNegationNode) {
083            yCond = ((LogicNegationNode) yCond).getValue();
084            yNeg = !yNeg;
085        }
086
087        if (xCond != forX || yCond != forY) {
088            return new ShortCircuitOrNode(xCond, xNeg, yCond, yNeg, shortCircuitProbability);
089        } else {
090            return this;
091        }
092    }
093
094    public LogicNode canonical(CanonicalizerTool tool, LogicNode forX, LogicNode forY) {
095        ShortCircuitOrNode ret = canonicalizeNegation(forX, forY);
096        if (ret != this) {
097            return ret;
098        }
099
100        if (forX == forY) {
101            // @formatter:off
102            //  a ||  a = a
103            //  a || !a = true
104            // !a ||  a = true
105            // !a || !a = !a
106            // @formatter:on
107            if (isXNegated()) {
108                if (isYNegated()) {
109                    // !a || !a = !a
110                    return LogicNegationNode.create(forX);
111                } else {
112                    // !a || a = true
113                    return LogicConstantNode.tautology();
114                }
115            } else {
116                if (isYNegated()) {
117                    // a || !a = true
118                    return LogicConstantNode.tautology();
119                } else {
120                    // a || a = a
121                    return forX;
122                }
123            }
124        }
125        if (forX instanceof LogicConstantNode) {
126            if (((LogicConstantNode) forX).getValue() ^ isXNegated()) {
127                return LogicConstantNode.tautology();
128            } else {
129                if (isYNegated()) {
130                    return new LogicNegationNode(forY);
131                } else {
132                    return forY;
133                }
134            }
135        }
136        if (forY instanceof LogicConstantNode) {
137            if (((LogicConstantNode) forY).getValue() ^ isYNegated()) {
138                return LogicConstantNode.tautology();
139            } else {
140                if (isXNegated()) {
141                    return new LogicNegationNode(forX);
142                } else {
143                    return forX;
144                }
145            }
146        }
147        return this;
148    }
149}