1 /*
2 * Copyright (c) 2024, 2026, 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. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package jdk.incubator.code;
27
28 import java.util.*;
29
30 /**
31 * A value, that is the result of an operation or a block parameter.
32 * <p>
33 * A value is considered unbuilt if it's {@link #declaringBlock() declaring block} is unbuilt and
34 * therefore is inaccessible. A value is considered built when the declaring block is built and
35 * therefore is accessible.
36 * @sealedGraph
37 */
38 public sealed abstract class Value implements CodeItem
39 permits Block.Parameter, Op.Result {
40 final Block block;
41 final TypeElement type;
42 // @@@ In topological order?
43 // Can the representation be more efficient e.g. an array?
44 final SequencedSet<Op.Result> uses;
45
46 Value(Block block, TypeElement type) {
47 this.block = block;
48 this.type = type;
49 this.uses = new LinkedHashSet<>();
50 }
51
52 /**
53 * Returns this value's declaring block.
54 * <p>If the value is an operation result, then the declaring block is the operation's parent block.
55 * If the value is a block parameter then the declaring block is the block declaring the parameter.
56 *
57 * @return the value's declaring block.
58 * @throws IllegalStateException if this value is unbuilt because its declaring block is unbuilt.
59 */
60 public Block declaringBlock() {
61 if (!isBuilt()) {
62 throw new IllegalStateException("Declaring block is unbuilt");
63 }
64 return block;
65 }
66
67 /**
68 * Returns this value's declaring code element.
69 * <p>If the value is an operation result, then the declaring code element is the operation.
70 * If the value is a block parameter then the declaring code element is this value's declaring block.
71 *
72 * @return the value's declaring code element.
73 * @throws IllegalStateException if this value is a a block parameter and is unbuilt because its declaring block is
74 * unbuilt.
75 */
76 public CodeElement<?, ?> declaringElement() {
77 return switch (this) {
78 case Block.Parameter _ -> block;
79 case Op.Result r -> r.op();
80 };
81 }
82
83 /**
84 * Returns the type of the value.
85 *
86 * @return the type of the value.
87 */
88 public TypeElement type() {
89 return type;
90 }
91
92 /**
93 * Returns this value as an operation result.
94 *
95 * @return the value as an operation result.
96 * @throws IllegalStateException if the value is not an instance of an operation result.
97 */
98 public Op.Result result() {
99 if (this instanceof Op.Result r) {
100 return r;
101 }
102 throw new IllegalStateException("Value is not an instance of operation result");
103 }
104
105 /**
106 * Returns this value as a block parameter.
107 *
108 * @return the value as a block parameter.
109 * @throws IllegalStateException if the value is not an instance of a block parameter.
110 */
111 public Block.Parameter parameter() {
112 if (this instanceof Block.Parameter p) {
113 return p;
114 }
115 throw new IllegalStateException("Value is not an instance of block parameter");
116 }
117
118 /**
119 * Returns the values this value directly depends on.
120 * <p>
121 * An operation result depends on the set of values whose members are the operation's operands and block arguments
122 * of the operation's successors.
123 * A block parameter does not depend on any values, and therefore this method returns an empty sequenced set.
124 *
125 * @return the values this value directly depends on, as an unmodifiable sequenced set. For an operation result the
126 * operation's operands will occur first and then block arguments of each successor.
127 */
128 public abstract SequencedSet<Value> dependsOn();
129
130 /**
131 * Returns the uses of this value, specifically each operation result of an operation where this value is used as
132 * an operand or as an argument of a block reference that is a successor.
133 *
134 * @return the uses of this value, as an unmodifiable sequenced set. The encouncter order is unspecified
135 * and determined by the order in which operations are built into blocks.
136 * @throws IllegalStateException if an unbuilt block is encountered.
137 */
138 public SequencedSet<Op.Result> uses() {
139 if (!isBuilt()) {
140 throw new IllegalStateException("Users are are unbuilt");
141 }
142
143 return Collections.unmodifiableSequencedSet(uses);
144 }
145
146 /**
147 * Returns {@code true} if this value is dominated by the given value {@code dom}.
148 * <p>
149 * If {@code v} and {@code dom} are in not declared in the same block then, domination is the result of
150 * if the declaring block of {@code v} is dominated by the declaring block of {@code dom}.
151 * <p>
152 * Otherwise, if {@code v} and {@code dom} are declared in the same block then (in order):
153 * <ul>
154 * <li>if {@code dom} is a block parameter, then {@code v} is dominated by {@code dom}.
155 * <li>if {@code v} is a block parameter, then {@code v} is <b>not</b> dominated by {@code dom}.
156 * <li>otherwise, both {@code v} and {@code dom} are operation results, then {@code v} is dominated by {@code dom}
157 * if {@code v} is the same as {@code dom} or {@code v} occurs after {@code dom} in the declaring block.
158 * </ul>
159 *
160 * @param dom the dominating value
161 * @return {@code true} if this value is dominated by the given value {@code dom}.
162 * @throws IllegalStateException if an unbuilt block is encountered.
163 */
164 public boolean isDominatedBy(Value dom) {
165 if (this == dom) {
166 return true;
167 }
168
169 if (declaringBlock() != dom.declaringBlock()) {
170 return declaringBlock().isDominatedBy(dom.declaringBlock());
171 }
172
173 // Any value is dominated by a block parameter
174 if (dom instanceof Block.Parameter) {
175 return true;
176 } else if (this instanceof Block.Parameter) {
177 return false;
178 } else {
179 assert this instanceof Op.Result &&
180 dom instanceof Op.Result;
181 List<Op> ops = declaringBlock().ops();
182 return ops.indexOf(((Op.Result) this).op()) >= ops.indexOf(((Op.Result) dom).op());
183 }
184 }
185
186 /**
187 * Compares two values by comparing their declaring elements.
188 *
189 * @apiNote
190 * This method behaves is if it returns the result of the following expression but may be implemented more
191 * efficiently.
192 * {@snippet :
193 * Comparator.comparing(Value::declaringElement, CodeElement::compare).compare(a, b)
194 * }
195 * @param a the first value to compare
196 * @param b the second value to compare
197 * @return the value {@code 0} if {@code a == b}; {@code -1} if {@code a} is less than {@code b}; and {@code -1}
198 * if {@code a} is greater than {@code b}.
199 * @throws IllegalArgumentException if {@code a} and {@code b} are not present in the same code model
200 * @throws IllegalStateException if an unbuilt block is encountered.
201 * @see CodeElement#compare
202 */
203 public static int compare(Value a, Value b) {
204 return CodeElement.compare(a.declaringElement(), b.declaringElement());
205 }
206
207 boolean isBuilt() {
208 return block.isBuilt();
209 }
210 }