1 /*
   2  * Copyright (c) 2016, 2017, 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 package org.graalvm.compiler.nodes.test;
  24 
  25 import java.util.function.Function;
  26 
  27 import org.junit.Assert;
  28 import org.junit.Test;
  29 
  30 import org.graalvm.compiler.core.test.GraalCompilerTest;
  31 import org.graalvm.compiler.nodes.ConstantNode;
  32 import org.graalvm.compiler.nodes.LogicNode;
  33 import org.graalvm.compiler.nodes.ShortCircuitOrNode;
  34 import org.graalvm.compiler.nodes.StructuredGraph;
  35 import org.graalvm.compiler.nodes.ValueNode;
  36 import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
  37 import org.graalvm.compiler.nodes.calc.ConditionalNode;
  38 import org.graalvm.compiler.nodes.calc.IntegerEqualsNode;
  39 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
  40 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
  41 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin;
  42 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins.Registration;
  43 import org.graalvm.compiler.phases.common.CanonicalizerPhase;
  44 import org.graalvm.compiler.phases.tiers.PhaseContext;
  45 
  46 import jdk.vm.ci.meta.JavaKind;
  47 import jdk.vm.ci.meta.ResolvedJavaMethod;
  48 
  49 public class ShortCircuitOrNodeTest extends GraalCompilerTest {
  50 
  51     static boolean shortCircuitOr(boolean b1, boolean b2) {
  52         return b1 || b2;
  53     }
  54 
  55     @Override
  56     protected Plugins getDefaultGraphBuilderPlugins() {
  57         Plugins plugins = super.getDefaultGraphBuilderPlugins();
  58         Registration r = new Registration(plugins.getInvocationPlugins(), ShortCircuitOrNodeTest.class);
  59         r.register2("shortCircuitOr", boolean.class, boolean.class, new InvocationPlugin() {
  60             @Override
  61             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode b1, ValueNode b2) {
  62                 LogicNode x = b.add(new IntegerEqualsNode(b1, b.add(ConstantNode.forInt(1))));
  63                 LogicNode y = b.add(new IntegerEqualsNode(b2, b.add(ConstantNode.forInt(1))));
  64                 ShortCircuitOrNode compare = b.add(new ShortCircuitOrNode(x, false, y, false, 0.5));
  65                 b.addPush(JavaKind.Boolean, new ConditionalNode(compare, b.add(ConstantNode.forBoolean(true)), b.add(ConstantNode.forBoolean(false))));
  66                 return true;
  67             }
  68         });
  69 
  70         return plugins;
  71     }
  72 
  73     public static int testSharedConditionSnippet(Object o) {
  74         boolean b2 = o != null;
  75         boolean b1 = o instanceof Function;
  76         if (b1) {
  77             if (shortCircuitOr(b1, b2)) {
  78                 return 4;
  79             } else {
  80                 return 3;
  81             }
  82         }
  83         return 1;
  84     }
  85 
  86     @Test
  87     public void testSharedCondition() {
  88         test("testSharedConditionSnippet", "String");
  89     }
  90 
  91     private int testInputCombinations(String snippet) {
  92         int trueCount = 0;
  93         for (int i = 0; i < 4; ++i) {
  94             boolean aValue = (i <= 1);
  95             boolean bValue = ((i % 2) == 0);
  96             boolean returnValue = (boolean) test(snippet, new Object[]{aValue, bValue}).returnValue;
  97 
  98             if (returnValue) {
  99                 trueCount++;
 100             }
 101         }
 102 
 103         return trueCount;
 104     }
 105 
 106     public boolean testSimpleSnippet(boolean a, boolean b) {
 107         return shortCircuitOr(a, b);
 108     }
 109 
 110     @Test
 111     public void testSimple() {
 112         testInputCombinations("testSimpleSnippet");
 113     }
 114 
 115     public static boolean testCascadeSnippet1(boolean a, boolean b) {
 116         return shortCircuitOr(shortCircuitOr(a, b), a);
 117     }
 118 
 119     public static boolean testCascadeSnippet2(boolean a, boolean b) {
 120         return shortCircuitOr(shortCircuitOr(b, a), a);
 121     }
 122 
 123     public static boolean testCascadeSnippet3(boolean a, boolean b) {
 124         return shortCircuitOr(a, shortCircuitOr(a, b));
 125     }
 126 
 127     public static boolean testCascadeSnippet4(boolean a, boolean b) {
 128         return shortCircuitOr(a, shortCircuitOr(b, a));
 129     }
 130 
 131     public static boolean testCascadeSnippet5(boolean a, boolean b) {
 132         return shortCircuitOr(!shortCircuitOr(a, b), a);
 133     }
 134 
 135     public static boolean testCascadeSnippet6(boolean a, boolean b) {
 136         return shortCircuitOr(!shortCircuitOr(b, a), a);
 137     }
 138 
 139     public static boolean testCascadeSnippet7(boolean a, boolean b) {
 140         return shortCircuitOr(!a, shortCircuitOr(a, b));
 141     }
 142 
 143     public static boolean testCascadeSnippet8(boolean a, boolean b) {
 144         return shortCircuitOr(!a, shortCircuitOr(b, a));
 145     }
 146 
 147     public static boolean testCascadeSnippet9(boolean a, boolean b) {
 148         return shortCircuitOr(shortCircuitOr(!a, b), a);
 149     }
 150 
 151     public static boolean testCascadeSnippet10(boolean a, boolean b) {
 152         return shortCircuitOr(shortCircuitOr(!b, a), a);
 153     }
 154 
 155     public static boolean testCascadeSnippet11(boolean a, boolean b) {
 156         return shortCircuitOr(a, !shortCircuitOr(a, b));
 157     }
 158 
 159     public static boolean testCascadeSnippet12(boolean a, boolean b) {
 160         return shortCircuitOr(a, !shortCircuitOr(b, a));
 161     }
 162 
 163     public static boolean testCascadeSnippet13(boolean a, boolean b) {
 164         return shortCircuitOr(!shortCircuitOr(!a, b), a);
 165     }
 166 
 167     public static boolean testCascadeSnippet14(boolean a, boolean b) {
 168         return shortCircuitOr(!shortCircuitOr(!b, a), a);
 169     }
 170 
 171     public static boolean testCascadeSnippet15(boolean a, boolean b) {
 172         return shortCircuitOr(!a, !shortCircuitOr(a, b));
 173     }
 174 
 175     public static boolean testCascadeSnippet16(boolean a, boolean b) {
 176         return shortCircuitOr(!a, !shortCircuitOr(!b, a));
 177     }
 178 
 179     public static boolean testCascadeSnippet17(boolean a, boolean b) {
 180         return shortCircuitOr(shortCircuitOr(a, !b), a);
 181     }
 182 
 183     public static boolean testCascadeSnippet18(boolean a, boolean b) {
 184         return shortCircuitOr(shortCircuitOr(b, !a), a);
 185     }
 186 
 187     public static boolean testCascadeSnippet19(boolean a, boolean b) {
 188         return shortCircuitOr(a, shortCircuitOr(!a, b));
 189     }
 190 
 191     public static boolean testCascadeSnippet20(boolean a, boolean b) {
 192         return shortCircuitOr(a, shortCircuitOr(!b, a));
 193     }
 194 
 195     public static boolean testCascadeSnippet21(boolean a, boolean b) {
 196         return shortCircuitOr(!shortCircuitOr(a, !b), a);
 197     }
 198 
 199     public static boolean testCascadeSnippet22(boolean a, boolean b) {
 200         return shortCircuitOr(!shortCircuitOr(b, !a), a);
 201     }
 202 
 203     public static boolean testCascadeSnippet23(boolean a, boolean b) {
 204         return shortCircuitOr(!a, shortCircuitOr(!a, b));
 205     }
 206 
 207     public static boolean testCascadeSnippet24(boolean a, boolean b) {
 208         return shortCircuitOr(!a, shortCircuitOr(!b, a));
 209     }
 210 
 211     public static boolean testCascadeSnippet25(boolean a, boolean b) {
 212         return shortCircuitOr(shortCircuitOr(!a, !b), a);
 213     }
 214 
 215     public static boolean testCascadeSnippet26(boolean a, boolean b) {
 216         return shortCircuitOr(shortCircuitOr(!b, !a), a);
 217     }
 218 
 219     public static boolean testCascadeSnippet27(boolean a, boolean b) {
 220         return shortCircuitOr(a, !shortCircuitOr(!a, b));
 221     }
 222 
 223     public static boolean testCascadeSnippet28(boolean a, boolean b) {
 224         return shortCircuitOr(a, !shortCircuitOr(!b, a));
 225     }
 226 
 227     public static boolean testCascadeSnippet29(boolean a, boolean b) {
 228         return shortCircuitOr(!shortCircuitOr(!a, !b), a);
 229     }
 230 
 231     public static boolean testCascadeSnippet30(boolean a, boolean b) {
 232         return shortCircuitOr(!shortCircuitOr(!b, !a), a);
 233     }
 234 
 235     public static boolean testCascadeSnippet31(boolean a, boolean b) {
 236         return shortCircuitOr(!a, !shortCircuitOr(!a, b));
 237     }
 238 
 239     public static boolean testCascadeSnippet32(boolean a, boolean b) {
 240         return shortCircuitOr(!a, !shortCircuitOr(!b, a));
 241     }
 242 
 243     public static boolean testCascadeSnippet33(boolean a, boolean b) {
 244         return shortCircuitOr(shortCircuitOr(a, b), !a);
 245     }
 246 
 247     public static boolean testCascadeSnippet34(boolean a, boolean b) {
 248         return shortCircuitOr(shortCircuitOr(b, a), !a);
 249     }
 250 
 251     public static boolean testCascadeSnippet35(boolean a, boolean b) {
 252         return shortCircuitOr(a, shortCircuitOr(a, !b));
 253     }
 254 
 255     public static boolean testCascadeSnippet36(boolean a, boolean b) {
 256         return shortCircuitOr(a, shortCircuitOr(b, !a));
 257     }
 258 
 259     public static boolean testCascadeSnippet37(boolean a, boolean b) {
 260         return shortCircuitOr(!shortCircuitOr(a, b), !a);
 261     }
 262 
 263     public static boolean testCascadeSnippet38(boolean a, boolean b) {
 264         return shortCircuitOr(!shortCircuitOr(b, a), !a);
 265     }
 266 
 267     public static boolean testCascadeSnippet39(boolean a, boolean b) {
 268         return shortCircuitOr(!a, shortCircuitOr(a, !b));
 269     }
 270 
 271     public static boolean testCascadeSnippet40(boolean a, boolean b) {
 272         return shortCircuitOr(!a, shortCircuitOr(b, !a));
 273     }
 274 
 275     public static boolean testCascadeSnippet41(boolean a, boolean b) {
 276         return shortCircuitOr(shortCircuitOr(!a, b), !a);
 277     }
 278 
 279     public static boolean testCascadeSnippet42(boolean a, boolean b) {
 280         return shortCircuitOr(shortCircuitOr(!b, a), !a);
 281     }
 282 
 283     public static boolean testCascadeSnippet43(boolean a, boolean b) {
 284         return shortCircuitOr(a, !shortCircuitOr(a, !b));
 285     }
 286 
 287     public static boolean testCascadeSnippet44(boolean a, boolean b) {
 288         return shortCircuitOr(a, !shortCircuitOr(b, !a));
 289     }
 290 
 291     public static boolean testCascadeSnippet45(boolean a, boolean b) {
 292         return shortCircuitOr(!shortCircuitOr(!a, b), !a);
 293     }
 294 
 295     public static boolean testCascadeSnippet46(boolean a, boolean b) {
 296         return shortCircuitOr(!shortCircuitOr(!b, a), !a);
 297     }
 298 
 299     public static boolean testCascadeSnippet47(boolean a, boolean b) {
 300         return shortCircuitOr(!a, !shortCircuitOr(a, !b));
 301     }
 302 
 303     public static boolean testCascadeSnippet48(boolean a, boolean b) {
 304         return shortCircuitOr(!a, !shortCircuitOr(!b, !a));
 305     }
 306 
 307     public static boolean testCascadeSnippet49(boolean a, boolean b) {
 308         return shortCircuitOr(shortCircuitOr(a, !b), !a);
 309     }
 310 
 311     public static boolean testCascadeSnippet50(boolean a, boolean b) {
 312         return shortCircuitOr(shortCircuitOr(b, !a), !a);
 313     }
 314 
 315     public static boolean testCascadeSnippet51(boolean a, boolean b) {
 316         return shortCircuitOr(a, shortCircuitOr(!a, !b));
 317     }
 318 
 319     public static boolean testCascadeSnippet52(boolean a, boolean b) {
 320         return shortCircuitOr(a, shortCircuitOr(!b, !a));
 321     }
 322 
 323     public static boolean testCascadeSnippet53(boolean a, boolean b) {
 324         return shortCircuitOr(!shortCircuitOr(a, !b), !a);
 325     }
 326 
 327     public static boolean testCascadeSnippet54(boolean a, boolean b) {
 328         return shortCircuitOr(!shortCircuitOr(b, !a), !a);
 329     }
 330 
 331     public static boolean testCascadeSnippet55(boolean a, boolean b) {
 332         return shortCircuitOr(!a, shortCircuitOr(!a, !b));
 333     }
 334 
 335     public static boolean testCascadeSnippet56(boolean a, boolean b) {
 336         return shortCircuitOr(!a, shortCircuitOr(!b, !a));
 337     }
 338 
 339     public static boolean testCascadeSnippet57(boolean a, boolean b) {
 340         return shortCircuitOr(shortCircuitOr(!a, !b), !a);
 341     }
 342 
 343     public static boolean testCascadeSnippet58(boolean a, boolean b) {
 344         return shortCircuitOr(shortCircuitOr(!b, !a), !a);
 345     }
 346 
 347     public static boolean testCascadeSnippet59(boolean a, boolean b) {
 348         return shortCircuitOr(a, !shortCircuitOr(!a, !b));
 349     }
 350 
 351     public static boolean testCascadeSnippet60(boolean a, boolean b) {
 352         return shortCircuitOr(a, !shortCircuitOr(!b, !a));
 353     }
 354 
 355     public static boolean testCascadeSnippet61(boolean a, boolean b) {
 356         return shortCircuitOr(!shortCircuitOr(!a, !b), !a);
 357     }
 358 
 359     public static boolean testCascadeSnippet62(boolean a, boolean b) {
 360         return shortCircuitOr(!shortCircuitOr(!b, !a), !a);
 361     }
 362 
 363     public static boolean testCascadeSnippet63(boolean a, boolean b) {
 364         return shortCircuitOr(!a, !shortCircuitOr(!a, !b));
 365     }
 366 
 367     public static boolean testCascadeSnippet64(boolean a, boolean b) {
 368         return shortCircuitOr(!a, !shortCircuitOr(!b, !a));
 369     }
 370 
 371     @Test
 372     public void testCascade() {
 373         for (int i = 1; i <= 64; ++i) {
 374             String snippet = "testCascadeSnippet" + i;
 375             StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES);
 376             PhaseContext context = new PhaseContext(getProviders());
 377             CanonicalizerPhase canonicalizer = new CanonicalizerPhase();
 378             canonicalizer.apply(graph, context);
 379             int shortCircuitCount = graph.getNodes(ShortCircuitOrNode.TYPE).count();
 380 
 381             int trueCount = testInputCombinations(snippet);
 382 
 383             if (trueCount % 2 == 0) {
 384                 // No ShortCircuitOrNode expected in the graph.
 385                 Assert.assertEquals(0, shortCircuitCount);
 386             } else {
 387                 // Only a single ShortCircuitOrNode expected in the graph.
 388                 Assert.assertEquals(1, shortCircuitCount);
 389             }
 390         }
 391     }
 392 }