1/*
2 * Copyright (c) 2015, 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 */
23package org.graalvm.compiler.nodes.test;
24
25import org.junit.Assert;
26import org.junit.Ignore;
27import org.junit.Test;
28
29import org.graalvm.compiler.api.directives.GraalDirectives;
30import org.graalvm.compiler.core.test.GraalCompilerTest;
31import org.graalvm.compiler.graph.Node;
32import org.graalvm.compiler.nodes.IfNode;
33import org.graalvm.compiler.nodes.LogicNode;
34import org.graalvm.compiler.nodes.StructuredGraph;
35import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
36import org.graalvm.compiler.nodes.calc.SubNode;
37import org.graalvm.compiler.phases.common.CanonicalizerPhase;
38import org.graalvm.compiler.phases.common.ConvertDeoptimizeToGuardPhase;
39import org.graalvm.compiler.phases.common.IterativeConditionalEliminationPhase;
40import org.graalvm.compiler.phases.tiers.PhaseContext;
41
42/**
43 * A few tests of expected simplifications by
44 * {@link IfNode#simplify(org.graalvm.compiler.graph.spi.SimplifierTool)}.
45 */
46public class IfNodeCanonicalizationTest extends GraalCompilerTest {
47
48    static int value;
49
50    static final byte[] testValues = {-128, -1, 0, 1, 127};
51
52    @Test
53    public void test1() {
54        /*
55         * exercise conversion of x - y < 0 into x < y, both by checking expected graph shape and
56         * that the transformed code produces the right answer.
57         */
58        test("testSnippet1", SubNode.class, 0);
59        byte[] values = new byte[4];
60        for (byte a : testValues) {
61            values[0] = a;
62            for (byte b : testValues) {
63                values[1] = b;
64                for (byte c : testValues) {
65                    values[2] = c;
66                    for (byte d : testValues) {
67                        values[3] = d;
68                        value = 2;
69                        super.test("testSnippet1", values, true);
70                        super.test("testSnippet1", values, false);
71                    }
72                }
73            }
74        }
75    }
76
77    public int testSnippet1(byte[] values, boolean test) {
78        int v = values[0] - values[1];
79        if (test) {
80            v = values[2] - values[3];
81        }
82        if (v < 0) {
83            value = 1;
84        }
85        return value;
86    }
87
88    @Test
89    public void test2() {
90        test("testSnippet2", 1);
91    }
92
93    public boolean testSnippet2(int a, int[] limit) {
94        int l = limit.length;
95        if (!(a >= 0 && a < l)) {
96            value = a;
97            return true;
98        }
99        return false;
100    }
101
102    @Ignore("currently not working because swapped case isn't handled")
103    @Test
104    public void test3() {
105        test("testSnippet3", 1);
106    }
107
108    public boolean testSnippet3(int a, int[] limit) {
109        int l = limit.length;
110        if (a < l && a >= 0) {
111            value = 9;
112            return true;
113        }
114        return false;
115    }
116
117    @Test
118    public void test4() {
119        test("testSnippet4", 1);
120    }
121
122    public boolean testSnippet4(int a, int[] limit) {
123        int l = limit.length;
124        if (a < 0) {
125            GraalDirectives.deoptimize();
126        }
127        if (a >= l) {
128            GraalDirectives.deoptimize();
129        }
130        return true;
131    }
132
133    @Ignore("Reversed conditions aren't working with guards")
134    @Test
135    public void test5() {
136        test("testSnippet5", 1);
137    }
138
139    public boolean testSnippet5(int a, int[] limit) {
140        int l = limit.length;
141        if (a >= l) {
142            GraalDirectives.deoptimize();
143        }
144        if (a < 0) {
145            GraalDirectives.deoptimize();
146        }
147        return true;
148    }
149
150    public void test(String name, int logicCount) {
151        test(name, LogicNode.class, logicCount);
152    }
153
154    public void test(String name, Class<? extends Node> expectedClass, int expectedCount) {
155        StructuredGraph graph = parseEager(name, AllowAssumptions.YES);
156
157        PhaseContext context = new PhaseContext(getProviders());
158        CanonicalizerPhase canonicalizer = new CanonicalizerPhase();
159        graph.clearAllStateAfter();
160        graph.setGuardsStage(StructuredGraph.GuardsStage.AFTER_FSA);
161        canonicalizer.apply(graph, context);
162
163        new ConvertDeoptimizeToGuardPhase().apply(graph, context);
164        // new DominatorConditionalEliminationPhase(true).apply(graph, context);
165        new IterativeConditionalEliminationPhase(canonicalizer, true).apply(graph, context);
166        canonicalizer.apply(graph, context);
167        canonicalizer.apply(graph, context);
168
169        Assert.assertEquals(expectedCount, graph.getNodes().filter(expectedClass).count());
170    }
171}
172