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 import java.util.stream.Collectors;
30
31 /**
32 * A (basic) block containing an ordered sequence of operations, where the last operation is
33 * a {@link Op.Terminating terminating} operation.
34 * <p>
35 * The terminating operation, according to its specification, may branch to other blocks contained in the
36 * same parent body, by way of its {@link Op#successors() successors}, or exit the parent body and optionally
37 * yield a result.
38 * <p>
39 * Blocks may declare one or more block parameters.
40 */
41 public final class Block implements CodeElement<Block, Op> {
42
43 /**
44 * A value that is a block parameter
45 */
46 public static final class Parameter extends Value {
47 Parameter(Block block, TypeElement type) {
48 super(block, type);
49 }
50
51 @Override
52 public String toString() {
53 return "%param@" + Integer.toHexString(hashCode());
54 }
55
56 @Override
57 public SequencedSet<Value> dependsOn() {
58 return Collections.emptyNavigableSet();
59 }
60
61 /**
62 * Returns the invokable operation associated with this block parameter.
63 * <p>
64 * If this block parameter is declared in an entry block and that
65 * block's ancestor operation (the parent of the entry block's parent body)
66 * is an instance of {@link Op.Invokable}, then that instance is returned,
67 * otherwise {@code null} is returned.
68 * <p>
69 * A non-{@code null} result implies this parameter is an invokable parameter.
70 *
71 * @apiNote
72 * This method may be used to pattern match on the returned result:
73 * {@snippet lang = "java":
74 * if (p.invokableOperation() instanceof CoreOp.FuncOp f) {
75 * assert f.parameters().indexOf(p) == p.index(); // @link substring="parameters()" target="Op.Invokable#parameters()"
76 * }
77 *}
78 *
79 * @return the invokable operation, otherwise {@code null} if the operation
80 * is not an instance of {@link Op.Invokable}.
81 * @see Op.Invokable#parameters()
82 */
83 public Op.Invokable invokableOperation() {
84 if (declaringBlock().isEntryBlock() &&
85 declaringBlock().ancestorOp() instanceof Op.Invokable o) {
86 return o;
87 } else {
88 return null;
89 }
90 }
91
92 /**
93 * {@return the index of this block parameter in the parameters of its declaring block.}
94 * @see Value#declaringBlock()
95 * @see Block#parameters()
96 */
97 public int index() {
98 return declaringBlock().parameters().indexOf(this);
99 }
100 }
101
102 /**
103 * A block reference that refers to a block with arguments.
104 * <p>
105 * A terminating operation may refer, via a block reference, to one or more blocks as its successors.
106 * When control is passed from a block to a successor block the values of the block reference's arguments are
107 * assigned, in order, to the successor block's parameters.
108 */
109 public static final class Reference implements CodeItem {
110 final Block target;
111 final List<Value> arguments;
112
113 /**
114 * Constructs a block reference for a given target block and arguments.
115 *
116 * @param target the target block.
117 * @param arguments the target block arguments, a copy will be made as needed.
118 */
119 Reference(Block target, List<? extends Value> arguments) {
120 this.target = target;
121 this.arguments = List.copyOf(arguments);
122 }
123
124 /**
125 * {@return the target block.}
126 * @throws IllegalStateException if the target block is partially built
127 */
128 public Block targetBlock() {
129 if (!isBound()) {
130 throw new IllegalStateException("Target block is partially built");
131 }
132
133 return target;
134 }
135
136 /**
137 * {@return the block arguments.}
138 */
139 public List<Value> arguments() {
140 return arguments;
141 }
142
143 boolean isBound() {
144 return target.isBound();
145 }
146 }
147
148 final Body parentBody;
149
150 final List<Parameter> parameters;
151
152 final List<Op> ops;
153
154 // @@@ In topological order
155 // @@@ Create lazily
156 // Can the representation be more efficient e.g. an array?
157 final SequencedSet<Block> predecessors;
158
159 // Reverse postorder index
160 // Set when block's body has sorted its blocks and therefore set when built
161 // Block is inoperable when < 0 i.e., when partially built
162 int index = -1;
163
164 Block(Body parentBody) {
165 this(parentBody, List.of());
166 }
167
168 Block(Body parentBody, List<TypeElement> parameterTypes) {
169 this.parentBody = parentBody;
170 this.parameters = new ArrayList<>();
171 for (TypeElement param : parameterTypes) {
172 parameters.add(new Parameter(this, param));
173 }
174 this.ops = new ArrayList<>();
175 this.predecessors = new LinkedHashSet<>();
176 }
177
178
179 @Override
180 public String toString() {
181 return "^block_" + index + "@" + Integer.toHexString(hashCode());
182 }
183
184 /**
185 * Returns this block's parent body.
186 *
187 * @return this block's parent body.
188 */
189 @Override
190 public Body parent() {
191 return parentBody;
192 }
193
194 @Override
195 public List<Op> children() {
196 return ops();
197 }
198
199 /**
200 * Returns the sequence of operations contained in this block.
201 *
202 * @return returns the sequence operations, as an unmodifiable list.
203 */
204 public List<Op> ops() {
205 return Collections.unmodifiableList(ops);
206 }
207
208 /**
209 * Returns this block's index within the parent body's blocks.
210 * <p>
211 * The following identity holds true:
212 * {@snippet lang = "java" :
213 * this.parentBody().blocks().indexOf(this) == this.index();
214 * }
215 *
216 * @apiNote
217 * The block's index may be used to efficiently track blocks using
218 * bits sets or boolean arrays.
219 *
220 * @return the block index.
221 */
222 public int index() {
223 return index;
224 }
225
226 /**
227 * Returns the block parameters.
228 *
229 * @return the block parameters, as an unmodifiable list.
230 */
231 public List<Parameter> parameters() {
232 return Collections.unmodifiableList(parameters);
233 }
234
235 /**
236 * Returns the block parameter types.
237 *
238 * @return the block parameter types, as am unmodifiable list.
239 */
240 public List<TypeElement> parameterTypes() {
241 return parameters.stream().map(Value::type).toList();
242 }
243
244 /**
245 * Returns the first operation in this block.
246 *
247 * @return the first operation in this block.
248 */
249 public Op firstOp() {
250 return ops.getFirst();
251 }
252
253 /**
254 * Returns the last, terminating, operation in this block.
255 * <p>
256 * The terminating operation implements {@link Op.Terminating}.
257 *
258 * @return the last, terminating, operation in this block.
259 */
260 public Op terminatingOp() {
261 Op lop = ops.getLast();
262 assert lop instanceof Op.Terminating;
263 return lop;
264 }
265
266 /**
267 * Returns the next operation after the given operation, otherwise {@code null}
268 * if this operation is the last operation.
269 *
270 * @param op the operation
271 * @return the next operation after the given operation.
272 */
273 public Op nextOp(Op op) {
274 int i = ops.indexOf(op);
275 if (i == -1) {
276 throw new IllegalArgumentException();
277 }
278 return i < ops().size() - 1 ? ops.get(i + 1) : null;
279 }
280
281 /**
282 * Returns the set of predecessors, the set containing each block in the parent
283 * body that refers to this block as a successor.
284 *
285 * @return the set of predecessors, as an unmodifiable sequenced set. The encouncter order is unspecified
286 * and determined by the order in which operations are built.
287 * @apiNote A block may refer to itself as a successor and therefore also be its predecessor.
288 */
289 public SequencedSet<Block> predecessors() {
290 return Collections.unmodifiableSequencedSet(predecessors);
291 }
292
293 /**
294 * Returns the list of predecessor references to this block.
295 * <p>
296 * This method behaves is if it returns the result of the following expression:
297 * {@snippet lang = java:
298 * predecessors.stream().flatMap(p->successors().stream())
299 * .filter(r->r.targetBlock() == this)
300 * .toList();
301 *}
302 *
303 * @return the list of predecessor references to this block, as an unmodifiable list.
304 * @apiNote A predecessor block may reference it successor block one or more times.
305 */
306 public List<Block.Reference> predecessorReferences() {
307 return predecessors.stream().flatMap(p -> p.successors().stream())
308 .filter(r -> r.targetBlock() == this)
309 .toList();
310 }
311
312 /**
313 * Returns the list of successors referring to other blocks.
314 * <p>
315 * The successors are declared by the terminating operation contained in this block.
316 *
317 * @return the list of successors, as an unmodifiable list.
318 * @apiNote given a block, A say, whose successor targets a block, B say, we can
319 * state that B is a successor block of A and A is a predecessor block of B.
320 */
321 public List<Reference> successors() {
322 return ops.getLast().successors();
323 }
324
325 /**
326 * Returns the set of target blocks referred to by the successors of this block.
327 * <p>
328 * This method behaves is if it returns the result of the following expression:
329 * {@snippet lang = java:
330 * successors().stream()
331 * .map(Block.Reference::targetBlock)
332 * .collect(Collectors.toCollection(LinkedHashSet::new));
333 *}
334 *
335 * @return the set of target blocks, as an unmodifiable set.
336 */
337 public SequencedSet<Block> successorTargets() {
338 return successors().stream().map(Block.Reference::targetBlock)
339 .collect(Collectors.toCollection(LinkedHashSet::new));
340 }
341
342 /**
343 * Returns true if this block is an entry block.
344 *
345 * @return true if this block is an entry block.
346 */
347 public boolean isEntryBlock() {
348 return parentBody.entryBlock() == this;
349 }
350
351 /**
352 * Returns {@code true} if this block is
353 * <a href="https://en.wikipedia.org/wiki/Dominator_(graph_theory)">dominated by</a> the given block {@code dom}.
354 * This block is dominated by {@code dom}, if every path from the root entry block to this block passes through
355 * {@code dom}.
356 * <p>
357 * If this block, {@code b} say, and {@code dom} are not in the same parent body,
358 * then {@code b} becomes the nearest ancestor block, result of {@code b.parentBody().parentOp().parentBlock()},
359 * and so on until either:
360 * {@code b} is {@code null}, therefore {@code b} is <b>not</b> dominated by {@code dom} and this method
361 * returns {@code false}; or
362 * {@code b.parentBody() == dom.parentBody()}, therefore this method returns the result
363 * of {@code b.isDominatedBy(dom)}.
364 * <p>
365 * If this method returns {@code true} then {@code dom.isDominatedBy(this)}
366 * will return {@code false}. However, if this method returns {@code false} then it
367 * does not imply {@code dom.isDominatedBy(this)} returns {@code true}, as neither
368 * block may dominate the other.
369 *
370 * @param dom the dominating block
371 * @return {@code true} if this block is dominated by the given block.
372 */
373 // @@@ Should this be reversed and named dominates(Block b)
374 public boolean isDominatedBy(Block dom) {
375 Block b = findBlockForDomBody(this, dom.ancestorBody());
376 if (b == null) {
377 return false;
378 }
379
380 // A block non-strictly dominates itself
381 if (b == dom) {
382 return true;
383 }
384
385 // The entry block in b's body dominates all other blocks in the body
386 Block entry = b.ancestorBody().entryBlock();
387 if (dom == entry) {
388 return true;
389 }
390
391 // Traverse the immediate dominators until dom is reached or the entry block
392 Map<Block, Block> idoms = b.ancestorBody().immediateDominators();
393 Block idom = idoms.get(b);
394 while (idom != entry) {
395 if (idom == dom) {
396 return true;
397 }
398
399 idom = idoms.get(idom);
400 }
401
402 return false;
403 }
404
405 /**
406 * Returns the immediate dominator of this block, otherwise {@code null} if this block is the entry block.
407 * Both this block and the immediate dominator (if defined) have the same parent body.
408 * <p>
409 * The immediate dominator is the unique block that strictly dominates this block, but does not strictly dominate
410 * any other block that strictly dominates this block.
411 *
412 * @return the immediate dominator of this block, otherwise {@code null} if this block is the entry block.
413 */
414 public Block immediateDominator() {
415 if (this == ancestorBody().entryBlock()) {
416 return null;
417 }
418
419 Map<Block, Block> idoms = ancestorBody().immediateDominators();
420 return idoms.get(this);
421 }
422
423 /**
424 * Returns the immediate post dominator of this block, otherwise {@link Body#IPDOM_EXIT} if this block is the
425 * only block with no successors or if this block is one of many blocks that has no successors.
426 * Both this block and the immediate post dominator (if defined) have the same parent body.
427 * <p>
428 * The post immediate dominator is the unique block that strictly post dominates this block, but does not strictly
429 * post dominate any other block that strictly post dominates this block.
430 *
431 * @return the immediate dominator of this block, otherwise {@code null} if this block is the entry block.
432 */
433 public Block immediatePostDominator() {
434 if (this == ancestorBody().entryBlock()) {
435 return null;
436 }
437
438 Map<Block, Block> ipdoms = ancestorBody().immediatePostDominators();
439 Block ipdom = ipdoms.get(this);
440 return ipdom == this ? Body.IPDOM_EXIT : ipdom;
441 }
442
443 // @@@ isPostDominatedBy and immediatePostDominator
444
445 private static Block findBlockForDomBody(Block b, final Body domr) {
446 Body rb = b.ancestorBody();
447 while (domr != rb) {
448 // @@@ What if body is isolated
449
450 b = rb.ancestorBlock();
451 // null when op is top-level (and its body is isolated), or not yet assigned to block
452 if (b == null) {
453 return null;
454 }
455 rb = b.ancestorBody();
456 }
457 return b;
458 }
459
460 /**
461 * A builder of a block.
462 * <p>
463 * When the parent body builder is built this block builder is also built. If a built builder
464 * is operated on to append a block parameter, append an operation, or add a block, then
465 * an {@code IllegalStateException} is thrown.
466 */
467 public final class Builder {
468 final Body.Builder parentBody;
469 final CodeContext cc;
470 final CodeTransformer ot;
471
472 Builder(Body.Builder parentBody, CodeContext cc, CodeTransformer ot) {
473 this.parentBody = parentBody;
474 this.cc = cc;
475 this.ot = ot;
476 }
477
478 void check() {
479 parentBody.check();
480 }
481
482 Block target() {
483 return Block.this;
484 }
485
486 /**
487 * {@return the block builder's operation transformer}
488 */
489 public CodeTransformer transformer() {
490 return ot;
491 }
492
493 /**
494 * {@return the block builder's context}
495 */
496 public CodeContext context() {
497 return cc;
498 }
499
500 /**
501 * {@return the parent body builder}
502 */
503 public Body.Builder parentBody() {
504 return parentBody;
505 }
506
507 /**
508 * Returns the entry block builder for parent body.
509 *
510 * <p>The returned block is rebound if necessary to this block builder's
511 * context and transformer.
512 *
513 * @return the entry block builder for parent body builder
514 */
515 public Block.Builder entryBlock() {
516 return parentBody.entryBlock.rebind(cc, ot);
517 }
518
519 /**
520 * {@return true if this block builder is a builder of the entry block}
521 */
522 public boolean isEntryBlock() {
523 return Block.this == parentBody.target().entryBlock();
524 }
525
526 /**
527 * Rebinds this block builder with the given context and operation transformer.
528 *
529 * <p>Either this block builder and the returned block builder may be operated on to build
530 * the same block.
531 * Both are equal to each other, and both are closed when the parent body builder is closed.
532 *
533 * @param cc the context
534 * @param ot the operation transformer
535 * @return the rebound block builder
536 */
537 public Block.Builder rebind(CodeContext cc, CodeTransformer ot) {
538 return this.cc == cc && this.ot == ot
539 ? this
540 : this.target().new Builder(parentBody(), cc, ot);
541 }
542
543 /**
544 * Adds a new block to the parent body.
545 *
546 * @param params the block's parameter types
547 * @return the new block builder
548 */
549 public Block.Builder block(TypeElement... params) {
550 return block(List.of(params));
551 }
552
553 /**
554 * Adds a new block to the parent body.
555 *
556 * @param params the block's parameter types
557 * @return the new block builder
558 */
559 public Block.Builder block(List<TypeElement> params) {
560 return parentBody.block(params, cc, ot);
561 }
562
563 /**
564 * Returns an unmodifiable list of the block's parameters.
565 *
566 * @return the unmodifiable list of the block's parameters
567 */
568 public List<Parameter> parameters() {
569 return Collections.unmodifiableList(parameters);
570 }
571
572 /**
573 * Appends a block parameter to the block's parameters.
574 *
575 * @param p the parameter type
576 * @return the appended block parameter
577 */
578 public Parameter parameter(TypeElement p) {
579 check();
580 return appendBlockParameter(p);
581 }
582
583 /**
584 * Creates a reference to this block that can be used as a successor of a terminating operation.
585 *
586 * @param args the block arguments
587 * @return the reference to this block
588 * @throws IllegalStateException if this block builder is associated with the entry block.
589 */
590 public Reference successor(Value... args) {
591 return successor(List.of(args));
592 }
593
594 /**
595 * Creates a reference to this block that can be used as a successor of a terminating operation.
596 *
597 * @param args the block arguments
598 * @return the reference to this block
599 * @throws IllegalStateException if this block builder is associated with the entry block.
600 */
601 public Reference successor(List<? extends Value> args) {
602 if (isEntryBlock()) {
603 throw new IllegalStateException("Entry block cannot be referred to as a successor");
604 }
605
606 return new Reference(Block.this, List.copyOf(args));
607 }
608
609 /**
610 * Transforms a body starting from this block builder, using an operation transformer.
611 * <p>
612 * This method first rebinds this builder with a child context created from
613 * this builder's context and the given operation transformer, and then
614 * transforms the body using the operation transformer by
615 * {@link CodeTransformer#acceptBody(Builder, Body, List) accepting}
616 * the rebound builder, the body, and the values.
617 *
618 * @apiNote
619 * Creation of a child context ensures block and value mappings produced by
620 * the transformation do not affect this builder's context.
621 *
622 * @param body the body to transform
623 * @param values the output values to map to the input parameters of the body's entry block
624 * @param ot the operation transformer
625 * @see CodeTransformer#acceptBody(Builder, Body, List)
626 */
627 public void body(Body body, List<? extends Value> values,
628 CodeTransformer ot) {
629 check();
630
631 ot.acceptBody(rebind(CodeContext.create(cc), ot), body, values);
632 }
633
634 /**
635 * Transforms a body starting from this block builder, using a given operation transformer.
636 * <p>
637 * This method first rebinds this builder with the given context
638 * and the given operation transformer, and then
639 * transforms the body using the operation transformer by
640 * {@link CodeTransformer#acceptBody(Builder, Body, List) accepting}
641 * the rebound builder, the body, and the values.
642 *
643 * @apiNote
644 * The passing of a context can ensure block and value mappings produced by
645 * the transformation do not affect this builder's context.
646 *
647 * @param body the body to transform
648 * @param values the output values to map to the input parameters of the body's entry block
649 * @param cc the code context
650 * @param ot the operation transformer
651 * @see CodeTransformer#acceptBody(Builder, Body, List)
652 */
653 public void body(Body body, List<? extends Value> values,
654 CodeContext cc, CodeTransformer ot) {
655 check();
656
657 ot.acceptBody(rebind(cc, ot), body, values);
658 }
659
660 /**
661 * Appends an operation to this block builder, first transforming the operation if bound.
662 * <p>
663 * If the operation is not bound to a block, then the operation is appended and bound to this block.
664 * Otherwise, if the operation is bound, the operation is first
665 * {@link Op#transform(CodeContext, CodeTransformer) transformed} with this builder's context and
666 * operation transformer, the resulting unbound transformed operation is appended, and the
667 * operation's result mapped to the transformed operation's result, using the builder's context.
668 * <p>
669 * If the unbound operation (transformed, or otherwise) is structurally invalid then an
670 * {@code IllegalStateException} is thrown. An unbound operation is structurally invalid if:
671 * <ul>
672 * <li>any of its bodies does not have the same ancestor body as this block's parent body.
673 * <li>any of its operands (values) is not reachable from this block.
674 * <li>any of its successors is not a sibling of this block.
675 * <li>any of its successors arguments (values) is not reachable from this block.
676 * </ul>
677 * A value is reachable from this block if there is a path from this block's parent body,
678 * via its ancestor bodies, to the value's block's parent body. (Note this structural check
679 * ensures values are only used from the same tree being built, but it is weaker than a
680 * dominance check that may be performed when the parent body is built.)
681 *
682 * @param op the operation to append
683 * @return the operation result of the appended operation
684 * @throws IllegalStateException if the operation is structurally invalid
685 */
686 public Op.Result op(Op op) {
687 check();
688
689 final Op.Result oprToTransform = op.result();
690
691 Op transformedOp = op;
692 if (op.isSealed() || oprToTransform != null) {
693 // If operation is assigned to block, or it's sealed, then copy it and transform its contents
694 transformedOp = op.transform(cc, ot);
695 assert transformedOp.result == null;
696 }
697
698 Op.Result transformedOpr = insertOp(transformedOp);
699
700 if (oprToTransform != null) {
701 // Map the result of the first transformation
702 // @@@ If the same operation is transformed more than once then subsequent
703 // transformed ops will not get implicitly mapped
704 // Should this be an error?
705 cc.mapValueIfAbsent(oprToTransform, transformedOpr);
706 }
707
708 return transformedOpr;
709 }
710
711 /**
712 * Returns true if this block builder is equal to the other object.
713 * <p>This block builder is equal if the other object is an instance of a block builder, and they are
714 * associated with the same block (but perhaps bound to different contexts and transformers).
715 *
716 * @param o the other object
717 * @return true if this builder is equal to the other object.
718 */
719 @Override
720 public boolean equals(Object o) {
721 if (this == o) return true;
722 return o instanceof Builder that && Block.this == that.target();
723 }
724
725 @Override
726 public int hashCode() {
727 return Block.this.hashCode();
728 }
729 }
730
731 // Modifying methods
732
733 // Create block parameter associated with this block
734 private Parameter appendBlockParameter(TypeElement type) {
735 Parameter blockParameter = new Parameter(this, type);
736 parameters.add(blockParameter);
737
738 return blockParameter;
739 }
740
741 // Create an operation, adding to the end of the list of existing operations
742 private Op.Result insertOp(Op op) {
743 Op.Result opResult = new Op.Result(this, op);
744 bindOp(opResult, op);
745
746 ops.add(op);
747 return opResult;
748 }
749
750 private void bindOp(Op.Result opr, Op op) {
751 // Structural checks
752 if (!ops.isEmpty() && ops.getLast() instanceof Op.Terminating) {
753 throw new IllegalStateException("Operation cannot be appended, the block has a terminal operation");
754 }
755
756 for (Body b : op.bodies()) {
757 if (b.ancestorBody != null && b.ancestorBody != this.parentBody) {
758 throw new IllegalStateException("Body of operation is bound to a different ancestor body: ");
759 }
760 }
761
762 for (Value v : op.operands()) {
763 if (!isReachable(v)) {
764 throw new IllegalStateException(
765 String.format("Operand of operation %s is not defined in tree: %s", op, v));
766 }
767 assert !v.isBound();
768 }
769
770 for (Reference s : op.successors()) {
771 if (s.target.parentBody != this.parentBody) {
772 throw new IllegalStateException("Target of block reference is not a sibling of this block");
773 }
774
775 for (Value v : s.arguments()) {
776 if (!isReachable(v)) {
777 throw new IllegalStateException(
778 String.format("Argument of block reference %s of terminating operation %s is not defined in tree: %s", s, op, v));
779 }
780 assert !v.isBound();
781 }
782 }
783
784 // State updates after structural checks
785 // @@@ The alternative is to close the body builder on failure, rendering it inoperable,
786 // so checks and updates can be merged
787 for (Value v : op.operands()) {
788 v.uses.add(opr);
789 }
790
791 for (Reference s : op.successors()) {
792 for (Value v : s.arguments()) {
793 v.uses.add(opr);
794 }
795
796 s.target.predecessors.add(Block.this);
797 }
798
799 op.result = opr;
800 }
801
802 // Determine if the parent body of value's block is an ancestor of this block
803 private boolean isReachable(Value v) {
804 Body b = parentBody;
805 while (b != null && b != v.block.parentBody) {
806 b = b.ancestorBody;
807 }
808 return b != null;
809 }
810
811 //
812
813 boolean isBound() {
814 return index >= 0;
815 }
816 }