001/* 002 * This file is part of the Jikes RVM project (http://jikesrvm.org). 003 * 004 * This file is licensed to You under the Eclipse Public License (EPL); 005 * You may not use this file except in compliance with the License. You 006 * may obtain a copy of the License at 007 * 008 * http://www.opensource.org/licenses/eclipse-1.0.php 009 * 010 * See the COPYRIGHT.txt file distributed with this work for information 011 * regarding copyright ownership. 012 */ 013package org.jikesrvm.compilers.opt.ssa; 014 015import static org.jikesrvm.compilers.opt.driver.OptConstants.SSA_SYNTH_BCI; 016import static org.jikesrvm.compilers.opt.ir.Operators.GUARD_MOVE; 017import static org.jikesrvm.compilers.opt.ir.Operators.PHI; 018 019import java.lang.reflect.Constructor; 020import java.util.Enumeration; 021import java.util.HashMap; 022import java.util.HashSet; 023import java.util.Iterator; 024import java.util.LinkedList; 025import java.util.Stack; 026 027import org.jikesrvm.VM; 028import org.jikesrvm.classloader.TypeReference; 029import org.jikesrvm.compilers.opt.DefUse; 030import org.jikesrvm.compilers.opt.OptOptions; 031import org.jikesrvm.compilers.opt.OptimizingCompilerException; 032import org.jikesrvm.compilers.opt.controlflow.BranchOptimizations; 033import org.jikesrvm.compilers.opt.controlflow.DominatorTree; 034import org.jikesrvm.compilers.opt.controlflow.DominatorTreeNode; 035import org.jikesrvm.compilers.opt.controlflow.LTDominators; 036import org.jikesrvm.compilers.opt.driver.CompilerPhase; 037import org.jikesrvm.compilers.opt.ir.BasicBlock; 038import org.jikesrvm.compilers.opt.ir.IR; 039import org.jikesrvm.compilers.opt.ir.IRTools; 040import org.jikesrvm.compilers.opt.ir.Instruction; 041import org.jikesrvm.compilers.opt.ir.Move; 042import org.jikesrvm.compilers.opt.ir.Phi; 043import org.jikesrvm.compilers.opt.ir.Register; 044import org.jikesrvm.compilers.opt.ir.operand.ConstantOperand; 045import org.jikesrvm.compilers.opt.ir.operand.Operand; 046import org.jikesrvm.compilers.opt.ir.operand.RegisterOperand; 047import org.jikesrvm.compilers.opt.ir.operand.TrueGuardOperand; 048import org.jikesrvm.compilers.opt.ir.operand.UnreachableOperand; 049import org.jikesrvm.compilers.opt.liveness.LiveAnalysis; 050import org.jikesrvm.compilers.opt.liveness.LiveSet; 051import org.jikesrvm.compilers.opt.util.TreeNode; 052 053/** 054 * This compiler phase translates out of SSA form. 055 * 056 * @see SSA 057 * @see SSAOptions 058 * @see LTDominators 059 */ 060public class LeaveSSA extends CompilerPhase { 061 062 /** 063 * verbose debugging flag 064 */ 065 static final boolean DEBUG = false; 066 067 /** 068 * The IR to manipulate 069 */ 070 private IR ir; 071 072 private final BranchOptimizations branchOpts = new BranchOptimizations(-1, true, true); 073 074 private boolean splitSomeBlock = false; 075 076 private final HashSet<Instruction> globalRenameTable = new HashSet<Instruction>(); 077 078 private final HashSet<Register> globalRenamePhis = new HashSet<Register>(); 079 080 /** 081 * Is SSA form enabled for the HIR? 082 */ 083 @Override 084 public final boolean shouldPerform(OptOptions options) { 085 return options.SSA; 086 } 087 088 /** 089 * Constructor for this compiler phase 090 */ 091 private static final Constructor<CompilerPhase> constructor = getCompilerPhaseConstructor(LeaveSSA.class); 092 093 /** 094 * Get a constructor object for this compiler phase 095 * @return compiler phase constructor 096 */ 097 @Override 098 public Constructor<CompilerPhase> getClassConstructor() { 099 return constructor; 100 } 101 102 /** 103 * Return a string name for this phase. 104 * @return "Leave SSA" 105 */ 106 @Override 107 public final String getName() { 108 return "Leave SSA"; 109 } 110 111 /** 112 * perform the main out-of-ssa transformation 113 */ 114 @Override 115 public final void perform(IR ir) { 116 this.ir = ir; 117 translateFromSSA(ir); 118 119 // reset ir.SSADictionary 120 ir.HIRInfo.dictionary = null; 121 // reset ssa options 122 ir.actualSSAOptions = null; 123 124 branchOpts.perform(ir, true); 125 126 ir.HIRInfo.dominatorsAreComputed = false; 127 } 128 129 /** 130 * This class provides an abstraction over stacks of names 131 * for registers. 132 */ 133 static final class VariableStacks extends HashMap<Register, Stack<Operand>> { 134 /** Support for map serialization */ 135 static final long serialVersionUID = -5664504465082745314L; 136 137 /** 138 * Get the name at the top of the stack for a particular register 139 * @param s the register in question 140 * @return the name at the top of the stack for the register 141 */ 142 Operand peek(Register s) { 143 Stack<Operand> stack = get(s); 144 if (stack == null || stack.isEmpty()) { 145 return null; 146 } else { 147 return stack.peek(); 148 } 149 } 150 151 /** 152 * Pop the name at the top of the stack for a particular register 153 * @param s the register in question 154 * @return the name at the top of the stack for the register 155 */ 156 Operand pop(Register s) { 157 Stack<Operand> stack = get(s); 158 if (stack == null) { 159 throw new OptimizingCompilerException( 160 "Failure in translating out of SSA form: trying to pop operand from non-existant stack"); 161 } else { 162 return stack.pop(); 163 } 164 } 165 166 /** 167 * Push a name at the top of the stack for a particular register 168 * @param s the register in question 169 * @param name the name to push on the stack 170 */ 171 void push(Register s, Operand name) { 172 Stack<Operand> stack = get(s); 173 if (stack == null) { 174 stack = new Stack<Operand>(); 175 put(s, stack); 176 } 177 stack.push(name); 178 } 179 } 180 181 /** 182 * An instance of this class represents a pending copy instruction 183 * to be inserted. 184 */ 185 static final class Copy { 186 /** 187 * The right-hand side of the copy instruction 188 */ 189 final Operand source; 190 /** 191 * The left-hand side of the copy instruction 192 */ 193 final RegisterOperand destination; 194 /** 195 * The phi instruction which generated this copy instruction 196 */ 197 final Instruction phi; 198 199 /** 200 * Create a pending copy operation for an operand of a phi instruction 201 * @param phi the phi instruction 202 * @param index which operand of the instruction to copy 203 */ 204 Copy(Instruction phi, int index) { 205 this.phi = phi; 206 destination = Phi.getResult(phi).asRegister(); 207 source = Phi.getValue(phi, index); 208 } 209 } 210 211 // substitute variables renamed in control parents 212 private void performRename(BasicBlock bb, DominatorTree dom, VariableStacks s) { 213 if (DEBUG) VM.sysWriteln("performRename: " + bb); 214 215 Enumeration<Instruction> e = bb.forwardRealInstrEnumerator(); 216 while (e.hasMoreElements()) { 217 Instruction i = e.nextElement(); 218 Enumeration<Operand> ee = i.getUses(); 219 while (ee.hasMoreElements()) { 220 Operand o = ee.nextElement(); 221 if (o instanceof RegisterOperand) { 222 Register r1 = ((RegisterOperand) o).getRegister(); 223 if (r1.isValidation()) continue; 224 Operand r2 = s.peek(r1); 225 if (r2 != null) { 226 if (DEBUG) { 227 VM.sysWriteln("replace operand in " + i + "(" + r2 + " for " + o); 228 } 229 i.replaceOperand(o, r2.copy()); 230 } 231 } 232 } 233 } 234 235 // record renamings required in children 236 e = bb.forwardRealInstrEnumerator(); 237 while (e.hasMoreElements()) { 238 Instruction i = e.nextElement(); 239 if (globalRenameTable.contains(i)) { 240 Register original = Move.getVal(i).asRegister().getRegister(); 241 RegisterOperand rename = Move.getResult(i); 242 if (DEBUG) VM.sysWriteln("record rename " + rename + " for " + original); 243 s.push(original, rename); 244 } 245 } 246 247 // insert copies in control children 248 Enumeration<TreeNode> children = dom.getChildren(bb); 249 while (children.hasMoreElements()) { 250 BasicBlock c = ((DominatorTreeNode) children.nextElement()).getBlock(); 251 performRename(c, dom, s); 252 } 253 254 // pop renamings from this block off stack 255 e = bb.forwardRealInstrEnumerator(); 256 while (e.hasMoreElements()) { 257 Instruction i = e.nextElement(); 258 if (globalRenameTable.contains(i)) { 259 Register original = Move.getVal(i).asRegister().getRegister(); 260 s.pop(original); 261 } 262 } 263 } 264 265 private boolean usedBelowCopy(BasicBlock bb, Register r) { 266 Enumeration<Instruction> ie = bb.reverseRealInstrEnumerator(); 267 while (ie.hasMoreElements()) { 268 Instruction inst = ie.nextElement(); 269 if (inst.isBranch()) { 270 Enumeration<Operand> oe = inst.getUses(); 271 while (oe.hasMoreElements()) { 272 Operand op = oe.nextElement(); 273 if (op.isRegister() && op.asRegister().getRegister() == r) { 274 return true; 275 } 276 } 277 } else { 278 break; 279 } 280 } 281 282 return false; 283 } 284 285 /** 286 * Record pending copy operations needed to insert at the end of a basic 287 * block.<p> 288 * 289 * TODO: this procedure is getting long and ugly. Rewrite or refactor 290 * it. 291 * @param bb the basic block to process 292 * @param live valid liveness information for the IR 293 */ 294 private void scheduleCopies(BasicBlock bb, LiveAnalysis live) { 295 296 if (DEBUG) VM.sysWrite("scheduleCopies: " + bb + "\n"); 297 298 // compute out liveness from information in LiveAnalysis 299 LiveSet out = new LiveSet(); 300 for (Enumeration<BasicBlock> outBlocks = bb.getOut(); outBlocks.hasMoreElements();) { 301 BasicBlock ob = outBlocks.nextElement(); 302 LiveAnalysis.BBLiveElement le = live.getLiveInfo(ob); 303 out.add(le.getIn()); 304 } 305 306 // usedByAnother represents the set of registers that appear on the 307 // left-hand side of subsequent phi nodes. This is important, since 308 // we be careful to order copies if the same register appears as the 309 // source and dest of copies in the same basic block. 310 HashSet<Register> usedByAnother = new HashSet<Register>(4); 311 312 // for each basic block successor b of bb, if we make a block on the 313 // critical edge bb->b, then store this critical block. 314 HashMap<BasicBlock, BasicBlock> criticalBlocks = new HashMap<BasicBlock, BasicBlock>(4); 315 316 // For each critical basic block b in which we are inserting copies: return the 317 // mapping of registers to names implied by the copies that have 318 // already been inserted into b. 319 HashMap<BasicBlock, HashMap<Register, Register>> currentNames = 320 new HashMap<BasicBlock, HashMap<Register, Register>>(4); 321 322 // Additionally store the current names for the current basic block bb. 323 HashMap<Register, Register> bbNames = new HashMap<Register, Register>(4); 324 325 // copySet is a linked-list of copies we need to insert in this block. 326 final LinkedList<Copy> copySet = new LinkedList<Copy>(); 327 328 /* Worklist is actually used like a stack - should we make this an Stack ?? */ 329 final LinkedList<Copy> workList = new LinkedList<Copy>(); 330 331 // collect copies required in this block. These copies move 332 // the appropriate rval into the lval of each phi node in 333 // control children of the current block. 334 Enumeration<BasicBlock> e = bb.getOut(); 335 while (e.hasMoreElements()) { 336 BasicBlock bbs = e.nextElement(); 337 if (bbs.isExit()) continue; 338 for (Instruction phi = bbs.firstInstruction(); phi != bbs.lastInstruction(); phi = 339 phi.nextInstructionInCodeOrder()) { 340 if (phi.operator() != PHI) continue; 341 for (int index = 0; index < Phi.getNumberOfPreds(phi); index++) { 342 if (Phi.getPred(phi, index).block != bb) continue; 343 Operand rval = Phi.getValue(phi, index); 344 if (rval.isRegister() && Phi.getResult(phi).asRegister().getRegister() == rval.asRegister().getRegister()) { 345 continue; 346 } 347 Copy c = new Copy(phi, index); 348 copySet.add(0, c); 349 if (c.source instanceof RegisterOperand) { 350 Register r = c.source.asRegister().getRegister(); 351 usedByAnother.add(r); 352 } 353 } 354 } 355 } 356 // the copies that need to be added to this block are processed 357 // in a worklist that ensures that copies are inserted only 358 // after the destination register has been read by any other copy 359 // that needs it. 360 // 361 // initialize work list with all copies whose destination is not 362 // the source for any other copy, and delete such copies from 363 // the set of needed copies. 364 for (Iterator<Copy> copySetIter = copySet.iterator(); copySetIter.hasNext();) { 365 Copy c = copySetIter.next(); 366 if (!usedByAnother.contains(c.destination.getRegister())) { 367 workList.add(0, c); 368 copySetIter.remove(); 369 } 370 } 371 // while there is any more work to do. 372 while (!workList.isEmpty() || !copySet.isEmpty()) { 373 // while there are copies that can be correctly inserted. 374 while (!workList.isEmpty()) { 375 Copy c = workList.remove(0); 376 Register r = c.destination.getRegister(); 377 TypeReference tt = c.destination.getType(); 378 if (VM.VerifyAssertions && tt == null) { 379 tt = TypeReference.Int; 380 VM.sysWrite("SSA, warning: null type in " + c.destination + "\n"); 381 } 382 383 Register rr = null; 384 if (c.source.isRegister()) rr = c.source.asRegister().getRegister(); 385 boolean shouldSplitBlock = 386 !c.phi.getBasicBlock().isExceptionHandlerBasicBlock() && 387 ((ir.options.SSA_SPLITBLOCK_TO_AVOID_RENAME && out.contains(r)) || 388 (rr != null && ir.options.SSA_SPLITBLOCK_FOR_LOCAL_LIVE && usedBelowCopy(bb, rr))); 389 390 if (ir.options.SSA_SPLITBLOCK_INTO_INFREQUENT) { 391 if (!bb.getInfrequent() && 392 c.phi.getBasicBlock().getInfrequent() && 393 !c.phi.getBasicBlock().isExceptionHandlerBasicBlock()) { 394 shouldSplitBlock = true; 395 } 396 } 397 398 // this check captures cases when the result of a phi 399 // in a control successor is live on exit of the current 400 // block. this means it is incorrect to simply insert 401 // a copy of the destination in the current block. so 402 // we rename the destination to a new temporary, and 403 // record the renaming so that dominator blocks get the 404 // new name. 405 if (out.contains(r) && !shouldSplitBlock) { 406 if (!globalRenamePhis.contains(r)) { 407 Register t = ir.regpool.getReg(r); 408 Instruction save = SSA.makeMoveInstruction(ir, t, r, tt); 409 if (DEBUG) { 410 VM.sysWriteln("Inserting " + save + " before " + c.phi + " in " + c.phi.getBasicBlock()); 411 } 412 c.phi.insertAfter(save); 413 globalRenamePhis.add(r); 414 globalRenameTable.add(save); 415 } 416 } 417 Instruction ci = null; 418 419 // insert copy operation required to remove phi 420 if (c.source instanceof ConstantOperand) { 421 if (c.source instanceof UnreachableOperand) { 422 ci = null; 423 } else { 424 ci = SSA.makeMoveInstruction(ir, r, (ConstantOperand) c.source); 425 } 426 } else if (c.source instanceof RegisterOperand) { 427 if (shouldSplitBlock) { 428 if (DEBUG) VM.sysWriteln("splitting edge: " + bb + "->" + c.phi.getBasicBlock()); 429 BasicBlock criticalBlock = criticalBlocks.get(c.phi.getBasicBlock()); 430 if (criticalBlock == null) { 431 criticalBlock = IRTools.makeBlockOnEdge(bb, c.phi.getBasicBlock(), ir); 432 if (c.phi.getBasicBlock().getInfrequent()) { 433 criticalBlock.setInfrequent(); 434 } 435 splitSomeBlock = true; 436 criticalBlocks.put(c.phi.getBasicBlock(), criticalBlock); 437 HashMap<Register, Register> newNames = new HashMap<Register, Register>(4); 438 currentNames.put(criticalBlock, newNames); 439 } 440 Register sr = c.source.asRegister().getRegister(); 441 HashMap<Register, Register> criticalBlockNames = currentNames.get(criticalBlock); 442 Register nameForSR = criticalBlockNames.get(sr); 443 if (nameForSR == null) { 444 nameForSR = bbNames.get(sr); 445 if (nameForSR == null) nameForSR = sr; 446 } 447 if (DEBUG) VM.sysWriteln("dest(r): " + r); 448 if (DEBUG) VM.sysWriteln("sr: " + sr + ", nameForSR: " + nameForSR); 449 ci = SSA.makeMoveInstruction(ir, r, nameForSR, tt); 450 criticalBlockNames.put(sr, r); 451 criticalBlock.appendInstructionRespectingTerminalBranch(ci); 452 } else { 453 Register sr = c.source.asRegister().getRegister(); 454 Register nameForSR = bbNames.get(sr); 455 if (nameForSR == null) nameForSR = sr; 456 if (DEBUG) VM.sysWriteln("not splitting edge: " + bb + "->" + c.phi.getBasicBlock()); 457 if (DEBUG) VM.sysWriteln("dest(r): " + r); 458 if (DEBUG) VM.sysWriteln("sr: " + sr + ", nameForSR: " + nameForSR); 459 ci = SSA.makeMoveInstruction(ir, r, nameForSR, tt); 460 bbNames.put(sr, r); 461 SSA.addAtEnd(ir, bb, ci, c.phi.getBasicBlock().isExceptionHandlerBasicBlock()); 462 } 463 // ugly hack: having already added ci; set ci to null to skip remaining code; 464 ci = null; 465 } else { 466 throw new OptimizingCompilerException("Unexpected phi operand " + 467 c 468 .source + 469 " encountered during SSA teardown", true); 470 } 471 if (ci != null) { 472 if (shouldSplitBlock) { 473 if (DEBUG) VM.sysWriteln("splitting edge: " + bb + "->" + c.phi.getBasicBlock()); 474 BasicBlock criticalBlock = criticalBlocks.get(c.phi.getBasicBlock()); 475 if (criticalBlock == null) { 476 criticalBlock = IRTools.makeBlockOnEdge(bb, c.phi.getBasicBlock(), ir); 477 if (c.phi.getBasicBlock().getInfrequent()) { 478 criticalBlock.setInfrequent(); 479 } 480 splitSomeBlock = true; 481 criticalBlocks.put(c.phi.getBasicBlock(), criticalBlock); 482 HashMap<Register, Register> newNames = new HashMap<Register, Register>(4); 483 currentNames.put(criticalBlock, newNames); 484 } 485 criticalBlock.appendInstructionRespectingTerminalBranch(ci); 486 } else { 487 SSA.addAtEnd(ir, bb, ci, c.phi.getBasicBlock().isExceptionHandlerBasicBlock()); 488 } 489 } 490 491 // source has been copied and so can now be overwritten 492 // safely. so now add any copies _to_ the source of the 493 // current copy to the work list. 494 if (c.source instanceof RegisterOperand) { 495 Register saved = c.source.asRegister().getRegister(); 496 Iterator<Copy> copySetIter = copySet.iterator(); 497 while (copySetIter.hasNext()) { 498 Copy cc = copySetIter.next(); 499 if (cc.destination.asRegister().getRegister() == saved) { 500 workList.add(0, cc); 501 copySetIter.remove(); 502 } 503 } 504 } 505 } 506 // an empty work list with work remaining in the copy set 507 // implies a cycle in the dependencies amongst copies. deal 508 // with this: break the cycle by copying the destination 509 // of an arbitrary member of the copy set into a temporary. 510 // this destination has thus been saved, and can now be 511 // safely overwritten. so, add that copy to the work list. 512 if (!copySet.isEmpty()) { 513 Copy c = copySet.remove(0); 514 Register tt = ir.regpool.getReg(c.destination.getRegister()); 515 SSA.addAtEnd(ir, 516 bb, 517 SSA.makeMoveInstruction(ir, tt, c.destination.getRegister(), c.destination.getType()), 518 c.phi.getBasicBlock().isExceptionHandlerBasicBlock()); 519 bbNames.put(c.destination.getRegister(), tt); 520 workList.add(0, c); 521 } 522 } 523 } 524 525 /** 526 * Insert copy instructions into a basic block to safely translate out 527 * of SSA form. 528 * 529 * @param bb the basic block 530 * @param dom a valid dominator tree for the IR 531 * @param live valid liveness information for the IR 532 */ 533 private void insertCopies(BasicBlock bb, DominatorTree dom, LiveAnalysis live) { 534 // add copies required in this block to remove phis. 535 // (record renaming required by simultaneous liveness in global tables) 536 scheduleCopies(bb, live); 537 538 // insert copies in control children 539 Enumeration<TreeNode> children = dom.getChildren(bb); 540 while (children.hasMoreElements()) { 541 BasicBlock c = ((DominatorTreeNode) children.nextElement()).getBlock(); 542 insertCopies(c, dom, live); 543 } 544 } 545 546 /** 547 * Main driver to translate an IR out of SSA form. 548 * 549 * @param ir the IR in SSA form 550 */ 551 public void translateFromSSA(IR ir) { 552 // 0. Deal with guards (validation registers) 553 unSSAGuards(ir); 554 555 // 1. re-compute dominator tree in case of control flow changes 556 LTDominators.perform(ir, true, true); 557 DominatorTree dom = new DominatorTree(ir, true); 558 559 // 1.5 Perform Sreedhar's naive translation from TSSA to CSSA 560 //if (ir.options.UNROLL_LOG == 0) normalizeSSA(ir); 561 562 // 2. compute liveness 563 LiveAnalysis live = new LiveAnalysis(false, // don't create GC maps 564 true, // skip (final) local propagation step 565 // of live analysis 566 false, // don't store information at handlers 567 false); // don't skip guards 568 569 live.perform(ir); 570 // 3. initialization 571 VariableStacks s = new VariableStacks(); 572 // 4. convert phi nodes into copies 573 BasicBlock b = ((DominatorTreeNode) dom.getRoot()).getBlock(); 574 insertCopies(b, dom, live); 575 // 5. If necessary, recompute dominators to account for new control flow. 576 if (splitSomeBlock) { 577 LTDominators.perform(ir, true, true); 578 dom = new DominatorTree(ir, true); 579 } 580 // 6. compensate for copies required by simultaneous liveness 581 performRename(b, dom, s); 582 // 7. phis are now redundant 583 removeAllPhis(ir); 584 } 585 586 /** 587 * Remove all phi instructions from the IR. 588 * 589 * @param ir the governing IR 590 */ 591 static void removeAllPhis(IR ir) { 592 for (Instruction s = ir.firstInstructionInCodeOrder(), 593 sentinel = ir.lastInstructionInCodeOrder(), 594 nextInstr = null; s != sentinel; s = nextInstr) { 595 // cache because remove nulls next/prev fields 596 nextInstr = s.nextInstructionInCodeOrder(); 597 if (Phi.conforms(s)) s.remove(); 598 } 599 } 600 601 /** 602 * Special treatment for guard registers: 603 * Remove guard-phis by evaluating operands into same register. 604 * If this target register is not unique, unite the alternatives. 605 * 606 * @param ir the governing IR, currently in SSA form 607 */ 608 private void unSSAGuards(IR ir) { 609 // 0. initialization 610 unSSAGuardsInit(ir); 611 // 1. Determine target registers 612 unSSAGuardsDetermineReg(ir); 613 // 2. Rename targets and remove Phis 614 unSSAGuardsFinalize(ir); 615 } 616 617 Instruction guardPhis = null; 618 619 private HashMap<Instruction, Instruction> inst2guardPhi; 620 private HashMap<Register, Integer> guardRegUnion; 621 private HashMap<Register, Register> associatedRegisters; 622 623 /** 624 * Initialization for removal of guard phis. 625 * 626 * @param ir the governing IR, currently in SSA form 627 */ 628 private void unSSAGuardsInit(IR ir) { 629 guardPhis = null; 630 Enumeration<Instruction> e = ir.forwardInstrEnumerator(); 631 632 // visit all instructions, looking for guard phis 633 634 inst2guardPhi = new HashMap<Instruction, Instruction>(); 635 636 while (e.hasMoreElements()) { 637 Instruction inst = e.nextElement(); 638 if (!Phi.conforms(inst)) continue; 639 Operand res = Phi.getResult(inst); 640 if (!(res instanceof RegisterOperand)) continue; 641 Register r = res.asRegister().getRegister(); 642 if (!r.isValidation()) continue; 643 644 // force all operands of Phis into registers. 645 inst2guardPhi.put(inst, guardPhis); 646 guardPhis = inst; 647 648 int values = Phi.getNumberOfValues(inst); 649 for (int i = 0; i < values; ++i) { 650 Operand op = Phi.getValue(inst, i); 651 if (!(op instanceof RegisterOperand)) { 652 if (op instanceof TrueGuardOperand) { 653 BasicBlock bb = Phi.getPred(inst, i).block; 654 Instruction move = Move.create(GUARD_MOVE, res.asRegister().copyD2D(), new TrueGuardOperand()); 655 move.position = ir.gc.getInlineSequence(); 656 move.bcIndex = SSA_SYNTH_BCI; 657 bb.appendInstructionRespectingTerminalBranchOrPEI(move); 658 } else if (op instanceof UnreachableOperand) { 659 // do nothing 660 } else { 661 if (VM.VerifyAssertions) VM._assert(VM.NOT_REACHED); 662 } 663 } 664 } 665 } 666 667 guardRegUnion = new HashMap<Register, Integer>(); 668 associatedRegisters = new HashMap<Register, Register>(); 669 // visit all guard registers, init union/find 670 for (Register r = ir.regpool.getFirstSymbolicRegister(); r != null; r = r.getNext()) { 671 if (!r.isValidation()) continue; 672 guardRegUnion.put(r, Integer.valueOf(1)); 673 associatedRegisters.put(r, r); 674 } 675 } 676 677 /** 678 * Determine target register for guard phi operands 679 * 680 * @param ir the governing IR, currently in SSA form 681 */ 682 private void unSSAGuardsDetermineReg(IR ir) { 683 Instruction inst = guardPhis; 684 while (inst != null) { 685 Register r = Phi.getResult(inst).asRegister().getRegister(); 686 int values = Phi.getNumberOfValues(inst); 687 for (int i = 0; i < values; ++i) { 688 Operand op = Phi.getValue(inst, i); 689 if (op instanceof RegisterOperand) { 690 guardUnion(op.asRegister().getRegister(), r); 691 } else { 692 if (VM.VerifyAssertions) { 693 VM._assert(op instanceof TrueGuardOperand || op instanceof UnreachableOperand); 694 } 695 } 696 } 697 inst = inst2guardPhi.get(inst); 698 } 699 } 700 701 /** 702 * Rename registers and delete Phis. 703 * 704 * @param ir the governing IR, currently in SSA form 705 */ 706 private void unSSAGuardsFinalize(IR ir) { 707 DefUse.computeDU(ir); 708 for (Register r = ir.regpool.getFirstSymbolicRegister(); r != null; r = r.getNext()) { 709 if (!r.isValidation()) continue; 710 Register nreg = guardFind(r); 711 Enumeration<RegisterOperand> uses = DefUse.uses(r); 712 while (uses.hasMoreElements()) { 713 RegisterOperand use = uses.nextElement(); 714 use.setRegister(nreg); 715 } 716 Enumeration<RegisterOperand> defs = DefUse.defs(r); 717 while (defs.hasMoreElements()) { 718 RegisterOperand def = defs.nextElement(); 719 def.setRegister(nreg); 720 } 721 } 722 Instruction inst = guardPhis; 723 while (inst != null) { 724 inst.remove(); 725 inst = inst2guardPhi.get(inst); 726 } 727 } 728 729 private Register guardUnion(Register from, Register to) { 730 Register a = guardFind(from); 731 Register b = guardFind(to); 732 if (a == b) return a; 733 int aUnion = guardRegUnion.get(a); 734 int bUnion = guardRegUnion.get(b); 735 if (aUnion == bUnion) { 736 guardRegUnion.put(a, Integer.valueOf(aUnion + 1)); 737 associatedRegisters.put(b, a); 738 return a; 739 } 740 if (aUnion > bUnion) { 741 associatedRegisters.put(b, a); 742 return a; 743 } 744 associatedRegisters.put(a, b); 745 return b; 746 } 747 748 private Register guardFind(Register r) { 749 Register start = r; 750 if (VM.VerifyAssertions) VM._assert(associatedRegisters.get(r) != null); 751 while (associatedRegisters.get(r) != r) r = associatedRegisters.get(r); 752 while (associatedRegisters.get(start) != r) { 753 associatedRegisters.put(start, r); 754 start = associatedRegisters.get(start); 755 } 756 return r; 757 } 758 759 /** 760 * Avoid potential lost copy and other associated problems by 761 * Sreedhar's naive translation from TSSA to CSSA. Guards are rather 762 * trivial to un-SSA so they have already been removed from the IR. 763 * This algorithm is very wasteful of registers so needs good 764 * coalescing. 765 * @param ir the IR to work upon 766 */ 767 @SuppressWarnings("unused") // NB this was an aborted attempt to fix a bug in leave SSA 768 private static void normalizeSSA(IR ir) { 769 for (Instruction s = ir.firstInstructionInCodeOrder(), 770 sentinel = ir.lastInstructionInCodeOrder(), 771 nextInstr = null; s != sentinel; s = nextInstr) { 772 // cache so we don't process inserted instructions 773 nextInstr = s.nextInstructionInCodeOrder(); 774 if (Phi.conforms(s) && !s.getBasicBlock().isExceptionHandlerBasicBlock()) { 775 // We ignore exception handler BBs as they cause problems when inserting copies 776 if (DEBUG) VM.sysWriteln("Processing " + s + " of basic block " + s.getBasicBlock()); 777 // Does the phi instruction have an unreachable operand? 778 boolean hasUnreachable = false; 779 // 1. Naively copy source operands into predecessor blocks 780 for (int index = 0; index < Phi.getNumberOfPreds(s); index++) { 781 Operand op = Phi.getValue(s, index); 782 if (op.isRegister()) { 783 // Get rval 784 Register rval = op.asRegister().getRegister(); 785 if (rval.isValidation()) { 786 continue; // ignore guards 787 } else { 788 // Make rval' 789 Register rvalPrime = ir.regpool.getReg(rval); 790 // Make copy instruction 791 Instruction copy = SSA.makeMoveInstruction(ir, rvalPrime, rval, op.getType()); 792 // Insert a copy of rval to rval' in predBlock 793 BasicBlock pred = Phi.getPred(s, index).block; 794 pred.appendInstructionRespectingTerminalBranch(copy); 795 if (DEBUG) VM.sysWriteln("Inserted rval copy of " + copy + " into basic block " + pred); 796 // Rename rval to rval' in phi instruction 797 op.asRegister().setRegister(rvalPrime); 798 } 799 } else if (op instanceof UnreachableOperand) { 800 hasUnreachable = true; 801 } 802 } 803 // 2. Naively copy the result if there were no unreachable operands 804 if (!hasUnreachable) { 805 Operand op = Phi.getResult(s); 806 if (!op.isRegister()) { 807 // ignore heap operands 808 } else { 809 // Get lval 810 Register lval = op.asRegister().getRegister(); 811 // Make lval' 812 Register lvalPrime = ir.regpool.getReg(lval); 813 // Make copy instruction 814 Instruction copy = SSA.makeMoveInstruction(ir, lval, lvalPrime, op.getType()); 815 // Insert a copy of lval' to lval after phi instruction 816 s.insertAfter(copy); 817 // Rename lval to lval' in phi instruction 818 op.asRegister().setRegister(lvalPrime); 819 if (DEBUG) VM.sysWriteln("Inserted lval copy of " + copy + " after " + s); 820 } 821 } 822 } 823 } 824 } 825}