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 TestNormalizeBlocksTransformer
28 */
29
30 import jdk.incubator.code.Op;
31 import jdk.incubator.code.dialect.core.NormalizeBlocksTransformer;
32 import jdk.incubator.code.dialect.java.JavaOp;
33 import jdk.incubator.code.extern.OpParser;
34 import org.junit.jupiter.api.Assertions;
35 import org.junit.jupiter.params.ParameterizedTest;
36 import org.junit.jupiter.params.provider.MethodSource;
37
38 import java.util.stream.Stream;
39
40 public class TestNormalizeBlocksTransformer {
41 static final String TEST1_INPUT = """
42 func @"f" (%0 : java.type:"int")java.type:"int" -> {
43 %1 : java.type:"int" = invoke @java.ref:"C::m():int";
44 branch ^block_1;
45
46 ^block_1:
47 %2 : java.type:"int" = invoke %1 @java.ref:"C::m(int):int";
48 branch ^block_2(%2);
49
50 ^block_2(%3: java.type:"int"):
51 %4 : java.type:"int" = invoke %2 %3 @java.ref:"C::m(int, int):int";
52 branch ^block_3(%3);
53
54 ^block_3(%5: java.type:"int"):
55 %6 : java.type:"int" = invoke %4 %3 %5 @java.ref:"C::m(int, int, int):int";
56 branch ^block_4;
57
58 ^block_4:
59 return %6;
60 };
61 """;
62 static final String TEST1_EXPECTED = """
63 func @"f" (%0 : java.type:"int")java.type:"int" -> {
64 %1 : java.type:"int" = invoke @java.ref:"C::m():int";
65 %2 : java.type:"int" = invoke %1 @java.ref:"C::m(int):int";
66 %3 : java.type:"int" = invoke %2 %2 @java.ref:"C::m(int, int):int";
67 %4 : java.type:"int" = invoke %3 %2 %2 @java.ref:"C::m(int, int, int):int";
68 return %4;
69 };
70 """;
71
72 static final String TEST2_INPUT = """
73 func @"f" (%0 : java.type:"java.lang.Object")java.type:"void" -> {
74 %1 : Var<java.type:"java.lang.Object"> = var %0 @"o";
75 exception.region.enter ^block_1 ^block_8 ^block_3;
76
77 ^block_1:
78 %3 : java.type:"int" = invoke @java.ref:"A::try_():int";
79 branch ^block_2;
80
81 ^block_2:
82 exception.region.exit ^block_6 ^block_3 ^block_8;
83
84 ^block_3(%4 : java.type:"java.lang.RuntimeException"):
85 exception.region.enter ^block_4 ^block_8;
86
87 ^block_4:
88 %6 : Var<java.type:"java.lang.RuntimeException"> = var %4 @"e";
89 branch ^block_5;
90
91 ^block_5:
92 exception.region.exit ^block_6 ^block_8;
93
94 ^block_6:
95 %7 : java.type:"int" = invoke @java.ref:"A::finally_():int";
96 branch ^block_7;
97
98 ^block_7:
99 return;
100
101 ^block_8(%8 : java.type:"java.lang.Throwable"):
102 %9 : java.type:"int" = invoke @java.ref:"A::finally_():int";
103 throw %8;
104 };
105 """;
106 static final String TEST2_EXPECTED = """
107 func @"f" (%0 : java.type:"java.lang.Object")java.type:"void" -> {
108 %1 : Var<java.type:"java.lang.Object"> = var %0 @"o";
109 exception.region.enter ^block_1 ^block_5 ^block_2;
110
111 ^block_1:
112 %3 : java.type:"int" = invoke @java.ref:"A::try_():int";
113 exception.region.exit ^block_4 ^block_2 ^block_5;
114
115 ^block_2(%4 : java.type:"java.lang.RuntimeException"):
116 exception.region.enter ^block_3 ^block_5;
117
118 ^block_3:
119 %6 : Var<java.type:"java.lang.RuntimeException"> = var %4 @"e";
120 exception.region.exit ^block_4 ^block_5;
121
122 ^block_4:
123 %7 : java.type:"int" = invoke @java.ref:"A::finally_():int";
124 return;
125
126 ^block_5(%8 : java.type:"java.lang.Throwable"):
127 %9 : java.type:"int" = invoke @java.ref:"A::finally_():int";
128 throw %8;
129 };""";
130
131 static final String TEST3_INPUT = """
132 func @"f" (%0 : java.type:"int")java.type:"int" -> {
133 %1 : java.type:"int" = constant @0;
134 %2 : java.type:"boolean" = gt %0 %1;
135 cbranch %2 ^block_1 ^block_2;
136
137 ^block_1:
138 %3 : java.type:"int" = constant @1;
139 branch ^block_1_1;
140
141 ^block_1_1:
142 branch ^block_3(%3);
143
144 ^block_2:
145 %4 : java.type:"int" = constant @-1;
146 branch ^block_2_1;
147
148 ^block_2_1:
149 branch ^block_3(%4);
150
151 ^block_3(%5 : java.type:"int"):
152 return %5;
153 };""";
154 static final String TEST3_EXPECTED = """
155 func @"f" (%0 : java.type:"int")java.type:"int" -> {
156 %1 : java.type:"int" = constant @0;
157 %2 : java.type:"boolean" = gt %0 %1;
158 cbranch %2 ^block_1 ^block_2;
159
160 ^block_1:
161 %3 : java.type:"int" = constant @1;
162 branch ^block_3(%3);
163
164 ^block_2:
165 %4 : java.type:"int" = constant @-1;
166 branch ^block_3(%4);
167
168 ^block_3(%5 : java.type:"int"):
169 return %5;
170 };
171 """;
172
173 static final String TEST4_INPUT = """
174 func @"f" (%0 : java.type:"int")java.type:"int" -> {
175 %1 : java.type:"int" = constant @0;
176 %2 : java.type:"boolean" = gt %0 %1;
177 cbranch %2 ^block_1 ^block_2;
178
179 ^block_1:
180 %3 : java.type:"int" = constant @1;
181 branch ^block_1_1;
182
183 ^block_1_1:
184 branch ^block_3(%0, %3, %1);
185
186 ^block_2:
187 %4 : java.type:"int" = constant @-1;
188 branch ^block_2_1;
189
190 ^block_2_1:
191 branch ^block_3(%0, %4, %1);
192
193 ^block_3(%unused_1 : java.type:"int", %5 : java.type:"int", %unused_2 : java.type:"int"):
194 return %5;
195 };""";
196 static final String TEST4_EXPECTED = """
197 func @"f" (%0 : java.type:"int")java.type:"int" -> {
198 %1 : java.type:"int" = constant @0;
199 %2 : java.type:"boolean" = gt %0 %1;
200 cbranch %2 ^block_1 ^block_2;
201
202 ^block_1:
203 %3 : java.type:"int" = constant @1;
204 branch ^block_3(%3);
205
206 ^block_2:
207 %4 : java.type:"int" = constant @-1;
208 branch ^block_3(%4);
209
210 ^block_3(%5 : java.type:"int"):
211 return %5;
212 };
213 """;
214
215 static final String TEST5_INPUT = """
216 func @"f" ()java.type:"void" -> {
217 exception.region.enter ^block_1 ^block_4;
218
219 ^block_1:
220 invoke @java.ref:"A::m():void";
221 branch ^block_2;
222
223 ^block_2:
224 exception.region.exit ^block_3 ^block_4;
225
226 ^block_3:
227 branch ^block_5;
228
229 ^block_4(%1 : java.type:"java.lang.Throwable"):
230 branch ^block_5;
231
232 ^block_5:
233 return;
234 };
235 """;
236 static final String TEST5_EXPECTED = """
237 func @"f" ()java.type:"void" -> {
238 exception.region.enter ^block_1 ^block_3;
239
240 ^block_1:
241 invoke @java.ref:"A::m():void";
242 exception.region.exit ^block_2 ^block_3;
243
244 ^block_2:
245 branch ^block_4;
246
247 ^block_3(%1 : java.type:"java.lang.Throwable"):
248 branch ^block_4;
249
250 ^block_4:
251 return;
252 };
253 """;
254
255 static final String TEST6_INPUT = """
256 func @"m" (%0 : java.type:"java.lang.Object")java.type:"int" -> {
257 %1 : java.type:"java.lang.Object" = constant @null;
258 %2 : java.type:"boolean" = invoke %0 %1 @java.ref:"java.util.Objects::equals(java.lang.Object, java.lang.Object):boolean";
259 cbranch %2 ^block_1 ^block_2;
260
261 ^block_1:
262 %3 : java.type:"java.lang.NullPointerException" = new @java.ref:"java.lang.NullPointerException::()";
263 throw %3;
264
265 ^block_2:
266 %4 : java.type:"boolean" = instanceof %0 @java.type:"java.util.List";
267 cbranch %4 ^block_3 ^block_5;
268
269 ^block_3:
270 %5 : java.type:"java.util.List" = cast %0 @java.type:"java.util.List";
271 branch ^block_4;
272
273 ^block_4:
274 %6 : java.type:"boolean" = constant @true;
275 branch ^block_6(%6);
276
277 ^block_5:
278 %7 : java.type:"boolean" = constant @false;
279 branch ^block_6(%7);
280
281 ^block_6(%8 : java.type:"boolean"):
282 cbranch %8 ^block_7 ^block_8;
283
284 ^block_7:
285 %9 : java.type:"int" = constant @1;
286 branch ^block_21(%9);
287
288 ^block_8:
289 %10 : java.type:"boolean" = instanceof %0 @java.type:"java.lang.String";
290 cbranch %10 ^block_9 ^block_11;
291
292 ^block_9:
293 %11 : java.type:"java.lang.String" = cast %0 @java.type:"java.lang.String";
294 branch ^block_10;
295
296 ^block_10:
297 %12 : java.type:"boolean" = constant @true;
298 branch ^block_12(%12);
299
300 ^block_11:
301 %13 : java.type:"boolean" = constant @false;
302 branch ^block_12(%13);
303
304 ^block_12(%14 : java.type:"boolean"):
305 cbranch %14 ^block_13 ^block_14;
306
307 ^block_13:
308 %15 : java.type:"int" = constant @2;
309 branch ^block_21(%15);
310
311 ^block_14:
312 %16 : java.type:"boolean" = instanceof %0 @java.type:"java.util.Map";
313 cbranch %16 ^block_15 ^block_17;
314
315 ^block_15:
316 %17 : java.type:"java.util.Map" = cast %0 @java.type:"java.util.Map";
317 branch ^block_16;
318
319 ^block_16:
320 %18 : java.type:"boolean" = constant @true;
321 branch ^block_18(%18);
322
323 ^block_17:
324 %19 : java.type:"boolean" = constant @false;
325 branch ^block_18(%19);
326
327 ^block_18(%20 : java.type:"boolean"):
328 cbranch %20 ^block_19 ^block_20;
329
330 ^block_19:
331 %21 : java.type:"int" = constant @3;
332 branch ^block_21(%21);
333
334 ^block_20:
335 %22 : java.type:"int" = constant @-1;
336 branch ^block_21(%22);
337
338 ^block_21(%23 : java.type:"int"):
339 return %23;
340 };
341 """;
342 static final String TEST6_EXPECTED = """
343 func @"m" (%0 : java.type:"java.lang.Object")java.type:"int" -> {
344 %1 : java.type:"java.lang.Object" = constant @null;
345 %2 : java.type:"boolean" = invoke %0 %1 @java.ref:"java.util.Objects::equals(java.lang.Object, java.lang.Object):boolean";
346 cbranch %2 ^block_1 ^block_2;
347
348 ^block_1:
349 %3 : java.type:"java.lang.NullPointerException" = new @java.ref:"java.lang.NullPointerException::()";
350 throw %3;
351
352 ^block_2:
353 %4 : java.type:"boolean" = instanceof %0 @java.type:"java.util.List";
354 cbranch %4 ^block_3 ^block_4;
355
356 ^block_3:
357 %5 : java.type:"java.util.List" = cast %0 @java.type:"java.util.List";
358 %6 : java.type:"int" = constant @1;
359 branch ^block_9(%6);
360
361 ^block_4:
362 %7 : java.type:"boolean" = instanceof %0 @java.type:"java.lang.String";
363 cbranch %7 ^block_5 ^block_6;
364
365 ^block_5:
366 %8 : java.type:"java.lang.String" = cast %0 @java.type:"java.lang.String";
367 %9 : java.type:"int" = constant @2;
368 branch ^block_9(%9);
369
370 ^block_6:
371 %10 : java.type:"boolean" = instanceof %0 @java.type:"java.util.Map";
372 cbranch %10 ^block_7 ^block_8;
373
374 ^block_7:
375 %11 : java.type:"java.util.Map" = cast %0 @java.type:"java.util.Map";
376 %12 : java.type:"int" = constant @3;
377 branch ^block_9(%12);
378
379 ^block_8:
380 %13 : java.type:"int" = constant @-1;
381 branch ^block_9(%13);
382
383 ^block_9(%14 : java.type:"int"):
384 return %14;
385 };
386 """;
387 static Object[][] testModels() {
388 return new Object[][]{
389 parse(TEST1_INPUT, TEST1_EXPECTED),
390 parse(TEST2_INPUT, TEST2_EXPECTED),
391 parse(TEST3_INPUT, TEST3_EXPECTED),
392 parse(TEST4_INPUT, TEST4_EXPECTED),
393 parse(TEST5_INPUT, TEST5_EXPECTED),
394 parse(TEST6_INPUT, TEST6_EXPECTED),
395 };
396 }
397
398 static Object[] parse(String... models) {
399 return Stream.of(models).map(s -> OpParser.fromString(JavaOp.JAVA_DIALECT_FACTORY, s).getFirst())
400 .toArray(Object[]::new);
401 }
402
403 @ParameterizedTest
404 @MethodSource("testModels")
405 public void test(Op input, Op expected) {
406 Op actual = NormalizeBlocksTransformer.transform(input);
407 Assertions.assertEquals(expected.toText(), actual.toText());
408 }
409 }