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.
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 * @test
26 * @modules jdk.incubator.code
27 * @run junit TestUsesDependsOn
28 */
29
30 import jdk.incubator.code.Block;
31 import jdk.incubator.code.Op;
32 import jdk.incubator.code.Value;
33 import jdk.incubator.code.extern.OpParser;
34 import org.junit.jupiter.api.Assertions;
35 import org.junit.jupiter.api.Test;
36
37 import java.util.HashMap;
38 import java.util.List;
39 import java.util.Map;
40 import java.util.Set;
41 import java.util.concurrent.atomic.AtomicInteger;
42 import java.util.function.BiConsumer;
43 import java.util.function.Function;
44
45 public class TestUsesDependsOn {
46
47 static final String OP = """
48 func @"f" (%0 : java.type:"int", %1 : java.type:"int")java.type:"int" -> {
49 %2 : java.type:"int" = add %0 %1;
50 %3 : java.type:"boolean" = lt %0 %1;
51 %4 : java.type:"void" = cbranch %3 ^b1(%2, %2) ^b2(%0, %1);
52
53 ^b1(%5 : java.type:"int", %6 : java.type:"int"):
54 %7 : java.type:"void" = return %5;
55
56 ^b2(%8 : java.type:"int", %9 : java.type:"int"):
57 %10 : java.type:"void" = return %8;
58 };
59 """;
60
61 @Test
62 public void testDependsOn() {
63 Op f = OpParser.fromStringOfJavaCodeModel(OP);
64
65 Map<String, List<String>> dependsUpon = computeValueMap(f, Value::dependsOn);
66
67 var expected = Map.ofEntries(
68 Map.entry("0", List.of()),
69 Map.entry("1", List.of()),
70 Map.entry("2", List.of("0", "1")),
71 Map.entry("3", List.of("0", "1")),
72 Map.entry("4", List.of("3", "2", "0", "1")),
73 Map.entry("5", List.of()),
74 Map.entry("6", List.of()),
75 Map.entry("7", List.of("5")),
76 Map.entry("8", List.of()),
77 Map.entry("9", List.of()),
78 Map.entry("10", List.of("8"))
79 );
80
81 Assertions.assertEquals(expected, dependsUpon);
82 }
83
84
85 @Test
86 public void testUses() {
87 Op f = OpParser.fromStringOfJavaCodeModel(OP);
88 System.out.println(f.toText());
89
90 Map<String, List<String>> uses = computeValueMap(f, Value::uses);
91
92 var expected = Map.ofEntries(
93 Map.entry("0", List.of("2", "3", "4")),
94 Map.entry("1", List.of("2", "3", "4")),
95 Map.entry("2", List.of("4")),
96 Map.entry("3", List.of("4")),
97 Map.entry("4", List.of()),
98 Map.entry("5", List.of("7")),
99 Map.entry("6", List.of()),
100 Map.entry("7", List.of()),
101 Map.entry("8", List.of("10")),
102 Map.entry("9", List.of()),
103 Map.entry("10", List.of())
104 );
105 System.out.println(uses.toString());
106 System.out.println(expected);
107
108 Assertions.assertEquals(expected, uses);
109 }
110
111 static Map<String, List<String>> computeValueMap(Op op, Function<Value, Set<? extends Value>> f) {
112 AtomicInteger ai = new AtomicInteger();
113
114 Map<Value, String> valueNameMap = computeValues(op, new HashMap<>(), (v, m) -> {
115 String name = Integer.toString(ai.getAndIncrement());
116 m.put(v, name);
117 });
118
119 return computeValues(op, new HashMap<>(), (v, m) -> {
120 m.put(valueNameMap.get(v), f.apply(v).stream().map(valueNameMap::get).toList());
121 });
122 }
123
124 static <T> T computeValues(Op op, T t, BiConsumer<Value, T> c) {
125 return op.traverse(t, (m, codeElement) -> {
126 return switch (codeElement) {
127 case Block b -> {
128 for (var a : b.parameters()) {
129 c.accept(a, m);
130 }
131
132 yield m;
133 }
134 case Op o -> {
135 if (o.result() != null) {
136 c.accept(o.result(), m);
137 }
138
139 yield m;
140 }
141 default -> m;
142 };
143 });
144 }
145 }