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