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