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 }