001/* 002 * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved. 003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 004 * 005 * This code is free software; you can redistribute it and/or modify it 006 * under the terms of the GNU General Public License version 2 only, as 007 * published by the Free Software Foundation. 008 * 009 * This code is distributed in the hope that it will be useful, but WITHOUT 010 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 011 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 012 * version 2 for more details (a copy is included in the LICENSE file that 013 * accompanied this code). 014 * 015 * You should have received a copy of the GNU General Public License version 016 * 2 along with this work; if not, write to the Free Software Foundation, 017 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 018 * 019 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 020 * or visit www.oracle.com if you need additional information or have any 021 * questions. 022 */ 023package com.oracle.graal.nodes; 024 025import java.util.*; 026 027import jdk.internal.jvmci.common.*; 028import com.oracle.graal.debug.*; 029import jdk.internal.jvmci.meta.*; 030import jdk.internal.jvmci.meta.JavaTypeProfile.*; 031 032import com.oracle.graal.compiler.common.*; 033import com.oracle.graal.compiler.common.calc.*; 034import com.oracle.graal.compiler.common.type.*; 035import com.oracle.graal.graph.*; 036import com.oracle.graal.graph.iterators.*; 037import com.oracle.graal.graph.spi.*; 038import com.oracle.graal.nodeinfo.*; 039import com.oracle.graal.nodes.calc.*; 040import com.oracle.graal.nodes.java.*; 041import com.oracle.graal.nodes.spi.*; 042import com.oracle.graal.nodes.util.*; 043 044/** 045 * The {@code IfNode} represents a branch that can go one of two directions depending on the outcome 046 * of a comparison. 047 */ 048@NodeInfo 049public final class IfNode extends ControlSplitNode implements Simplifiable, LIRLowerable { 050 public static final NodeClass<IfNode> TYPE = NodeClass.create(IfNode.class); 051 052 private static final DebugMetric CORRECTED_PROBABILITIES = Debug.metric("CorrectedProbabilities"); 053 054 @Successor AbstractBeginNode trueSuccessor; 055 @Successor AbstractBeginNode falseSuccessor; 056 @Input(InputType.Condition) LogicNode condition; 057 protected double trueSuccessorProbability; 058 059 public LogicNode condition() { 060 return condition; 061 } 062 063 public void setCondition(LogicNode x) { 064 updateUsages(condition, x); 065 condition = x; 066 } 067 068 public IfNode(LogicNode condition, FixedNode trueSuccessor, FixedNode falseSuccessor, double trueSuccessorProbability) { 069 this(condition, BeginNode.begin(trueSuccessor), BeginNode.begin(falseSuccessor), trueSuccessorProbability); 070 } 071 072 public IfNode(LogicNode condition, AbstractBeginNode trueSuccessor, AbstractBeginNode falseSuccessor, double trueSuccessorProbability) { 073 super(TYPE, StampFactory.forVoid()); 074 this.condition = condition; 075 this.falseSuccessor = falseSuccessor; 076 this.trueSuccessor = trueSuccessor; 077 setTrueSuccessorProbability(trueSuccessorProbability); 078 } 079 080 /** 081 * Gets the true successor. 082 * 083 * @return the true successor 084 */ 085 public AbstractBeginNode trueSuccessor() { 086 return trueSuccessor; 087 } 088 089 /** 090 * Gets the false successor. 091 * 092 * @return the false successor 093 */ 094 public AbstractBeginNode falseSuccessor() { 095 return falseSuccessor; 096 } 097 098 public double getTrueSuccessorProbability() { 099 return this.trueSuccessorProbability; 100 } 101 102 public void setTrueSuccessor(AbstractBeginNode node) { 103 updatePredecessor(trueSuccessor, node); 104 trueSuccessor = node; 105 } 106 107 public void setFalseSuccessor(AbstractBeginNode node) { 108 updatePredecessor(falseSuccessor, node); 109 falseSuccessor = node; 110 } 111 112 /** 113 * Gets the node corresponding to the specified outcome of the branch. 114 * 115 * @param istrue {@code true} if the true successor is requested, {@code false} otherwise 116 * @return the corresponding successor 117 */ 118 public AbstractBeginNode successor(boolean istrue) { 119 return istrue ? trueSuccessor : falseSuccessor; 120 } 121 122 public void setTrueSuccessorProbability(double prob) { 123 assert prob >= -0.000000001 && prob <= 1.000000001 : "Probability out of bounds: " + prob; 124 trueSuccessorProbability = Math.min(1.0, Math.max(0.0, prob)); 125 } 126 127 @Override 128 public double probability(AbstractBeginNode successor) { 129 return successor == trueSuccessor ? trueSuccessorProbability : 1 - trueSuccessorProbability; 130 } 131 132 @Override 133 public void generate(NodeLIRBuilderTool gen) { 134 gen.emitIf(this); 135 } 136 137 @Override 138 public boolean verify() { 139 assertTrue(condition() != null, "missing condition"); 140 assertTrue(trueSuccessor() != null, "missing trueSuccessor"); 141 assertTrue(falseSuccessor() != null, "missing falseSuccessor"); 142 return super.verify(); 143 } 144 145 public void eliminateNegation() { 146 AbstractBeginNode oldTrueSuccessor = trueSuccessor; 147 AbstractBeginNode oldFalseSuccessor = falseSuccessor; 148 trueSuccessor = oldFalseSuccessor; 149 falseSuccessor = oldTrueSuccessor; 150 trueSuccessorProbability = 1 - trueSuccessorProbability; 151 setCondition(((LogicNegationNode) condition).getValue()); 152 } 153 154 @Override 155 public void simplify(SimplifierTool tool) { 156 if (trueSuccessor().next() instanceof DeoptimizeNode) { 157 if (trueSuccessorProbability != 0) { 158 CORRECTED_PROBABILITIES.increment(); 159 trueSuccessorProbability = 0; 160 } 161 } else if (falseSuccessor().next() instanceof DeoptimizeNode) { 162 if (trueSuccessorProbability != 1) { 163 CORRECTED_PROBABILITIES.increment(); 164 trueSuccessorProbability = 1; 165 } 166 } 167 168 if (condition() instanceof LogicNegationNode) { 169 eliminateNegation(); 170 } 171 if (condition() instanceof LogicConstantNode) { 172 LogicConstantNode c = (LogicConstantNode) condition(); 173 if (c.getValue()) { 174 tool.deleteBranch(falseSuccessor()); 175 tool.addToWorkList(trueSuccessor()); 176 graph().removeSplit(this, trueSuccessor()); 177 } else { 178 tool.deleteBranch(trueSuccessor()); 179 tool.addToWorkList(falseSuccessor()); 180 graph().removeSplit(this, falseSuccessor()); 181 } 182 return; 183 } 184 if (tool.allUsagesAvailable() && trueSuccessor().hasNoUsages() && falseSuccessor().hasNoUsages()) { 185 186 pushNodesThroughIf(tool); 187 188 if (checkForUnsignedCompare(tool) || removeOrMaterializeIf(tool)) { 189 return; 190 } 191 } 192 193 if (removeIntermediateMaterialization(tool)) { 194 return; 195 } 196 197 if (splitIfAtPhi(tool)) { 198 return; 199 } 200 201 if (falseSuccessor().hasNoUsages() && (!(falseSuccessor() instanceof LoopExitNode)) && falseSuccessor().next() instanceof IfNode) { 202 AbstractBeginNode intermediateBegin = falseSuccessor(); 203 IfNode nextIf = (IfNode) intermediateBegin.next(); 204 double probabilityB = (1.0 - this.trueSuccessorProbability) * nextIf.trueSuccessorProbability; 205 if (this.trueSuccessorProbability < probabilityB) { 206 // Reordering of those two if statements is beneficial from the point of view of 207 // their probabilities. 208 if (prepareForSwap(tool.getConstantReflection(), condition(), nextIf.condition(), this.trueSuccessorProbability, probabilityB)) { 209 // Reordering is allowed from (if1 => begin => if2) to (if2 => begin => if1). 210 assert intermediateBegin.next() == nextIf; 211 AbstractBeginNode bothFalseBegin = nextIf.falseSuccessor(); 212 nextIf.setFalseSuccessor(null); 213 intermediateBegin.setNext(null); 214 this.setFalseSuccessor(null); 215 216 this.replaceAtPredecessor(nextIf); 217 nextIf.setFalseSuccessor(intermediateBegin); 218 intermediateBegin.setNext(this); 219 this.setFalseSuccessor(bothFalseBegin); 220 nextIf.setTrueSuccessorProbability(probabilityB); 221 if (probabilityB == 1.0) { 222 this.setTrueSuccessorProbability(0.0); 223 } else { 224 double newProbability = this.trueSuccessorProbability / (1.0 - probabilityB); 225 this.setTrueSuccessorProbability(Math.min(1.0, newProbability)); 226 } 227 return; 228 } 229 } 230 } 231 } 232 233 private void pushNodesThroughIf(SimplifierTool tool) { 234 assert trueSuccessor().hasNoUsages() && falseSuccessor().hasNoUsages(); 235 // push similar nodes upwards through the if, thereby deduplicating them 236 do { 237 AbstractBeginNode trueSucc = trueSuccessor(); 238 AbstractBeginNode falseSucc = falseSuccessor(); 239 if (trueSucc instanceof BeginNode && falseSucc instanceof BeginNode && trueSucc.next() instanceof FixedWithNextNode && falseSucc.next() instanceof FixedWithNextNode) { 240 FixedWithNextNode trueNext = (FixedWithNextNode) trueSucc.next(); 241 FixedWithNextNode falseNext = (FixedWithNextNode) falseSucc.next(); 242 NodeClass<?> nodeClass = trueNext.getNodeClass(); 243 if (trueNext.getClass() == falseNext.getClass()) { 244 if (nodeClass.getInputEdges().areEqualIn(trueNext, falseNext) && trueNext.valueEquals(falseNext)) { 245 falseNext.replaceAtUsages(trueNext); 246 graph().removeFixed(falseNext); 247 GraphUtil.unlinkFixedNode(trueNext); 248 graph().addBeforeFixed(this, trueNext); 249 for (Node usage : trueNext.usages().snapshot()) { 250 if (usage.isAlive()) { 251 NodeClass<?> usageNodeClass = usage.getNodeClass(); 252 if (usageNodeClass.valueNumberable() && !usageNodeClass.isLeafNode()) { 253 Node newNode = graph().findDuplicate(usage); 254 if (newNode != null) { 255 usage.replaceAtUsages(newNode); 256 usage.safeDelete(); 257 } 258 } 259 if (usage.isAlive()) { 260 tool.addToWorkList(usage); 261 } 262 } 263 } 264 continue; 265 } 266 } 267 } 268 break; 269 } while (true); 270 } 271 272 /** 273 * Recognize a couple patterns that can be merged into an unsigned compare. 274 * 275 * @param tool 276 * @return true if a replacement was done. 277 */ 278 private boolean checkForUnsignedCompare(SimplifierTool tool) { 279 assert trueSuccessor().hasNoUsages() && falseSuccessor().hasNoUsages(); 280 if (condition() instanceof IntegerLessThanNode) { 281 IntegerLessThanNode lessThan = (IntegerLessThanNode) condition(); 282 Constant y = lessThan.getY().stamp().asConstant(); 283 if (y instanceof PrimitiveConstant && ((PrimitiveConstant) y).asLong() == 0 && falseSuccessor().next() instanceof IfNode) { 284 IfNode ifNode2 = (IfNode) falseSuccessor().next(); 285 if (ifNode2.condition() instanceof IntegerLessThanNode) { 286 IntegerLessThanNode lessThan2 = (IntegerLessThanNode) ifNode2.condition(); 287 AbstractBeginNode falseSucc = ifNode2.falseSuccessor(); 288 AbstractBeginNode trueSucc = ifNode2.trueSuccessor(); 289 IntegerBelowNode below = null; 290 /* 291 * Convert x >= 0 && x < positive which is represented as !(x < 0) && x < 292 * <positive> into an unsigned compare. 293 */ 294 if (lessThan2.getX() == lessThan.getX() && lessThan2.getY().stamp() instanceof IntegerStamp && ((IntegerStamp) lessThan2.getY().stamp()).isPositive() && 295 sameDestination(trueSuccessor(), ifNode2.falseSuccessor)) { 296 below = graph().unique(new IntegerBelowNode(lessThan2.getX(), lessThan2.getY())); 297 // swap direction 298 AbstractBeginNode tmp = falseSucc; 299 falseSucc = trueSucc; 300 trueSucc = tmp; 301 } else if (lessThan2.getY() == lessThan.getX() && sameDestination(trueSuccessor(), ifNode2.trueSuccessor)) { 302 /* 303 * Convert x >= 0 && x <= positive which is represented as !(x < 0) && 304 * !(<positive> > x), into x <| positive + 1. This can only be done for 305 * constants since there isn't a IntegerBelowEqualThanNode but that doesn't 306 * appear to be interesting. 307 */ 308 JavaConstant positive = lessThan2.getX().asJavaConstant(); 309 if (positive != null && positive.asLong() > 0 && positive.asLong() < positive.getKind().getMaxValue()) { 310 ConstantNode newLimit = ConstantNode.forIntegerStamp(lessThan2.getX().stamp(), positive.asLong() + 1, graph()); 311 below = graph().unique(new IntegerBelowNode(lessThan.getX(), newLimit)); 312 } 313 } 314 if (below != null) { 315 ifNode2.setTrueSuccessor(null); 316 ifNode2.setFalseSuccessor(null); 317 318 IfNode newIfNode = graph().add(new IfNode(below, falseSucc, trueSucc, 1 - trueSuccessorProbability)); 319 // Remove the < 0 test. 320 tool.deleteBranch(trueSuccessor); 321 graph().removeSplit(this, falseSuccessor); 322 323 // Replace the second test with the new one. 324 ifNode2.predecessor().replaceFirstSuccessor(ifNode2, newIfNode); 325 ifNode2.safeDelete(); 326 return true; 327 } 328 } 329 } 330 } 331 return false; 332 } 333 334 /** 335 * Check it these two blocks end up at the same place. Meeting at the same merge, or 336 * deoptimizing in the same way. 337 */ 338 private static boolean sameDestination(AbstractBeginNode succ1, AbstractBeginNode succ2) { 339 Node next1 = succ1.next(); 340 Node next2 = succ2.next(); 341 if (next1 instanceof EndNode && next2 instanceof EndNode) { 342 EndNode end1 = (EndNode) next1; 343 EndNode end2 = (EndNode) next2; 344 if (end1.merge() == end2.merge()) { 345 for (PhiNode phi : end1.merge().phis()) { 346 if (phi.valueAt(end1) != phi.valueAt(end2)) { 347 return false; 348 } 349 } 350 // They go to the same MergeNode and merge the same values 351 return true; 352 } 353 } else if (next1 instanceof DeoptimizeNode && next2 instanceof DeoptimizeNode) { 354 DeoptimizeNode deopt1 = (DeoptimizeNode) next1; 355 DeoptimizeNode deopt2 = (DeoptimizeNode) next2; 356 if (deopt1.reason() == deopt2.reason() && deopt1.action() == deopt2.action()) { 357 // Same deoptimization reason and action. 358 return true; 359 } 360 } else if (next1 instanceof LoopExitNode && next2 instanceof LoopExitNode) { 361 LoopExitNode exit1 = (LoopExitNode) next1; 362 LoopExitNode exit2 = (LoopExitNode) next2; 363 if (exit1.loopBegin() == exit2.loopBegin() && exit1.stateAfter() == exit2.stateAfter() && exit1.stateAfter() == null && sameDestination(exit1, exit2)) { 364 // Exit the same loop and end up at the same place. 365 return true; 366 } 367 } else if (next1 instanceof ReturnNode && next2 instanceof ReturnNode) { 368 ReturnNode exit1 = (ReturnNode) next1; 369 ReturnNode exit2 = (ReturnNode) next2; 370 if (exit1.result() == exit2.result()) { 371 // Exit the same loop and end up at the same place. 372 return true; 373 } 374 } 375 return false; 376 } 377 378 private static final class MutableProfiledType { 379 final ResolvedJavaType type; 380 double probability; 381 382 public MutableProfiledType(ResolvedJavaType type, double probability) { 383 this.type = type; 384 this.probability = probability; 385 } 386 } 387 388 private static boolean prepareForSwap(ConstantReflectionProvider constantReflection, LogicNode a, LogicNode b, double probabilityA, double probabilityB) { 389 if (a instanceof InstanceOfNode) { 390 InstanceOfNode instanceOfA = (InstanceOfNode) a; 391 if (b instanceof IsNullNode) { 392 IsNullNode isNullNode = (IsNullNode) b; 393 if (isNullNode.getValue() == instanceOfA.getValue()) { 394 if (instanceOfA.profile() != null && instanceOfA.profile().getNullSeen() != TriState.FALSE) { 395 instanceOfA.setProfile(new JavaTypeProfile(TriState.FALSE, instanceOfA.profile().getNotRecordedProbability(), instanceOfA.profile().getTypes())); 396 } 397 Debug.log("Can swap instanceof and isnull if"); 398 return true; 399 } 400 } else if (b instanceof InstanceOfNode) { 401 InstanceOfNode instanceOfB = (InstanceOfNode) b; 402 if (instanceOfA.getValue() == instanceOfB.getValue() && !instanceOfA.type().isInterface() && !instanceOfB.type().isInterface() && 403 !instanceOfA.type().isAssignableFrom(instanceOfB.type()) && !instanceOfB.type().isAssignableFrom(instanceOfA.type())) { 404 // Two instanceof on the same value with mutually exclusive types. 405 Debug.log("Can swap instanceof for types %s and %s", instanceOfA.type(), instanceOfB.type()); 406 swapInstanceOfProfiles(probabilityA, probabilityB, instanceOfA, instanceOfB); 407 return true; 408 } 409 } 410 } else if (a instanceof CompareNode) { 411 CompareNode compareA = (CompareNode) a; 412 Condition conditionA = compareA.condition(); 413 if (compareA.unorderedIsTrue()) { 414 return false; 415 } 416 if (b instanceof CompareNode) { 417 CompareNode compareB = (CompareNode) b; 418 if (compareA == compareB) { 419 Debug.log("Same conditions => do not swap and leave the work for global value numbering."); 420 return false; 421 } 422 if (compareB.unorderedIsTrue()) { 423 return false; 424 } 425 Condition comparableCondition = null; 426 Condition conditionB = compareB.condition(); 427 if (compareB.getX() == compareA.getX() && compareB.getY() == compareA.getY()) { 428 comparableCondition = conditionB; 429 } else if (compareB.getX() == compareA.getY() && compareB.getY() == compareA.getX()) { 430 comparableCondition = conditionB.mirror(); 431 } 432 433 if (comparableCondition != null) { 434 Condition combined = conditionA.join(comparableCondition); 435 if (combined == null) { 436 // The two conditions are disjoint => can reorder. 437 Debug.log("Can swap disjoint coditions on same values: %s and %s", conditionA, comparableCondition); 438 return true; 439 } 440 } else if (conditionA == Condition.EQ && conditionB == Condition.EQ) { 441 boolean canSwap = false; 442 if ((compareA.getX() == compareB.getX() && valuesDistinct(constantReflection, compareA.getY(), compareB.getY()))) { 443 canSwap = true; 444 } else if ((compareA.getX() == compareB.getY() && valuesDistinct(constantReflection, compareA.getY(), compareB.getX()))) { 445 canSwap = true; 446 } else if ((compareA.getY() == compareB.getX() && valuesDistinct(constantReflection, compareA.getX(), compareB.getY()))) { 447 canSwap = true; 448 } else if ((compareA.getY() == compareB.getY() && valuesDistinct(constantReflection, compareA.getX(), compareB.getX()))) { 449 canSwap = true; 450 } 451 452 if (canSwap) { 453 Debug.log("Can swap equality condition with one shared and one disjoint value."); 454 return true; 455 } 456 } 457 } 458 } 459 460 return false; 461 } 462 463 /** 464 * Arbitrary fraction of not recorded types that we'll guess are sub-types of B. 465 * 466 * This is is used because we can not check if the unrecorded types are sub-types of B or not. 467 */ 468 private static final double NOT_RECORDED_SUBTYPE_B = 0.5; 469 470 /** 471 * If the not-recorded fraction of types for the new profile of <code>instanceOfA</code> is 472 * above this threshold, no profile is used for this <code>instanceof</code> after the swap. 473 * 474 * The idea is that the reconstructed profile would contain too much unknowns to be of any use. 475 */ 476 private static final double NOT_RECORDED_CUTOFF = 0.4; 477 478 /** 479 * Tries to reconstruct profiles for the swapped <code>instanceof</code> checks. 480 * 481 * The tested types must be mutually exclusive. 482 */ 483 private static void swapInstanceOfProfiles(double probabilityA, double probabilityB, InstanceOfNode instanceOfA, InstanceOfNode instanceOfB) { 484 JavaTypeProfile profileA = instanceOfA.profile(); 485 JavaTypeProfile profileB = instanceOfB.profile(); 486 487 JavaTypeProfile newProfileA = null; 488 JavaTypeProfile newProfileB = null; 489 if (profileA != null || profileB != null) { 490 List<MutableProfiledType> newProfiledTypesA = new ArrayList<>(); 491 List<MutableProfiledType> newProfiledTypesB = new ArrayList<>(); 492 double totalProbabilityA = 0.0; 493 double totalProbabilityB = 0.0; 494 double newNotRecordedA = 0.0; 495 double newNotRecordedB = 0.0; 496 TriState nullSeen = TriState.UNKNOWN; 497 if (profileA != null) { 498 for (ProfiledType profiledType : profileA.getTypes()) { 499 newProfiledTypesB.add(new MutableProfiledType(profiledType.getType(), profiledType.getProbability())); 500 totalProbabilityB += profiledType.getProbability(); 501 if (!instanceOfB.type().isAssignableFrom(profiledType.getType())) { 502 double typeProbabilityA = profiledType.getProbability() / (1 - probabilityB); 503 newProfiledTypesA.add(new MutableProfiledType(profiledType.getType(), typeProbabilityA)); 504 totalProbabilityA += typeProbabilityA; 505 } 506 } 507 newNotRecordedB += profileA.getNotRecordedProbability(); 508 newNotRecordedA += NOT_RECORDED_SUBTYPE_B * profileA.getNotRecordedProbability() / (1 - probabilityB); 509 nullSeen = profileA.getNullSeen(); 510 } 511 int searchA = newProfiledTypesA.size(); 512 int searchB = newProfiledTypesB.size(); 513 if (profileB != null) { 514 for (ProfiledType profiledType : profileB.getTypes()) { 515 double typeProbabilityB = profiledType.getProbability() * (1 - probabilityA); 516 appendOrMerge(profiledType.getType(), typeProbabilityB, searchB, newProfiledTypesB); 517 totalProbabilityB += typeProbabilityB; 518 if (!instanceOfB.type().isAssignableFrom(profiledType.getType())) { 519 double typeProbabilityA = typeProbabilityB / (1 - probabilityB); 520 appendOrMerge(profiledType.getType(), typeProbabilityA, searchA, newProfiledTypesA); 521 totalProbabilityA += typeProbabilityA; 522 } 523 } 524 newNotRecordedB += profileB.getNotRecordedProbability() * (1 - probabilityA); 525 newNotRecordedA += NOT_RECORDED_SUBTYPE_B * profileB.getNotRecordedProbability() * (1 - probabilityA) / (1 - probabilityB); 526 nullSeen = TriState.merge(nullSeen, profileB.getNullSeen()); 527 } 528 totalProbabilityA += newNotRecordedA; 529 totalProbabilityB += newNotRecordedB; 530 531 if (newNotRecordedA / NOT_RECORDED_SUBTYPE_B > NOT_RECORDED_CUTOFF) { 532 // too much unknown 533 newProfileA = null; 534 } else { 535 newProfileA = makeProfile(totalProbabilityA, newNotRecordedA, newProfiledTypesA, nullSeen); 536 } 537 newProfileB = makeProfile(totalProbabilityB, newNotRecordedB, newProfiledTypesB, nullSeen); 538 } 539 540 instanceOfB.setProfile(newProfileB); 541 instanceOfA.setProfile(newProfileA); 542 } 543 544 private static JavaTypeProfile makeProfile(double totalProbability, double notRecorded, List<MutableProfiledType> profiledTypes, TriState nullSeen) { 545 // protect against NaNs and empty profiles 546 if (totalProbability > 0.0) { 547 // normalize 548 ProfiledType[] profiledTypesArray = new ProfiledType[profiledTypes.size()]; 549 int i = 0; 550 for (MutableProfiledType profiledType : profiledTypes) { 551 profiledTypesArray[i++] = new ProfiledType(profiledType.type, profiledType.probability / totalProbability); 552 } 553 554 // sort 555 Arrays.sort(profiledTypesArray); 556 557 return new JavaTypeProfile(nullSeen, notRecorded / totalProbability, profiledTypesArray); 558 } 559 return null; 560 } 561 562 private static void appendOrMerge(ResolvedJavaType type, double probability, int searchUntil, List<MutableProfiledType> list) { 563 for (int i = 0; i < searchUntil; i++) { 564 MutableProfiledType profiledType = list.get(i); 565 if (profiledType.type.equals(type)) { 566 profiledType.probability += probability; 567 return; 568 } 569 } 570 list.add(new MutableProfiledType(type, probability)); 571 } 572 573 private static boolean valuesDistinct(ConstantReflectionProvider constantReflection, ValueNode a, ValueNode b) { 574 if (a.isConstant() && b.isConstant()) { 575 Boolean equal = constantReflection.constantEquals(a.asConstant(), b.asConstant()); 576 if (equal != null) { 577 return !equal.booleanValue(); 578 } 579 } 580 581 Stamp stampA = a.stamp(); 582 Stamp stampB = b.stamp(); 583 return stampA.alwaysDistinct(stampB); 584 } 585 586 /** 587 * Tries to remove an empty if construct or replace an if construct with a materialization. 588 * 589 * @return true if a transformation was made, false otherwise 590 */ 591 private boolean removeOrMaterializeIf(SimplifierTool tool) { 592 assert trueSuccessor().hasNoUsages() && falseSuccessor().hasNoUsages(); 593 if (trueSuccessor().next() instanceof AbstractEndNode && falseSuccessor().next() instanceof AbstractEndNode) { 594 AbstractEndNode trueEnd = (AbstractEndNode) trueSuccessor().next(); 595 AbstractEndNode falseEnd = (AbstractEndNode) falseSuccessor().next(); 596 AbstractMergeNode merge = trueEnd.merge(); 597 if (merge == falseEnd.merge() && trueSuccessor().anchored().isEmpty() && falseSuccessor().anchored().isEmpty()) { 598 PhiNode singlePhi = null; 599 int distinct = 0; 600 for (PhiNode phi : merge.phis()) { 601 ValueNode trueValue = phi.valueAt(trueEnd); 602 ValueNode falseValue = phi.valueAt(falseEnd); 603 if (trueValue != falseValue) { 604 distinct++; 605 singlePhi = phi; 606 } 607 } 608 if (distinct == 0) { 609 /* 610 * Multiple phis but merging same values for true and false, so simply delete 611 * the path 612 */ 613 removeThroughFalseBranch(tool); 614 return true; 615 } else if (distinct == 1) { 616 ValueNode trueValue = singlePhi.valueAt(trueEnd); 617 ValueNode falseValue = singlePhi.valueAt(falseEnd); 618 ConditionalNode conditional = canonicalizeConditionalCascade(trueValue, falseValue); 619 if (conditional != null) { 620 singlePhi.setValueAt(trueEnd, conditional); 621 removeThroughFalseBranch(tool); 622 return true; 623 } 624 } 625 } 626 } 627 if (trueSuccessor().next() instanceof ReturnNode && falseSuccessor().next() instanceof ReturnNode) { 628 ReturnNode trueEnd = (ReturnNode) trueSuccessor().next(); 629 ReturnNode falseEnd = (ReturnNode) falseSuccessor().next(); 630 ValueNode trueValue = trueEnd.result(); 631 ValueNode falseValue = falseEnd.result(); 632 ValueNode value = null; 633 if (trueValue != null) { 634 if (trueValue == falseValue) { 635 value = trueValue; 636 } else { 637 value = canonicalizeConditionalCascade(trueValue, falseValue); 638 if (value == null) { 639 return false; 640 } 641 } 642 } 643 ReturnNode newReturn = graph().add(new ReturnNode(value)); 644 replaceAtPredecessor(newReturn); 645 GraphUtil.killCFG(this); 646 return true; 647 } 648 return false; 649 } 650 651 protected void removeThroughFalseBranch(SimplifierTool tool) { 652 AbstractBeginNode trueBegin = trueSuccessor(); 653 graph().removeSplitPropagate(this, trueBegin, tool); 654 tool.addToWorkList(trueBegin); 655 if (condition().isAlive() && condition().hasNoUsages()) { 656 GraphUtil.killWithUnusedFloatingInputs(condition()); 657 } 658 } 659 660 private ConditionalNode canonicalizeConditionalCascade(ValueNode trueValue, ValueNode falseValue) { 661 if (trueValue.getKind() != falseValue.getKind()) { 662 return null; 663 } 664 if (trueValue.getKind() != Kind.Int && trueValue.getKind() != Kind.Long) { 665 return null; 666 } 667 if (trueValue.isConstant() && falseValue.isConstant()) { 668 return graph().unique(new ConditionalNode(condition(), trueValue, falseValue)); 669 } else { 670 ConditionalNode conditional = null; 671 ValueNode constant = null; 672 boolean negateCondition; 673 if (trueValue instanceof ConditionalNode && falseValue.isConstant()) { 674 conditional = (ConditionalNode) trueValue; 675 constant = falseValue; 676 negateCondition = true; 677 } else if (falseValue instanceof ConditionalNode && trueValue.isConstant()) { 678 conditional = (ConditionalNode) falseValue; 679 constant = trueValue; 680 negateCondition = false; 681 } else { 682 return null; 683 } 684 boolean negateConditionalCondition; 685 ValueNode otherValue; 686 if (constant == conditional.trueValue()) { 687 otherValue = conditional.falseValue(); 688 negateConditionalCondition = false; 689 } else if (constant == conditional.falseValue()) { 690 otherValue = conditional.trueValue(); 691 negateConditionalCondition = true; 692 } else { 693 return null; 694 } 695 if (otherValue.isConstant()) { 696 double shortCutProbability = probability(trueSuccessor()); 697 LogicNode newCondition = LogicNode.or(condition(), negateCondition, conditional.condition(), negateConditionalCondition, shortCutProbability); 698 return graph().unique(new ConditionalNode(newCondition, constant, otherValue)); 699 } 700 } 701 return null; 702 } 703 704 /** 705 * Take an if that is immediately dominated by a merge with a single phi and split off any paths 706 * where the test would be statically decidable creating a new merge below the approriate side 707 * of the IfNode. Any undecidable tests will continue to use the original IfNode. 708 * 709 * @param tool 710 */ 711 @SuppressWarnings("unchecked") 712 private boolean splitIfAtPhi(SimplifierTool tool) { 713 if (!(predecessor() instanceof MergeNode)) { 714 return false; 715 } 716 MergeNode merge = (MergeNode) predecessor(); 717 if (merge.forwardEndCount() == 1) { 718 // Don't bother. 719 return false; 720 } 721 if (merge.usages().count() != 1 || merge.phis().count() != 1) { 722 return false; 723 } 724 if (merge.stateAfter() != null) { 725 /* We'll get the chance to simplify this after frame state assignment. */ 726 return false; 727 } 728 PhiNode phi = merge.phis().first(); 729 if (phi.usages().count() != 1 || condition().usages().count() != 1) { 730 /* 731 * For simplicity the below code assumes assumes the phi goes dead at the end so skip 732 * this case. 733 */ 734 return false; 735 } 736 737 if (condition() instanceof Canonicalizable.Unary<?>) { 738 Canonicalizable.Unary<?> unary = (Canonicalizable.Unary<?>) condition(); 739 if (unary.getValue() != phi) { 740 return false; 741 } 742 } else if (condition() instanceof Canonicalizable.Binary<?>) { 743 Canonicalizable.Binary<?> binary = (Canonicalizable.Binary<?>) condition(); 744 if (binary.getX() != phi && binary.getY() != phi) { 745 return false; 746 } 747 } else { 748 return false; 749 } 750 751 /* 752 * We could additionally filter for the case that at least some of the Phi inputs or one of 753 * the condition inputs are constants but there are cases where a non-constant is 754 * simplifiable, usually where the stamp allows the question to be answered. 755 */ 756 757 /* Each successor of the if gets a new merge if needed. */ 758 MergeNode trueMerge = null; 759 MergeNode falseMerge = null; 760 assert merge.stateAfter() == null; 761 762 for (EndNode end : merge.forwardEnds().snapshot()) { 763 Node value = phi.valueAt(end); 764 Node result = null; 765 if (condition() instanceof Canonicalizable.Binary<?>) { 766 Canonicalizable.Binary<Node> compare = (Canonicalizable.Binary<Node>) condition; 767 if (compare.getX() == phi) { 768 result = compare.canonical(tool, value, compare.getY()); 769 } else { 770 result = compare.canonical(tool, compare.getX(), value); 771 } 772 } else { 773 assert condition() instanceof Canonicalizable.Unary<?>; 774 Canonicalizable.Unary<Node> compare = (Canonicalizable.Unary<Node>) condition; 775 result = compare.canonical(tool, value); 776 } 777 if (result instanceof LogicConstantNode) { 778 merge.removeEnd(end); 779 if (((LogicConstantNode) result).getValue()) { 780 if (trueMerge == null) { 781 trueMerge = insertMerge(trueSuccessor()); 782 } 783 trueMerge.addForwardEnd(end); 784 } else { 785 if (falseMerge == null) { 786 falseMerge = insertMerge(falseSuccessor()); 787 } 788 falseMerge.addForwardEnd(end); 789 } 790 } 791 } 792 transferProxies(trueSuccessor(), trueMerge); 793 transferProxies(falseSuccessor(), falseMerge); 794 795 cleanupMerge(tool, merge); 796 cleanupMerge(tool, trueMerge); 797 cleanupMerge(tool, falseMerge); 798 799 return true; 800 } 801 802 private static void transferProxies(AbstractBeginNode successor, MergeNode falseMerge) { 803 if (falseMerge != null) { 804 for (ProxyNode proxy : successor.proxies().snapshot()) { 805 proxy.replaceFirstInput(successor, falseMerge); 806 } 807 } 808 } 809 810 private void cleanupMerge(SimplifierTool tool, MergeNode merge) { 811 if (merge != null && merge.isAlive()) { 812 if (merge.forwardEndCount() == 0) { 813 GraphUtil.killCFG(merge, tool); 814 } else if (merge.forwardEndCount() == 1) { 815 graph().reduceTrivialMerge(merge); 816 } 817 } 818 } 819 820 private MergeNode insertMerge(AbstractBeginNode begin) { 821 MergeNode merge = graph().add(new MergeNode()); 822 if (!begin.anchored().isEmpty()) { 823 Object before = null; 824 before = begin.anchored().snapshot(); 825 begin.replaceAtUsages(InputType.Guard, merge); 826 begin.replaceAtUsages(InputType.Anchor, merge); 827 assert begin.anchored().isEmpty() : before + " " + begin.anchored().snapshot(); 828 } 829 830 AbstractBeginNode theBegin = begin; 831 if (begin instanceof LoopExitNode) { 832 // Insert an extra begin to make it easier. 833 theBegin = graph().add(new BeginNode()); 834 begin.replaceAtPredecessor(theBegin); 835 theBegin.setNext(begin); 836 } 837 FixedNode next = theBegin.next(); 838 next.replaceAtPredecessor(merge); 839 theBegin.setNext(graph().add(new EndNode())); 840 merge.addForwardEnd((EndNode) theBegin.next()); 841 merge.setNext(next); 842 return merge; 843 } 844 845 /** 846 * Tries to connect code that initializes a variable directly with the successors of an if 847 * construct that switches on the variable. For example, the pseudo code below: 848 * 849 * <pre> 850 * contains(list, e, yes, no) { 851 * if (list == null || e == null) { 852 * condition = false; 853 * } else { 854 * condition = false; 855 * for (i in list) { 856 * if (i.equals(e)) { 857 * condition = true; 858 * break; 859 * } 860 * } 861 * } 862 * if (condition) { 863 * return yes; 864 * } else { 865 * return no; 866 * } 867 * } 868 * </pre> 869 * 870 * will be transformed into: 871 * 872 * <pre> 873 * contains(list, e, yes, no) { 874 * if (list == null || e == null) { 875 * return no; 876 * } else { 877 * condition = false; 878 * for (i in list) { 879 * if (i.equals(e)) { 880 * return yes; 881 * } 882 * } 883 * return no; 884 * } 885 * } 886 * </pre> 887 * 888 * @return true if a transformation was made, false otherwise 889 */ 890 private boolean removeIntermediateMaterialization(SimplifierTool tool) { 891 if (!(predecessor() instanceof AbstractMergeNode) || predecessor() instanceof LoopBeginNode) { 892 return false; 893 } 894 AbstractMergeNode merge = (AbstractMergeNode) predecessor(); 895 896 if (!(condition() instanceof CompareNode)) { 897 return false; 898 } 899 900 CompareNode compare = (CompareNode) condition(); 901 if (compare.getUsageCount() != 1) { 902 return false; 903 } 904 905 // Only consider merges with a single usage that is both a phi and an operand of the 906 // comparison 907 NodeIterable<Node> mergeUsages = merge.usages(); 908 if (mergeUsages.count() != 1) { 909 return false; 910 } 911 Node singleUsage = mergeUsages.first(); 912 if (!(singleUsage instanceof ValuePhiNode) || (singleUsage != compare.getX() && singleUsage != compare.getY())) { 913 return false; 914 } 915 916 // Ensure phi is used by at most the comparison and the merge's frame state (if any) 917 ValuePhiNode phi = (ValuePhiNode) singleUsage; 918 NodeIterable<Node> phiUsages = phi.usages(); 919 if (phiUsages.count() > 2) { 920 return false; 921 } 922 for (Node usage : phiUsages) { 923 if (usage != compare && usage != merge.stateAfter()) { 924 return false; 925 } 926 } 927 928 List<EndNode> mergePredecessors = merge.cfgPredecessors().snapshot(); 929 assert phi.valueCount() == merge.forwardEndCount(); 930 931 Constant[] xs = constantValues(compare.getX(), merge, false); 932 Constant[] ys = constantValues(compare.getY(), merge, false); 933 if (xs == null || ys == null) { 934 return false; 935 } 936 937 // Sanity check that both ends are not followed by a merge without frame state. 938 if (!checkFrameState(trueSuccessor()) && !checkFrameState(falseSuccessor())) { 939 return false; 940 } 941 942 List<EndNode> falseEnds = new ArrayList<>(mergePredecessors.size()); 943 List<EndNode> trueEnds = new ArrayList<>(mergePredecessors.size()); 944 Map<AbstractEndNode, ValueNode> phiValues = CollectionsFactory.newMap(mergePredecessors.size()); 945 946 AbstractBeginNode oldFalseSuccessor = falseSuccessor(); 947 AbstractBeginNode oldTrueSuccessor = trueSuccessor(); 948 949 setFalseSuccessor(null); 950 setTrueSuccessor(null); 951 952 Iterator<EndNode> ends = mergePredecessors.iterator(); 953 for (int i = 0; i < xs.length; i++) { 954 EndNode end = ends.next(); 955 phiValues.put(end, phi.valueAt(end)); 956 if (compare.condition().foldCondition(xs[i], ys[i], tool.getConstantReflection(), compare.unorderedIsTrue())) { 957 trueEnds.add(end); 958 } else { 959 falseEnds.add(end); 960 } 961 } 962 assert !ends.hasNext(); 963 assert falseEnds.size() + trueEnds.size() == xs.length; 964 965 connectEnds(falseEnds, phiValues, oldFalseSuccessor, merge, tool); 966 connectEnds(trueEnds, phiValues, oldTrueSuccessor, merge, tool); 967 968 if (this.trueSuccessorProbability == 0.0) { 969 for (AbstractEndNode endNode : trueEnds) { 970 propagateZeroProbability(endNode); 971 } 972 } 973 974 if (this.trueSuccessorProbability == 1.0) { 975 for (AbstractEndNode endNode : falseEnds) { 976 propagateZeroProbability(endNode); 977 } 978 } 979 980 /* 981 * Remove obsolete ends only after processing all ends, otherwise oldTrueSuccessor or 982 * oldFalseSuccessor might have been removed if it is a LoopExitNode. 983 */ 984 if (falseEnds.isEmpty()) { 985 GraphUtil.killCFG(oldFalseSuccessor); 986 } 987 if (trueEnds.isEmpty()) { 988 GraphUtil.killCFG(oldTrueSuccessor); 989 } 990 991 GraphUtil.killCFG(merge); 992 993 assert !merge.isAlive() : merge; 994 assert !phi.isAlive() : phi; 995 assert !compare.isAlive() : compare; 996 assert !this.isAlive() : this; 997 998 return true; 999 } 1000 1001 private void propagateZeroProbability(FixedNode startNode) { 1002 Node prev = null; 1003 for (FixedNode node : GraphUtil.predecessorIterable(startNode)) { 1004 if (node instanceof IfNode) { 1005 IfNode ifNode = (IfNode) node; 1006 if (ifNode.trueSuccessor() == prev) { 1007 if (ifNode.trueSuccessorProbability == 0.0) { 1008 return; 1009 } else if (ifNode.trueSuccessorProbability == 1.0) { 1010 continue; 1011 } else { 1012 ifNode.setTrueSuccessorProbability(0.0); 1013 return; 1014 } 1015 } else if (ifNode.falseSuccessor() == prev) { 1016 if (ifNode.trueSuccessorProbability == 1.0) { 1017 return; 1018 } else if (ifNode.trueSuccessorProbability == 0.0) { 1019 continue; 1020 } else { 1021 ifNode.setTrueSuccessorProbability(1.0); 1022 return; 1023 } 1024 } else { 1025 throw new JVMCIError("Illegal state"); 1026 } 1027 } else if (node instanceof AbstractMergeNode && !(node instanceof LoopBeginNode)) { 1028 for (AbstractEndNode endNode : ((AbstractMergeNode) node).cfgPredecessors()) { 1029 propagateZeroProbability(endNode); 1030 } 1031 return; 1032 } 1033 prev = node; 1034 } 1035 } 1036 1037 private static boolean checkFrameState(FixedNode start) { 1038 FixedNode node = start; 1039 while (true) { 1040 if (node instanceof AbstractMergeNode) { 1041 AbstractMergeNode mergeNode = (AbstractMergeNode) node; 1042 if (mergeNode.stateAfter() == null) { 1043 return false; 1044 } else { 1045 return true; 1046 } 1047 } else if (node instanceof StateSplit) { 1048 StateSplit stateSplitNode = (StateSplit) node; 1049 if (stateSplitNode.stateAfter() != null) { 1050 return true; 1051 } 1052 } 1053 1054 if (node instanceof ControlSplitNode) { 1055 ControlSplitNode controlSplitNode = (ControlSplitNode) node; 1056 for (Node succ : controlSplitNode.cfgSuccessors()) { 1057 if (checkFrameState((FixedNode) succ)) { 1058 return true; 1059 } 1060 } 1061 return false; 1062 } else if (node instanceof FixedWithNextNode) { 1063 FixedWithNextNode fixedWithNextNode = (FixedWithNextNode) node; 1064 node = fixedWithNextNode.next(); 1065 } else if (node instanceof AbstractEndNode) { 1066 AbstractEndNode endNode = (AbstractEndNode) node; 1067 node = endNode.merge(); 1068 } else if (node instanceof ControlSinkNode) { 1069 return true; 1070 } else { 1071 return false; 1072 } 1073 } 1074 } 1075 1076 /** 1077 * Connects a set of ends to a given successor, inserting a merge node if there is more than one 1078 * end. If {@code ends} is not empty, then {@code successor} is added to {@code tool}'s 1079 * {@linkplain SimplifierTool#addToWorkList(com.oracle.graal.graph.Node) work list}. 1080 * 1081 * @param oldMerge the merge being removed 1082 * @param phiValues the values of the phi at the merge, keyed by the merge ends 1083 */ 1084 private void connectEnds(List<EndNode> ends, Map<AbstractEndNode, ValueNode> phiValues, AbstractBeginNode successor, AbstractMergeNode oldMerge, SimplifierTool tool) { 1085 if (!ends.isEmpty()) { 1086 if (ends.size() == 1) { 1087 AbstractEndNode end = ends.get(0); 1088 ((FixedWithNextNode) end.predecessor()).setNext(successor); 1089 oldMerge.removeEnd(end); 1090 GraphUtil.killCFG(end); 1091 } else { 1092 // Need a new phi in case the frame state is used by more than the merge being 1093 // removed 1094 AbstractMergeNode newMerge = graph().add(new MergeNode()); 1095 PhiNode oldPhi = (PhiNode) oldMerge.usages().first(); 1096 PhiNode newPhi = graph().addWithoutUnique(new ValuePhiNode(oldPhi.stamp(), newMerge)); 1097 1098 for (EndNode end : ends) { 1099 newPhi.addInput(phiValues.get(end)); 1100 newMerge.addForwardEnd(end); 1101 } 1102 1103 FrameState stateAfter = oldMerge.stateAfter(); 1104 if (stateAfter != null) { 1105 stateAfter = stateAfter.duplicate(); 1106 stateAfter.replaceFirstInput(oldPhi, newPhi); 1107 newMerge.setStateAfter(stateAfter); 1108 } 1109 1110 newMerge.setNext(successor); 1111 } 1112 tool.addToWorkList(successor); 1113 } 1114 } 1115 1116 /** 1117 * Gets an array of constants derived from a node that is either a {@link ConstantNode} or a 1118 * {@link PhiNode} whose input values are all constants. The length of the returned array is 1119 * equal to the number of ends terminating in a given merge node. 1120 * 1121 * @return null if {@code node} is neither a {@link ConstantNode} nor a {@link PhiNode} whose 1122 * input values are all constants 1123 */ 1124 public static Constant[] constantValues(ValueNode node, AbstractMergeNode merge, boolean allowNull) { 1125 if (node.isConstant()) { 1126 JavaConstant[] result = new JavaConstant[merge.forwardEndCount()]; 1127 Arrays.fill(result, node.asConstant()); 1128 return result; 1129 } 1130 1131 if (node instanceof PhiNode) { 1132 PhiNode phi = (PhiNode) node; 1133 if (phi.merge() == merge && phi instanceof ValuePhiNode && phi.valueCount() == merge.forwardEndCount()) { 1134 Constant[] result = new Constant[merge.forwardEndCount()]; 1135 int i = 0; 1136 for (ValueNode n : phi.values()) { 1137 if (!allowNull && !n.isConstant()) { 1138 return null; 1139 } 1140 result[i++] = n.asConstant(); 1141 } 1142 return result; 1143 } 1144 } 1145 1146 return null; 1147 } 1148 1149 @Override 1150 public AbstractBeginNode getPrimarySuccessor() { 1151 return this.trueSuccessor(); 1152 } 1153 1154 public AbstractBeginNode getSuccessor(boolean result) { 1155 return result ? this.trueSuccessor() : this.falseSuccessor(); 1156 } 1157}