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