1 /*
2  * Copyright (c) 2011, 2018, 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 package org.graalvm.compiler.core.test;
26 
27 import org.graalvm.compiler.loop.DefaultLoopPolicies;
28 import org.graalvm.compiler.loop.phases.LoopPeelingPhase;
29 import org.graalvm.compiler.nodes.ReturnNode;
30 import org.graalvm.compiler.nodes.StructuredGraph;
31 import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
32 import org.graalvm.compiler.nodes.ValueNode;
33 import org.graalvm.compiler.phases.common.CanonicalizerPhase;
34 import org.graalvm.compiler.phases.common.DeadCodeEliminationPhase;
35 import org.graalvm.compiler.phases.tiers.HighTierContext;
36 import org.graalvm.compiler.virtual.phases.ea.PartialEscapePhase;
37 import org.junit.Assert;
38 import org.junit.Ignore;
39 import org.junit.Test;
40 
41 /**
42  * In the following tests, the usages of local variable "a" are replaced with the integer constant
43  * 0. Then boxing elimination is applied and it is verified that the resulting graph is equal to the
44  * graph of the method that just has a "return 1" statement in it.
45  */
46 public class BoxingEliminationTest extends GraalCompilerTest {
47 
48     private static final Short s = 2;
49 
50     @SuppressWarnings("all")
referenceSnippet1()51     public static short referenceSnippet1() {
52         return 1;
53     }
54 
55     @SuppressWarnings("all")
referenceSnippet2()56     public static short referenceSnippet2() {
57         return 2;
58     }
59 
boxedShort()60     public static Short boxedShort() {
61         return 1;
62     }
63 
boxedObjectShort()64     public static Object boxedObjectShort() {
65         return (short) 1;
66     }
67 
boxedObjectInteger()68     public static Object boxedObjectInteger() {
69         return 1;
70     }
71 
boxedInteger()72     public static Integer boxedInteger() {
73         return 2;
74     }
75 
constantBoxedShort()76     public static Short constantBoxedShort() {
77         return s;
78     }
79 
80     @Test
test1()81     public void test1() {
82         compareGraphs("test1Snippet", "referenceSnippet1");
83     }
84 
85     @SuppressWarnings("all")
test1Snippet()86     public static short test1Snippet() {
87         return boxedShort();
88     }
89 
90     @Test
test2()91     public void test2() {
92         compareGraphs("test2Snippet", "referenceSnippet1");
93     }
94 
95     @SuppressWarnings("all")
test2Snippet()96     public static short test2Snippet() {
97         return (Short) boxedObjectShort();
98     }
99 
100     @Test
test3()101     public void test3() {
102         compareGraphs("test3Snippet", "referenceSnippet1");
103     }
104 
105     @SuppressWarnings("all")
test3Snippet()106     public static short test3Snippet() {
107         short b = boxedShort();
108         if (b < 0) {
109             b = boxedShort();
110         }
111         return b;
112     }
113 
114     @Test
test4()115     public void test4() {
116         compareGraphs("test4Snippet", "referenceSnippet2");
117     }
118 
119     @SuppressWarnings("all")
test4Snippet()120     public static short test4Snippet() {
121         return constantBoxedShort();
122     }
123 
124     @Ignore
125     @Test
testLoop()126     public void testLoop() {
127         compareGraphs("testLoopSnippet", "referenceLoopSnippet", false, true);
128     }
129 
testLoopSnippet(int n, int a)130     public static int testLoopSnippet(int n, int a) {
131         Integer sum = a;
132         for (Integer i = 0; i < n; i++) {
133             sum += i;
134         }
135         return sum;
136     }
137 
referenceLoopSnippet(int n, int a)138     public static int referenceLoopSnippet(int n, int a) {
139         int sum = a;
140         for (int i = 0; i < n; i++) {
141             sum += i;
142         }
143         return sum;
144     }
145 
146     @Test
testLoop2()147     public void testLoop2() {
148         compareGraphs("testLoop2Snippet", "referenceLoop2Snippet", true, true);
149     }
150 
testLoop2Snippet(int n, Integer a)151     public static int testLoop2Snippet(int n, Integer a) {
152         Integer sum = a;
153         for (Integer i = 0; i < n; i++) {
154             sum += i;
155         }
156         return sum;
157     }
158 
referenceLoop2Snippet(int n, Integer a)159     public static int referenceLoop2Snippet(int n, Integer a) {
160         Integer sum0;
161         if (n <= 0) {
162             sum0 = a;
163         } else {
164             int sum = a;
165             for (int i = 1; i < n; i++) {
166                 sum += i;
167             }
168             sum0 = sum;
169         }
170         return sum0;
171     }
172 
referenceIfSnippet(int a)173     public static int referenceIfSnippet(int a) {
174         int result;
175         if (a < 0) {
176             result = 2;
177         } else {
178             result = 1;
179         }
180         return result;
181     }
182 
183     @Test
testIf()184     public void testIf() {
185         compareGraphs("testIfSnippet", "referenceIfSnippet");
186     }
187 
testIfSnippet(int a)188     public static int testIfSnippet(int a) {
189         Integer result;
190         if (a < 0) {
191             result = boxedInteger();
192         } else {
193             result = (Integer) boxedObjectInteger();
194         }
195         return result;
196     }
197 
198     @Test
testComparison()199     public void testComparison() {
200         compareGraphs("testComparison1Snippet", "referenceComparisonSnippet");
201         compareGraphs("testComparison2Snippet", "referenceComparisonSnippet");
202     }
203 
204     @SuppressWarnings("cast")
testComparison1Snippet(int a, int b)205     public static boolean testComparison1Snippet(int a, int b) {
206         return ((Integer) a) == b;
207     }
208 
testComparison2Snippet(int a, int b)209     public static boolean testComparison2Snippet(int a, int b) {
210         Integer x = a;
211         Integer y = b;
212         return x == y;
213     }
214 
referenceComparisonSnippet(int a, int b)215     public static boolean referenceComparisonSnippet(int a, int b) {
216         return a == b;
217     }
218 
219     @Test
testLateCanonicalization()220     public void testLateCanonicalization() {
221         compareGraphs("testLateCanonicalizationSnippet", "referenceLateCanonicalizationSnippet");
222     }
223 
testLateCanonicalizationSnippet(int a)224     public static boolean testLateCanonicalizationSnippet(int a) {
225         Integer x = a;
226         Integer y = 1000;
227         return x == y;
228     }
229 
referenceLateCanonicalizationSnippet(int a)230     public static boolean referenceLateCanonicalizationSnippet(int a) {
231         return a == 1000;
232     }
233 
234     private StructuredGraph graph;
235 
materializeReferenceSnippet(int a)236     public static Integer materializeReferenceSnippet(int a) {
237         return Integer.valueOf(a);
238     }
239 
materializeTest1Snippet(int a)240     public static Integer materializeTest1Snippet(int a) {
241         Integer v = a;
242 
243         if (v == a) {
244             return v;
245         } else {
246             return null;
247         }
248     }
249 
250     @Test
materializeTest1()251     public void materializeTest1() {
252         test("materializeTest1Snippet", 1);
253     }
254 
intTest1Snippet()255     public static int intTest1Snippet() {
256         return Integer.valueOf(1);
257     }
258 
259     @Test
intTest1()260     public void intTest1() {
261         ValueNode result = getResult("intTest1Snippet");
262         Assert.assertTrue(result.isConstant());
263         Assert.assertEquals(1, result.asJavaConstant().asInt());
264     }
265 
mergeTest1Snippet(boolean d, int a, int b)266     public static int mergeTest1Snippet(boolean d, int a, int b) {
267         Integer v;
268         if (d) {
269             v = a;
270         } else {
271             v = b;
272         }
273         return v;
274     }
275 
276     @Test
mergeTest1()277     public void mergeTest1() {
278         processMethod("mergeTest1Snippet");
279     }
280 
equalsTest1Snippet(int x, int y)281     public static boolean equalsTest1Snippet(int x, int y) {
282         Integer a = x;
283         Integer b = y;
284         return a == b;
285     }
286 
287     @Test
equalsTest1()288     public void equalsTest1() {
289         processMethod("equalsTest1Snippet");
290     }
291 
loopTest1Snippet(int n, int v)292     public static int loopTest1Snippet(int n, int v) {
293         Integer sum = 0;
294         for (int i = 0; i < n; i++) {
295             sum += v;
296         }
297         return sum;
298     }
299 
300     @Test
loopTest1()301     public void loopTest1() {
302         processMethod("loopTest1Snippet");
303 
304     }
305 
getResult(String snippet)306     final ValueNode getResult(String snippet) {
307         processMethod(snippet);
308         assertDeepEquals(1, graph.getNodes(ReturnNode.TYPE).count());
309         return graph.getNodes(ReturnNode.TYPE).first().result();
310     }
311 
processMethod(final String snippet)312     private void processMethod(final String snippet) {
313         graph = parseEager(snippet, AllowAssumptions.NO);
314         HighTierContext context = getDefaultHighTierContext();
315         createInliningPhase().apply(graph, context);
316         new PartialEscapePhase(false, new CanonicalizerPhase(), graph.getOptions()).apply(graph, context);
317     }
318 
compareGraphs(final String snippet, final String referenceSnippet)319     private void compareGraphs(final String snippet, final String referenceSnippet) {
320         compareGraphs(snippet, referenceSnippet, false, false);
321     }
322 
compareGraphs(final String snippet, final String referenceSnippet, final boolean loopPeeling, final boolean excludeVirtual)323     private void compareGraphs(final String snippet, final String referenceSnippet, final boolean loopPeeling, final boolean excludeVirtual) {
324         graph = parseEager(snippet, AllowAssumptions.NO);
325         HighTierContext context = getDefaultHighTierContext();
326         CanonicalizerPhase canonicalizer = new CanonicalizerPhase();
327         canonicalizer.apply(graph, context);
328         createInliningPhase().apply(graph, context);
329         if (loopPeeling) {
330             new LoopPeelingPhase(new DefaultLoopPolicies()).apply(graph, context);
331         }
332         new DeadCodeEliminationPhase().apply(graph);
333         canonicalizer.apply(graph, context);
334         new PartialEscapePhase(false, canonicalizer, graph.getOptions()).apply(graph, context);
335 
336         new DeadCodeEliminationPhase().apply(graph);
337         canonicalizer.apply(graph, context);
338 
339         StructuredGraph referenceGraph = parseEager(referenceSnippet, AllowAssumptions.YES);
340         createInliningPhase().apply(referenceGraph, context);
341         new DeadCodeEliminationPhase().apply(referenceGraph);
342         new CanonicalizerPhase().apply(referenceGraph, context);
343 
344         assertEquals(referenceGraph, graph, excludeVirtual, true);
345     }
346 }
347