1 /*
2  * Copyright (c) 2014, 2018, 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 
24 
25 package org.graalvm.compiler.nodes.extended;
26 
27 import static org.graalvm.compiler.nodeinfo.InputType.Guard;
28 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_0;
29 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_0;
30 
31 import org.graalvm.compiler.core.common.type.StampFactory;
32 import org.graalvm.compiler.graph.Node;
33 import org.graalvm.compiler.graph.NodeClass;
34 import org.graalvm.compiler.graph.NodeInputList;
35 import org.graalvm.compiler.graph.spi.Simplifiable;
36 import org.graalvm.compiler.graph.spi.SimplifierTool;
37 import org.graalvm.compiler.nodeinfo.NodeInfo;
38 import org.graalvm.compiler.nodes.StructuredGraph;
39 import org.graalvm.compiler.nodes.ValueNode;
40 import org.graalvm.compiler.nodes.calc.FloatingNode;
41 import org.graalvm.compiler.nodes.spi.LIRLowerable;
42 import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
43 import org.graalvm.compiler.nodes.util.GraphUtil;
44 
45 @NodeInfo(allowedUsageTypes = Guard, cycles = CYCLES_0, size = SIZE_0)
46 public final class MultiGuardNode extends FloatingNode implements GuardingNode, LIRLowerable, Simplifiable, Node.ValueNumberable {
47     public static final NodeClass<MultiGuardNode> TYPE = NodeClass.create(MultiGuardNode.class);
48 
49     @OptionalInput(Guard) NodeInputList<ValueNode> guards;
50 
MultiGuardNode(ValueNode... guards)51     public MultiGuardNode(ValueNode... guards) {
52         super(TYPE, StampFactory.forVoid());
53         this.guards = new NodeInputList<>(this, guards);
54     }
55 
56     @Override
generate(NodeLIRBuilderTool generator)57     public void generate(NodeLIRBuilderTool generator) {
58     }
59 
60     @Override
simplify(SimplifierTool tool)61     public void simplify(SimplifierTool tool) {
62         if (usages().filter(node -> node instanceof ValueAnchorNode).isNotEmpty()) {
63             /*
64              * For ValueAnchorNode usages, we can optimize MultiGuardNodes away if they depend on
65              * zero or one floating nodes (as opposed to fixed nodes).
66              */
67             Node singleFloatingGuard = null;
68             for (ValueNode guard : guards) {
69                 if (GraphUtil.isFloatingNode(guard)) {
70                     if (singleFloatingGuard == null) {
71                         singleFloatingGuard = guard;
72                     } else if (singleFloatingGuard != guard) {
73                         return;
74                     }
75                 }
76             }
77             for (Node usage : usages().snapshot()) {
78                 if (usage instanceof ValueAnchorNode) {
79                     usage.replaceFirstInput(this, singleFloatingGuard);
80                     tool.addToWorkList(usage);
81                 }
82             }
83             if (usages().isEmpty()) {
84                 GraphUtil.killWithUnusedFloatingInputs(this);
85             }
86         }
87     }
88 
addGuard(GuardingNode g)89     public void addGuard(GuardingNode g) {
90         this.guards.add(g.asNode());
91     }
92 
combine(GuardingNode first, GuardingNode second)93     public static GuardingNode combine(GuardingNode first, GuardingNode second) {
94         if (first == null) {
95             return second;
96         } else if (second == null) {
97             return first;
98         } else {
99             StructuredGraph graph = first.asNode().graph();
100             return graph.unique(new MultiGuardNode(first.asNode(), second.asNode()));
101         }
102     }
103 
addGuard(GuardingNode first, GuardingNode second)104     public static GuardingNode addGuard(GuardingNode first, GuardingNode second) {
105         if (first instanceof MultiGuardNode && second != null) {
106             MultiGuardNode multi = (MultiGuardNode) first;
107             multi.addGuard(second);
108             return multi;
109         } else {
110             return combine(first, second);
111         }
112     }
113 }
114