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 import jdk.incubator.code.*;
25 import jdk.incubator.code.Reflect;
26 import jdk.incubator.code.analysis.Inliner;
27 import jdk.incubator.code.dialect.core.CoreOp;
28 import jdk.incubator.code.dialect.java.JavaOp;
29 import jdk.incubator.code.dialect.java.JavaType;
30 import jdk.incubator.code.interpreter.Interpreter;
31 import org.junit.jupiter.api.Assertions;
32 import org.junit.jupiter.api.Test;
33
34 import java.lang.invoke.MethodHandles;
35 import java.util.List;
36 import java.util.function.Consumer;
37 import java.util.function.IntBinaryOperator;
38
39 import static jdk.incubator.code.dialect.core.CoreOp.*;
40 import static jdk.incubator.code.dialect.core.CoreType.functionType;
41 import static jdk.incubator.code.dialect.java.JavaType.INT;
42
43 /*
44 * @test
45 * @modules jdk.incubator.code
46 * @run junit TestInline
47 */
48
49 public class TestInline {
50
51 @Test
52 public void testInline() {
53 IntBinaryOperator q = (@Reflect IntBinaryOperator)(int a, int b) -> a + b;
54 JavaOp.LambdaOp cop = (JavaOp.LambdaOp) Op.ofQuotable(q).get().op();
55
56 // functional type = (int)int
57 CoreOp.FuncOp f = func("f", functionType(INT, INT))
58 .body(fblock -> {
59 Block.Parameter i = fblock.parameters().get(0);
60
61 Op.Result fortyTwo = fblock.op(constant(INT, 42));
62
63 var cb = Inliner.inline(fblock, cop, List.of(i, fortyTwo), Inliner.INLINE_RETURN);
64 Assertions.assertEquals(cb, fblock);
65 });
66
67 System.out.println(f.toText());
68
69 int ir = (int) Interpreter.invoke(MethodHandles.lookup(), f, 1);
70 Assertions.assertEquals(43, ir);
71 }
72
73 @Test
74 public void testInlineVar() {
75 IntBinaryOperator q = (@Reflect IntBinaryOperator)(int a, int b) -> a + b;
76 JavaOp.LambdaOp cop = (JavaOp.LambdaOp) Op.ofQuotable(q).get().op();
77
78 // functional type = (int)int
79 CoreOp.FuncOp f = func("f", functionType(INT, INT))
80 .body(fblock -> {
81 Block.Parameter i = fblock.parameters().get(0);
82
83 Op.Result fortyTwo = fblock.op(constant(INT, 42));
84
85 Op.Result v = fblock.op(var(fblock.op(constant(INT, 0))));
86
87 var cb = Inliner.inline(fblock, cop, List.of(i, fortyTwo), (b, value) -> {
88 b.op(varStore(v, value));
89 });
90 Assertions.assertEquals(cb, fblock);
91
92 fblock.op(return_(fblock.op(varLoad(v))));
93 });
94
95 System.out.println(f.toText());
96
97 int ir = (int) Interpreter.invoke(MethodHandles.lookup(), f, 1);
98 Assertions.assertEquals(43, ir);
99 }
100
101
102 @Test
103 public void testInlineLowerMultipleReturn() {
104 IntBinaryOperator q = (@Reflect IntBinaryOperator)(int a, int b) -> {
105 if (a < 10) {
106 return a + b;
107 }
108 return a - b;
109 };
110 JavaOp.LambdaOp cop = (JavaOp.LambdaOp) Op.ofQuotable(q).get().op();
111 System.out.println(cop.toText());
112 JavaOp.LambdaOp lcop = cop.transform(CodeContext.create(), CodeTransformer.LOWERING_TRANSFORMER);
113 System.out.println(lcop.toText());
114
115 // functional type = (int)int
116 CoreOp.FuncOp f = func("f", functionType(INT, INT))
117 .body(fblock -> {
118 Block.Parameter i = fblock.parameters().get(0);
119
120 Op.Result fortyTwo = fblock.op(constant(INT, 42));
121
122 var cb = Inliner.inline(fblock, lcop, List.of(i, fortyTwo), Inliner.INLINE_RETURN);
123 Assertions.assertNotEquals(fblock, cb);
124 });
125 System.out.println(f.toText());
126
127 int ir = (int) Interpreter.invoke(MethodHandles.lookup(), f, 1);
128 Assertions.assertEquals(43, ir);
129 }
130
131 @Test
132 public void testInlineLowerMultipleReturnVar() {
133 IntBinaryOperator q = (@Reflect IntBinaryOperator)(int a, int b) -> {
134 if (a < 10) {
135 return a + b;
136 }
137 return a - b;
138 };
139 JavaOp.LambdaOp cop = (JavaOp.LambdaOp) Op.ofQuotable(q).get().op();
140 System.out.println(cop.toText());
141 JavaOp.LambdaOp lcop = cop.transform(CodeContext.create(), CodeTransformer.LOWERING_TRANSFORMER);
142 System.out.println(lcop.toText());
143
144 // functional type = (int)int
145 CoreOp.FuncOp f = func("f", functionType(INT, INT))
146 .body(fblock -> {
147 Block.Parameter i = fblock.parameters().get(0);
148
149 Op.Result fortyTwo = fblock.op(constant(INT, 42));
150
151 Op.Result v = fblock.op(var(fblock.op(constant(INT, 0))));
152
153 var cb = Inliner.inline(fblock, lcop, List.of(i, fortyTwo), (b, value) -> {
154 b.op(varStore(v, value));
155 });
156 Assertions.assertNotEquals(fblock, cb);
157
158 cb.op(return_(cb.op(varLoad(v))));
159 });
160 System.out.println(f.toText());
161
162 int ir = (int) Interpreter.invoke(MethodHandles.lookup(), f, 1);
163 Assertions.assertEquals(43, ir);
164 }
165
166 @Test
167 public void testInlineMultipleReturnLower() {
168 IntBinaryOperator q = (@Reflect IntBinaryOperator)(int a, int b) -> {
169 if (a < 10) {
170 return a + b;
171 }
172 return a - b;
173 };
174 JavaOp.LambdaOp cop = (JavaOp.LambdaOp) Op.ofQuotable(q).get().op();
175 System.out.println(cop.toText());
176
177 CoreOp.FuncOp f = func("f", functionType(INT, INT))
178 .body(fblock -> {
179 Block.Parameter i = fblock.parameters().get(0);
180
181 Op.Result fortyTwo = fblock.op(constant(INT, 42));
182
183 var cb = Inliner.inline(fblock, cop, List.of(i, fortyTwo), Inliner.INLINE_RETURN);
184 Assertions.assertEquals(cb, fblock);
185 });
186 System.out.println(f.toText());
187
188 f = f.transform(CodeTransformer.LOWERING_TRANSFORMER);
189 System.out.println(f.toText());
190
191 int ir = (int) Interpreter.invoke(MethodHandles.lookup(), f, 1);
192 Assertions.assertEquals(43, ir);
193 }
194
195 @Test
196 public void testInlineVoid() {
197 Consumer<int[]> q = (@Reflect Consumer<int[]>) (int[] a) -> {
198 a[0] = 42;
199 return;
200 };
201 JavaOp.LambdaOp cop = (JavaOp.LambdaOp) Op.ofQuotable(q).get().op();
202
203 // functional type = (int)int
204 CoreOp.FuncOp f = func("f", functionType(JavaType.VOID, JavaType.type(int[].class)))
205 .body(fblock -> {
206 Block.Parameter a = fblock.parameters().get(0);
207
208 var cb = Inliner.inline(fblock, cop, List.of(a), Inliner.INLINE_RETURN);
209 Assertions.assertEquals(cb, fblock);
210 });
211
212 System.out.println(f.toText());
213
214 int[] a = new int[1];
215 Interpreter.invoke(MethodHandles.lookup(), f, a);
216 Assertions.assertEquals(42, a[0]);
217 }
218
219 }