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 }