001/*
002 * Copyright (c) 2009, 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.calc;
024
025import static com.oracle.graal.nodes.calc.CompareNode.*;
026import jdk.internal.jvmci.meta.*;
027
028import com.oracle.graal.compiler.common.calc.*;
029import com.oracle.graal.compiler.common.type.*;
030import com.oracle.graal.graph.*;
031import com.oracle.graal.graph.spi.*;
032import com.oracle.graal.nodeinfo.*;
033import com.oracle.graal.nodes.*;
034import com.oracle.graal.nodes.spi.*;
035
036/**
037 * The {@code ConditionalNode} class represents a comparison that yields one of two values. Note
038 * that these nodes are not built directly from the bytecode but are introduced by canonicalization.
039 */
040@NodeInfo
041public final class ConditionalNode extends FloatingNode implements Canonicalizable, LIRLowerable {
042
043    public static final NodeClass<ConditionalNode> TYPE = NodeClass.create(ConditionalNode.class);
044    @Input(InputType.Condition) LogicNode condition;
045    @Input ValueNode trueValue;
046    @Input ValueNode falseValue;
047
048    public LogicNode condition() {
049        return condition;
050    }
051
052    public ConditionalNode(LogicNode condition) {
053        this(condition, ConstantNode.forInt(1, condition.graph()), ConstantNode.forInt(0, condition.graph()));
054    }
055
056    public ConditionalNode(LogicNode condition, ValueNode trueValue, ValueNode falseValue) {
057        super(TYPE, trueValue.stamp().meet(falseValue.stamp()));
058        assert trueValue.stamp().isCompatible(falseValue.stamp());
059        this.condition = condition;
060        this.trueValue = trueValue;
061        this.falseValue = falseValue;
062    }
063
064    public static ValueNode create(LogicNode condition) {
065        return create(condition, ConstantNode.forInt(1, condition.graph()), ConstantNode.forInt(0, condition.graph()));
066    }
067
068    public static ValueNode create(LogicNode condition, ValueNode trueValue, ValueNode falseValue) {
069        ValueNode synonym = findSynonym(condition, trueValue, falseValue);
070        if (synonym != null) {
071            return synonym;
072        }
073        return new ConditionalNode(condition, trueValue, falseValue);
074    }
075
076    @Override
077    public boolean inferStamp() {
078        return updateStamp(trueValue.stamp().meet(falseValue.stamp()));
079    }
080
081    public ValueNode trueValue() {
082        return trueValue;
083    }
084
085    public ValueNode falseValue() {
086        return falseValue;
087    }
088
089    @Override
090    public ValueNode canonical(CanonicalizerTool tool) {
091        ValueNode synonym = findSynonym(condition, trueValue(), falseValue());
092        if (synonym != null) {
093            return synonym;
094        }
095
096        // this optimizes the case where a value that can only be 0 or 1 is materialized to 0 or 1
097        if (trueValue().isConstant() && falseValue().isConstant() && condition instanceof IntegerEqualsNode) {
098            IntegerEqualsNode equals = (IntegerEqualsNode) condition;
099            if (equals.getY().isConstant() && equals.getY().asConstant().equals(JavaConstant.INT_0) && equals.getX().stamp() instanceof IntegerStamp) {
100                IntegerStamp equalsXStamp = (IntegerStamp) equals.getX().stamp();
101                if (equalsXStamp.upMask() == 1) {
102                    if (trueValue().asConstant().equals(JavaConstant.INT_0) && falseValue().asConstant().equals(JavaConstant.INT_1)) {
103                        return IntegerConvertNode.convertUnsigned(equals.getX(), stamp());
104                    }
105                }
106            }
107        }
108        if (condition instanceof CompareNode && ((CompareNode) condition).condition() == Condition.EQ) {
109            // optimize the pattern (x == y) ? x : y
110            CompareNode compare = (CompareNode) condition;
111            if ((compare.getX() == trueValue() && compare.getY() == falseValue()) || (compare.getX() == falseValue() && compare.getY() == trueValue())) {
112                return falseValue();
113            }
114        }
115        if (trueValue() == falseValue()) {
116            return trueValue();
117        }
118
119        return this;
120    }
121
122    private static ValueNode findSynonym(ValueNode condition, ValueNode trueValue, ValueNode falseValue) {
123        if (condition instanceof LogicNegationNode) {
124            LogicNegationNode negated = (LogicNegationNode) condition;
125            return ConditionalNode.create(negated.getValue(), falseValue, trueValue);
126        }
127        if (condition instanceof LogicConstantNode) {
128            LogicConstantNode c = (LogicConstantNode) condition;
129            if (c.getValue()) {
130                return trueValue;
131            } else {
132                return falseValue;
133            }
134        }
135        return null;
136    }
137
138    @Override
139    public void generate(NodeLIRBuilderTool generator) {
140        generator.emitConditional(this);
141    }
142
143    public ConditionalNode(StructuredGraph graph, Condition condition, ValueNode x, ValueNode y) {
144        this(createCompareNode(graph, condition, x, y, null));
145    }
146}