1 /*
  2  * Copyright (c) 2024, 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.Collections;
 29 import java.util.LinkedHashSet;
 30 import java.util.List;
 31 import java.util.Set;
 32 
 33 /**
 34  * A value, that is the result of an operation or a block parameter.
 35  * @sealedGraph
 36  */
 37 public sealed abstract class Value implements Comparable<Value>, CodeItem
 38         permits Block.Parameter, Op.Result {
 39     final Block block;
 40     final TypeElement type;
 41     // @@@ In topological order?
 42     //     Can the representation be more efficient e.g. an array?
 43     final Set<Op.Result> uses;
 44 
 45     Value(Block block, TypeElement type) {
 46         this.block = block;
 47         this.type = type;
 48         this.uses = new LinkedHashSet<>();
 49     }
 50 
 51     /**
 52      * Returns this value's declaring block.
 53      * <p>If the value is an operation result, then the declaring block is the operation's parent block.
 54      * If the value is a block parameter then the declaring block is the block declaring the parameter.
 55      *
 56      * @return the value's declaring block.
 57      * @throws IllegalStateException if the declaring block is partially built
 58      */
 59     public Block declaringBlock() {
 60         if (!isBound()) {
 61             throw new IllegalStateException("Declaring block is partially constructed");
 62         }
 63         return block;
 64     }
 65 
 66     /**
 67      * Returns the type of the value.
 68      *
 69      * @return the type of the value.
 70      */
 71     public TypeElement type() {
 72         return type;
 73     }
 74 
 75     /**
 76      * Returns the values this value directly depends on.
 77      * <p>
 78      * An operation result depends on the set of values whose members are the operation's operands and block arguments
 79      * of the operation's successors.
 80      * A block parameter does not depend on any values.
 81      *
 82      * @return the values this value directly depends on, as an unmodifiable set.
 83      */
 84     public abstract Set<Value> dependsOn();
 85 
 86     /**
 87      * Returns the uses of this value, specifically each operation result of an operation where this value is used as
 88      * an operand or as an argument of a block reference that is a successor.
 89      *
 90      * @return the uses of this value, as an unmodifiable set.
 91      * @throws IllegalStateException if the declaring block is partially built
 92      */
 93     public Set<Op.Result> uses() {
 94         if (!isBound()) {
 95             throw new IllegalStateException("Users are partially constructed");
 96         }
 97 
 98         return Collections.unmodifiableSet(uses);
 99     }
100 
101     /**
102      * Returns {@code true} if this value is dominated by the given value {@code dom}.
103      * <p>
104      * If {@code v} and {@code dom} are in not declared in the same block then, domination is the result of
105      * if the declaring block of {@code v} is dominated by the declaring block of {@code dom}.
106      * <p>
107      * Otherwise, if {@code v} and {@code dom} are declared in the same block then (in order):
108      * <ul>
109      * <li>if {@code dom} is a block parameter, then {@code v} is dominated by {@code dom}.
110      * <li>if {@code v} is a block parameter, then {@code v} is <b>not</b> dominated by {@code dom}.
111      * <li>otherwise, both {@code v} and {@code dom} are operation results, then {@code v} is dominated by {@code dom}
112      * if {@code v} is the same as {@code dom} or {@code v} occurs after {@code dom} in the declaring block.
113      * </ul>
114      *
115      * @param dom the dominating value
116      * @return {@code true} if this value is dominated by the given value {@code dom}.
117      * @throws IllegalStateException if the declaring block is partially built
118      */
119     public boolean isDominatedBy(Value dom) {
120         if (this == dom) {
121             return true;
122         }
123 
124         if (declaringBlock() != dom.declaringBlock()) {
125             return declaringBlock().isDominatedBy(dom.declaringBlock());
126         }
127 
128         // Any value is dominated by a block parameter
129         if (dom instanceof Block.Parameter) {
130             return true;
131         } else if (this instanceof Block.Parameter) {
132             return false;
133         } else {
134             assert this instanceof Op.Result &&
135                     dom instanceof Op.Result;
136             List<Op> ops = declaringBlock().ops();
137             return ops.indexOf(((Op.Result) this).op()) >= ops.indexOf(((Op.Result) dom).op());
138         }
139     }
140 
141 
142     @Override
143     public int compareTo(Value o) {
144         return compare(this, o);
145     }
146 
147     // @@@
148     public static int compare(Value v1, Value v2) {
149         if (v1 == v2) return 0;
150 
151         Block b1 = v1.declaringBlock();
152         Block b2 = v2.declaringBlock();
153         if (b1 == b2) {
154             if (v1 instanceof Op.Result or1 && v2 instanceof Op.Result or2) {
155                 List<Op> ops = b1.ops();
156                 return Integer.compare(ops.indexOf(or1.op()), ops.indexOf(or2.op()));
157             } else if (v1 instanceof Op.Result) {
158                 // v2 instanceof BlockParameter
159                 return 1;
160             } else if (v2 instanceof Op.Result) {
161                 // v1 instanceof BlockParameter
162                 return -1;
163             } else { // v1 && v2 instanceof BlockParameter
164                 assert v1 instanceof Block.Parameter && v2 instanceof Block.Parameter;
165                 List<Block.Parameter> args = b1.parameters();
166                 return Integer.compare(args.indexOf(v1), args.indexOf(v2));
167             }
168         }
169 
170         Body r1 = b1.parentBody();
171         Body r2 = b2.parentBody();
172         if (r1 == r2) {
173             // @@@ order should be defined by CFG and dominator relations
174             List<Block> bs = r1.blocks();
175             return Integer.compare(bs.indexOf(b1), bs.indexOf(b2));
176         }
177 
178         Op o1 = r1.parentOp();
179         Op o2 = r2.parentOp();
180         if (o1 == o2) {
181             List<Body> rs = o1.bodies();
182             return Integer.compare(rs.indexOf(r1), rs.indexOf(r2));
183         }
184 
185         return compare(o1.result(), o2.result());
186     }
187 
188     boolean isBound() {
189         return block.isBound();
190     }
191 }