1 /* 2 * Copyright (C) 2007 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.dx.ssa.back; 18 19 import com.android.dx.rop.code.*; 20 import com.android.dx.rop.cst.CstInteger; 21 import com.android.dx.ssa.InterferenceRegisterMapper; 22 import com.android.dx.ssa.RegisterMapper; 23 import com.android.dx.ssa.SsaInsn; 24 import com.android.dx.ssa.SsaMethod; 25 import com.android.dx.ssa.NormalSsaInsn; 26 import com.android.dx.ssa.PhiInsn; 27 import com.android.dx.ssa.Optimizer; 28 import com.android.dx.ssa.SsaBasicBlock; 29 import com.android.dx.util.IntSet; 30 import com.android.dx.util.IntIterator; 31 32 import java.util.ArrayList; 33 import java.util.BitSet; 34 import java.util.Map; 35 import java.util.TreeMap; 36 37 /** 38 * Allocates registers in a first-fit fashion, with the bottom reserved for 39 * method parameters and all SSAregisters representing the same local variable 40 * kept together if possible. 41 */ 42 public class FirstFitLocalCombiningAllocator extends RegisterAllocator { 43 /** local debug flag */ 44 private static final boolean DEBUG = false; 45 46 /** maps local variable to a list of associated SSA registers */ 47 private final Map<LocalItem, ArrayList<RegisterSpec>> localVariables; 48 49 /** list of move-result-pesudo instructions seen in this method */ 50 private final ArrayList<NormalSsaInsn> moveResultPseudoInsns; 51 52 /** list of invoke-range instructions seen in this method */ 53 private final ArrayList<NormalSsaInsn> invokeRangeInsns; 54 55 /** list of phi instructions seen in this method */ 56 private final ArrayList<PhiInsn> phiInsns; 57 58 /** indexed by SSA reg; the set of SSA regs we've mapped */ 59 private final BitSet ssaRegsMapped; 60 61 /** Register mapper which will be our result */ 62 private final InterferenceRegisterMapper mapper; 63 64 /** end of rop registers range (starting at 0) reserved for parameters */ 65 private final int paramRangeEnd; 66 67 /** set of rop registers reserved for parameters or local variables */ 68 private final BitSet reservedRopRegs; 69 70 /** set of rop registers that have been used by anything */ 71 private final BitSet usedRopRegs; 72 73 /** true if converter should take steps to minimize rop-form registers */ 74 private final boolean minimizeRegisters; 75 76 /** 77 * Constructs instance. 78 * 79 * @param ssaMeth {@code non-null;} method to process 80 * @param interference non-null interference graph for SSA registers 81 * @param minimizeRegisters true if converter should take steps to 82 * minimize rop-form registers 83 */ 84 public FirstFitLocalCombiningAllocator( 85 SsaMethod ssaMeth, InterferenceGraph interference, 86 boolean minimizeRegisters) { 87 super(ssaMeth, interference); 88 89 ssaRegsMapped = new BitSet(ssaMeth.getRegCount()); 90 91 mapper = new InterferenceRegisterMapper( 92 interference, ssaMeth.getRegCount()); 93 94 this.minimizeRegisters = minimizeRegisters; 95 96 /* 97 * Reserve space for the params at the bottom of the register 98 * space. Later, we'll flip the params to the end of the register 99 * space. 100 */ 101 102 paramRangeEnd = ssaMeth.getParamWidth(); 103 104 reservedRopRegs = new BitSet(paramRangeEnd * 2); 105 reservedRopRegs.set(0, paramRangeEnd); 106 usedRopRegs = new BitSet(paramRangeEnd * 2); 107 localVariables = new TreeMap<LocalItem, ArrayList<RegisterSpec>>(); 108 moveResultPseudoInsns = new ArrayList<NormalSsaInsn>(); 109 invokeRangeInsns = new ArrayList<NormalSsaInsn>(); 110 phiInsns = new ArrayList<PhiInsn>(); 111 } 112 113 /** {@inheritDoc} */ 114 @Override 115 public boolean wantsParamsMovedHigh() { 116 return true; 117 } 118 119 /** {@inheritDoc} */ 120 @Override 121 public RegisterMapper allocateRegisters() { 122 123 analyzeInstructions(); 124 125 if (DEBUG) { 126 printLocalVars(); 127 } 128 129 if (DEBUG) System.out.println("--->Mapping local-associated params"); 130 handleLocalAssociatedParams(); 131 132 if (DEBUG) System.out.println("--->Mapping other params"); 133 handleUnassociatedParameters(); 134 135 if (DEBUG) System.out.println("--->Mapping invoke-range"); 136 handleInvokeRangeInsns(); 137 138 if (DEBUG) { 139 System.out.println("--->Mapping local-associated non-params"); 140 } 141 handleLocalAssociatedOther(); 142 143 if (DEBUG) System.out.println("--->Mapping check-cast results"); 144 handleCheckCastResults(); 145 146 if (DEBUG) System.out.println("--->Mapping phis"); 147 handlePhiInsns(); 148 149 if (DEBUG) System.out.println("--->Mapping others"); 150 handleNormalUnassociated(); 151 152 return mapper; 153 } 154 155 /** 156 * Dumps local variable table to stdout for debugging. 157 */ 158 private void printLocalVars() { 159 System.out.println("Printing local vars"); 160 for (Map.Entry<LocalItem, ArrayList<RegisterSpec>> e : 161 localVariables.entrySet()) { 162 StringBuilder regs = new StringBuilder(); 163 164 regs.append('{'); 165 regs.append(' '); 166 for (RegisterSpec reg : e.getValue()) { 167 regs.append('v'); 168 regs.append(reg.getReg()); 169 regs.append(' '); 170 } 171 regs.append('}'); 172 System.out.printf("Local: %s Registers: %s\n", e.getKey(), regs); 173 } 174 } 175 176 /** 177 * Maps all local-associated parameters to rop registers. 178 */ 179 private void handleLocalAssociatedParams() { 180 for (ArrayList<RegisterSpec> ssaRegs : localVariables.values()) { 181 int sz = ssaRegs.size(); 182 int paramIndex = -1; 183 int paramCategory = 0; 184 185 // First, find out if this local variable is a parameter. 186 for (int i = 0; i < sz; i++) { 187 RegisterSpec ssaSpec = ssaRegs.get(i); 188 int ssaReg = ssaSpec.getReg(); 189 190 paramIndex = getParameterIndexForReg(ssaReg); 191 192 if (paramIndex >= 0) { 193 paramCategory = ssaSpec.getCategory(); 194 addMapping(ssaSpec, paramIndex); 195 break; 196 } 197 } 198 199 if (paramIndex < 0) { 200 // This local wasn't a parameter. 201 continue; 202 } 203 204 // Any remaining local-associated registers will be mapped later. 205 tryMapRegs(ssaRegs, paramIndex, paramCategory, true); 206 } 207 } 208 209 /** 210 * Gets the parameter index for SSA registers that are method parameters. 211 * {@code -1} is returned for non-parameter registers. 212 * 213 * @param ssaReg {@code >=0;} SSA register to look up 214 * @return parameter index or {@code -1} if not a parameter 215 */ 216 private int getParameterIndexForReg(int ssaReg) { 217 SsaInsn defInsn = ssaMeth.getDefinitionForRegister(ssaReg); 218 if (defInsn == null) { 219 return -1; 220 } 221 222 Rop opcode = defInsn.getOpcode(); 223 224 // opcode == null for phi insns. 225 if (opcode != null && opcode.getOpcode() == RegOps.MOVE_PARAM) { 226 CstInsn origInsn = (CstInsn) defInsn.getOriginalRopInsn(); 227 return ((CstInteger) origInsn.getConstant()).getValue(); 228 } 229 230 return -1; 231 } 232 233 /** 234 * Maps all local-associated registers that are not parameters. 235 * Tries to find an unreserved range that's wide enough for all of 236 * the SSA registers, and then tries to map them all to that 237 * range. If not all fit, a new range is tried until all registers 238 * have been fit. 239 */ 240 private void handleLocalAssociatedOther() { 241 for (ArrayList<RegisterSpec> specs : localVariables.values()) { 242 int ropReg = paramRangeEnd; 243 244 boolean done = false; 245 do { 246 int maxCategory = 1; 247 248 // Compute max category for remaining unmapped registers. 249 int sz = specs.size(); 250 for (int i = 0; i < sz; i++) { 251 RegisterSpec ssaSpec = specs.get(i); 252 int category = ssaSpec.getCategory(); 253 if (!ssaRegsMapped.get(ssaSpec.getReg()) 254 && category > maxCategory) { 255 maxCategory = category; 256 } 257 } 258 259 ropReg = findRopRegForLocal(ropReg, maxCategory); 260 if (canMapRegs(specs, ropReg)) { 261 done = tryMapRegs(specs, ropReg, maxCategory, true); 262 } 263 264 // Increment for next call to findRopRegForLocal. 265 ropReg++; 266 } while (!done); 267 } 268 } 269 270 /** 271 * Tries to map a list of SSA registers into the a rop reg, marking 272 * used rop space as reserved. SSA registers that don't fit are left 273 * unmapped. 274 * 275 * @param specs {@code non-null;} SSA registers to attempt to map 276 * @param ropReg {@code >=0;} rop register to map to 277 * @param maxAllowedCategory {@code 1..2;} maximum category 278 * allowed in mapping. 279 * @param markReserved do so if {@code true} 280 * @return {@code true} if all registers were mapped, {@code false} 281 * if some remain unmapped 282 */ 283 private boolean tryMapRegs( 284 ArrayList<RegisterSpec> specs, int ropReg, 285 int maxAllowedCategory, boolean markReserved) { 286 boolean remaining = false; 287 for (RegisterSpec spec : specs) { 288 if (ssaRegsMapped.get(spec.getReg())) { 289 continue; 290 } 291 292 boolean succeeded; 293 succeeded = tryMapReg(spec, ropReg, maxAllowedCategory); 294 remaining = !succeeded || remaining; 295 if (succeeded && markReserved) { 296 // This only needs to be called once really with 297 // the widest category used, but <shrug> 298 markReserved(ropReg, spec.getCategory()); 299 } 300 } 301 return !remaining; 302 } 303 304 /** 305 * Tries to map an SSA register to a rop register. 306 * 307 * @param ssaSpec {@code non-null;} SSA register 308 * @param ropReg {@code >=0;} rop register 309 * @param maxAllowedCategory {@code 1..2;} the maximum category 310 * that the SSA register is allowed to be 311 * @return {@code true} if map succeeded, {@code false} if not 312 */ 313 private boolean tryMapReg(RegisterSpec ssaSpec, int ropReg, 314 int maxAllowedCategory) { 315 if (ssaSpec.getCategory() <= maxAllowedCategory 316 && !ssaRegsMapped.get(ssaSpec.getReg()) 317 && canMapReg(ssaSpec, ropReg)) { 318 addMapping(ssaSpec, ropReg); 319 return true; 320 } 321 322 return false; 323 } 324 325 /** 326 * Marks a range of rop registers as "reserved for a local variable." 327 * 328 * @param ropReg {@code >= 0;} rop register to reserve 329 * @param category {@code > 0;} width to reserve 330 */ 331 private void markReserved(int ropReg, int category) { 332 reservedRopRegs.set(ropReg, ropReg + category, true); 333 } 334 335 /** 336 * Checks to see if any rop registers in the specified range are reserved 337 * for local variables or parameters. 338 * 339 * @param ropRangeStart {@code >= 0;} lowest rop register 340 * @param width {@code > 0;} number of rop registers in range. 341 * @return {@code true} if any register in range is marked reserved 342 */ 343 private boolean rangeContainsReserved(int ropRangeStart, int width) { 344 for (int i = ropRangeStart; i < (ropRangeStart + width); i++) { 345 if (reservedRopRegs.get(i)) { 346 return true; 347 } 348 } 349 return false; 350 } 351 352 /** 353 * Returns true if given rop register represents the {@code this} pointer 354 * for a non-static method. 355 * 356 * @param startReg rop register 357 * @return true if the "this" pointer is located here. 358 */ 359 private boolean isThisPointerReg(int startReg) { 360 // "this" is always the first parameter. 361 return startReg == 0 && !ssaMeth.isStatic(); 362 } 363 364 /** 365 * Finds a range of unreserved rop registers. 366 * 367 * @param startReg {@code >= 0;} a rop register to start the search at 368 * @param width {@code > 0;} the width, in registers, required. 369 * @return {@code >= 0;} start of available register range. 370 */ 371 private int findNextUnreservedRopReg(int startReg, int width) { 372 int reg; 373 374 reg = reservedRopRegs.nextClearBit(startReg); 375 376 while (true) { 377 int i = 1; 378 379 while (i < width && !reservedRopRegs.get(reg + i)) { 380 i++; 381 } 382 383 if (i == width) { 384 return reg; 385 } 386 387 reg = reservedRopRegs.nextClearBit(reg + i); 388 } 389 } 390 391 /** 392 * Finds a range of rop regs that can be used for local variables. 393 * If {@code MIX_LOCALS_AND_OTHER} is {@code false}, this means any 394 * rop register that has not yet been used. 395 * 396 * @param startReg {@code >= 0;} a rop register to start the search at 397 * @param width {@code > 0;} the width, in registers, required. 398 * @return {@code >= 0;} start of available register range. 399 */ 400 private int findRopRegForLocal(int startReg, int width) { 401 int reg; 402 403 reg = usedRopRegs.nextClearBit(startReg); 404 405 while (true) { 406 int i = 1; 407 408 while (i < width && !usedRopRegs.get(reg + i)) { 409 i++; 410 } 411 412 if (i == width) { 413 return reg; 414 } 415 416 reg = usedRopRegs.nextClearBit(reg + i); 417 } 418 } 419 420 /** 421 * Maps any parameter that isn't local-associated, which can happen 422 * in the case where there is no java debug info. 423 */ 424 private void handleUnassociatedParameters() { 425 int szSsaRegs = ssaMeth.getRegCount(); 426 427 for (int ssaReg = 0; ssaReg < szSsaRegs; ssaReg++) { 428 if (ssaRegsMapped.get(ssaReg)) { 429 // We already did this one above 430 continue; 431 } 432 433 int paramIndex = getParameterIndexForReg(ssaReg); 434 435 RegisterSpec ssaSpec = getDefinitionSpecForSsaReg(ssaReg); 436 if (paramIndex >= 0) { 437 addMapping(ssaSpec, paramIndex); 438 } 439 } 440 } 441 442 /** 443 * Handles all insns that want a register range for their sources. 444 */ 445 private void handleInvokeRangeInsns() { 446 for (NormalSsaInsn insn : invokeRangeInsns) { 447 adjustAndMapSourceRangeRange(insn); 448 } 449 } 450 451 /** 452 * Handles check cast results to reuse the same source register. 453 * Inserts a move if it can't map the same register to both and the 454 * check cast is not caught. 455 */ 456 private void handleCheckCastResults() { 457 for (NormalSsaInsn insn : moveResultPseudoInsns) { 458 RegisterSpec moveRegSpec = insn.getResult(); 459 int moveReg = moveRegSpec.getReg(); 460 BitSet predBlocks = insn.getBlock().getPredecessors(); 461 462 // Expect one predecessor block only 463 if (predBlocks.cardinality() != 1) { 464 continue; 465 } 466 467 SsaBasicBlock predBlock = 468 ssaMeth.getBlocks().get(predBlocks.nextSetBit(0)); 469 ArrayList<SsaInsn> insnList = predBlock.getInsns(); 470 471 /** 472 * If the predecessor block has a check-cast, it will be the last 473 * instruction 474 */ 475 SsaInsn checkCastInsn = insnList.get(insnList.size() - 1); 476 if (checkCastInsn.getOpcode().getOpcode() != RegOps.CHECK_CAST) { 477 continue; 478 } 479 480 RegisterSpec checkRegSpec = checkCastInsn.getSources().get(0); 481 int checkReg = checkRegSpec.getReg(); 482 483 /** 484 * See if either register is already mapped. Most likely the move 485 * result will be mapped already since the cast result is stored 486 * in a local variable. 487 */ 488 int category = checkRegSpec.getCategory(); 489 boolean moveMapped = ssaRegsMapped.get(moveReg); 490 boolean checkMapped = ssaRegsMapped.get(checkReg); 491 if (moveMapped & !checkMapped) { 492 int moveRopReg = mapper.oldToNew(moveReg); 493 checkMapped = tryMapReg(checkRegSpec, moveRopReg, category); 494 } 495 if (checkMapped & !moveMapped) { 496 int checkRopReg = mapper.oldToNew(checkReg); 497 moveMapped = tryMapReg(moveRegSpec, checkRopReg, category); 498 } 499 500 // Map any unmapped registers to anything available 501 if (!moveMapped || !checkMapped) { 502 int ropReg = findNextUnreservedRopReg(paramRangeEnd, category); 503 ArrayList<RegisterSpec> ssaRegs = 504 new ArrayList<RegisterSpec>(2); 505 ssaRegs.add(moveRegSpec); 506 ssaRegs.add(checkRegSpec); 507 508 while (!tryMapRegs(ssaRegs, ropReg, category, false)) { 509 ropReg = findNextUnreservedRopReg(ropReg + 1, category); 510 } 511 } 512 513 /* 514 * If source and result have a different mapping, insert a move so 515 * they can have the same mapping. Don't do this if the check cast 516 * is caught, since it will overwrite a potentially live value. 517 */ 518 boolean hasExceptionHandlers = 519 checkCastInsn.getOriginalRopInsn().getCatches().size() != 0; 520 int moveRopReg = mapper.oldToNew(moveReg); 521 int checkRopReg = mapper.oldToNew(checkReg); 522 if (moveRopReg != checkRopReg && !hasExceptionHandlers) { 523 ((NormalSsaInsn) checkCastInsn).changeOneSource(0, 524 insertMoveBefore(checkCastInsn, checkRegSpec)); 525 addMapping(checkCastInsn.getSources().get(0), moveRopReg); 526 } 527 } 528 } 529 530 /** 531 * Handles all phi instructions, trying to map them to a common register. 532 */ 533 private void handlePhiInsns() { 534 for (PhiInsn insn : phiInsns) { 535 processPhiInsn(insn); 536 } 537 } 538 539 /** 540 * Maps all non-parameter, non-local variable registers. 541 */ 542 private void handleNormalUnassociated() { 543 int szSsaRegs = ssaMeth.getRegCount(); 544 545 for (int ssaReg = 0; ssaReg < szSsaRegs; ssaReg++) { 546 if (ssaRegsMapped.get(ssaReg)) { 547 // We already did this one 548 continue; 549 } 550 551 RegisterSpec ssaSpec = getDefinitionSpecForSsaReg(ssaReg); 552 553 if (ssaSpec == null) continue; 554 555 int category = ssaSpec.getCategory(); 556 // Find a rop reg that does not interfere 557 int ropReg = findNextUnreservedRopReg(paramRangeEnd, category); 558 while (!canMapReg(ssaSpec, ropReg)) { 559 ropReg = findNextUnreservedRopReg(ropReg + 1, category); 560 } 561 562 addMapping(ssaSpec, ropReg); 563 } 564 } 565 566 /** 567 * Checks to see if a list of SSA registers can all be mapped into 568 * the same rop reg. Ignores registers that have already been mapped, 569 * and checks the interference graph and ensures the range does not 570 * cross the parameter range. 571 * 572 * @param specs {@code non-null;} SSA registers to check 573 * @param ropReg {@code >=0;} rop register to check mapping to 574 * @return {@code true} if all unmapped registers can be mapped 575 */ 576 private boolean canMapRegs(ArrayList<RegisterSpec> specs, int ropReg) { 577 for (RegisterSpec spec : specs) { 578 if (ssaRegsMapped.get(spec.getReg())) continue; 579 if (!canMapReg(spec, ropReg)) return false; 580 } 581 return true; 582 } 583 584 /** 585 * Checks to see if {@code ssaSpec} can be mapped to 586 * {@code ropReg}. Checks interference graph and ensures 587 * the range does not cross the parameter range. 588 * 589 * @param ssaSpec {@code non-null;} SSA spec 590 * @param ropReg prosepctive new-namespace reg 591 * @return {@code true} if mapping is possible 592 */ 593 private boolean canMapReg(RegisterSpec ssaSpec, int ropReg) { 594 int category = ssaSpec.getCategory(); 595 return !(spansParamRange(ropReg, category) 596 || mapper.interferes(ssaSpec, ropReg)); 597 } 598 599 /** 600 * Returns true if the specified rop register + category 601 * will cross the boundry between the lower {@code paramWidth} 602 * registers reserved for method params and the upper registers. We cannot 603 * allocate a register that spans the param block and the normal block, 604 * because we will be moving the param block to high registers later. 605 * 606 * @param ssaReg register in new namespace 607 * @param category width that the register will have 608 * @return {@code true} in the case noted above 609 */ 610 private boolean spansParamRange(int ssaReg, int category) { 611 return ((ssaReg < paramRangeEnd) 612 && ((ssaReg + category) > paramRangeEnd)); 613 } 614 615 /** 616 * Analyze each instruction and find out all the local variable assignments 617 * and move-result-pseudo/invoke-range instrucitons. 618 */ 619 private void analyzeInstructions() { 620 ssaMeth.forEachInsn(new SsaInsn.Visitor() { 621 /** {@inheritDoc} */ 622 public void visitMoveInsn(NormalSsaInsn insn) { 623 processInsn(insn); 624 } 625 626 /** {@inheritDoc} */ 627 public void visitPhiInsn(PhiInsn insn) { 628 processInsn(insn); 629 } 630 631 /** {@inheritDoc} */ 632 public void visitNonMoveInsn(NormalSsaInsn insn) { 633 processInsn(insn); 634 } 635 636 /** 637 * This method collects three types of instructions: 638 * 639 * 1) Adds a local variable assignment to the 640 * {@code localVariables} map. 641 * 2) Add move-result-pseudo to the 642 * {@code moveResultPseudoInsns} list. 643 * 3) Add invoke-range to the 644 * {@code invokeRangeInsns} list. 645 * 646 * @param insn {@code non-null;} insn that may represent a 647 * local variable assignment 648 */ 649 private void processInsn(SsaInsn insn) { 650 RegisterSpec assignment; 651 assignment = insn.getLocalAssignment(); 652 653 if (assignment != null) { 654 LocalItem local = assignment.getLocalItem(); 655 656 ArrayList<RegisterSpec> regList 657 = localVariables.get(local); 658 659 if (regList == null) { 660 regList = new ArrayList<RegisterSpec>(); 661 localVariables.put(local, regList); 662 } 663 664 regList.add(assignment); 665 } 666 667 if (insn instanceof NormalSsaInsn) { 668 if (insn.getOpcode().getOpcode() == 669 RegOps.MOVE_RESULT_PSEUDO) { 670 moveResultPseudoInsns.add((NormalSsaInsn) insn); 671 } else if (Optimizer.getAdvice().requiresSourcesInOrder( 672 insn.getOriginalRopInsn().getOpcode(), 673 insn.getSources())) { 674 invokeRangeInsns.add((NormalSsaInsn) insn); 675 } 676 } else if (insn instanceof PhiInsn) { 677 phiInsns.add((PhiInsn) insn); 678 } 679 680 } 681 }); 682 } 683 684 /** 685 * Adds a mapping from an SSA register to a rop register. 686 * {@link #canMapReg} should have already been called. 687 * 688 * @param ssaSpec {@code non-null;} SSA register to map from 689 * @param ropReg {@code >=0;} rop register to map to 690 */ 691 private void addMapping(RegisterSpec ssaSpec, int ropReg) { 692 int ssaReg = ssaSpec.getReg(); 693 694 // An assertion. 695 if (ssaRegsMapped.get(ssaReg) || !canMapReg(ssaSpec, ropReg)) { 696 throw new RuntimeException( 697 "attempt to add invalid register mapping"); 698 } 699 700 if (DEBUG) { 701 System.out.printf("Add mapping s%d -> v%d c:%d\n", 702 ssaSpec.getReg(), ropReg, ssaSpec.getCategory()); 703 } 704 705 int category = ssaSpec.getCategory(); 706 mapper.addMapping(ssaSpec.getReg(), ropReg, category); 707 ssaRegsMapped.set(ssaReg); 708 usedRopRegs.set(ropReg, ropReg + category); 709 } 710 711 712 /** 713 * Maps the source registers of the specified instruction such that they 714 * will fall in a contiguous range in rop form. Moves are inserted as 715 * necessary to allow the range to be allocated. 716 * 717 * @param insn {@code non-null;} insn whos sources to process 718 */ 719 private void adjustAndMapSourceRangeRange(NormalSsaInsn insn) { 720 int newRegStart = findRangeAndAdjust(insn); 721 722 RegisterSpecList sources = insn.getSources(); 723 int szSources = sources.size(); 724 int nextRopReg = newRegStart; 725 726 for (int i = 0; i < szSources; i++) { 727 RegisterSpec source = sources.get(i); 728 int sourceReg = source.getReg(); 729 int category = source.getCategory(); 730 int curRopReg = nextRopReg; 731 nextRopReg += category; 732 733 if (ssaRegsMapped.get(sourceReg)) { 734 continue; 735 } 736 737 LocalItem localItem = getLocalItemForReg(sourceReg); 738 addMapping(source, curRopReg); 739 740 if (localItem != null) { 741 markReserved(curRopReg, category); 742 ArrayList<RegisterSpec> similarRegisters 743 = localVariables.get(localItem); 744 745 int szSimilar = similarRegisters.size(); 746 747 /* 748 * Try to map all SSA registers also associated with 749 * this local. 750 */ 751 for (int j = 0; j < szSimilar; j++) { 752 RegisterSpec similarSpec = similarRegisters.get(j); 753 int similarReg = similarSpec.getReg(); 754 755 // Don't map anything that's also a source. 756 if (-1 != sources.indexOfRegister(similarReg)) { 757 continue; 758 } 759 760 // Registers left unmapped will get handled later. 761 tryMapReg(similarSpec, curRopReg, category); 762 } 763 } 764 } 765 } 766 767 /** 768 * Find a contiguous rop register range that fits the specified 769 * instruction's sources. First, try to center the range around 770 * sources that have already been mapped to rop registers. If that fails, 771 * just find a new contiguous range that doesn't interfere. 772 * 773 * @param insn {@code non-null;} the insn whose sources need to 774 * fit. Must be last insn in basic block. 775 * @return {@code >= 0;} rop register of start of range 776 */ 777 private int findRangeAndAdjust(NormalSsaInsn insn) { 778 RegisterSpecList sources = insn.getSources(); 779 int szSources = sources.size(); 780 // the category for each source index 781 int categoriesForIndex[] = new int[szSources]; 782 int rangeLength = 0; 783 784 // Compute rangeLength and categoriesForIndex 785 for (int i = 0; i < szSources; i++) { 786 int category = sources.get(i).getCategory(); 787 categoriesForIndex[i] = category; 788 rangeLength += categoriesForIndex[i]; 789 } 790 791 // the highest score of fits tried so far 792 int maxScore = Integer.MIN_VALUE; 793 // the high scoring range's start 794 int resultRangeStart = -1; 795 // by source index: set of sources needing moves in high scoring plan 796 BitSet resultMovesRequired = null; 797 798 /* 799 * First, go through each source that's already been mapped. Try 800 * to center the range around the rop register this source is mapped 801 * to. 802 */ 803 int rangeStartOffset = 0; 804 for (int i = 0; i < szSources; i++) { 805 int ssaCenterReg = sources.get(i).getReg(); 806 807 if (i != 0) { 808 rangeStartOffset -= categoriesForIndex[i - 1]; 809 } 810 if (!ssaRegsMapped.get(ssaCenterReg)) { 811 continue; 812 } 813 814 int rangeStart = mapper.oldToNew(ssaCenterReg) + rangeStartOffset; 815 816 if (rangeStart < 0 || spansParamRange(rangeStart, rangeLength)) { 817 continue; 818 } 819 820 BitSet curMovesRequired = new BitSet(szSources); 821 822 int fitWidth 823 = fitPlanForRange(rangeStart, insn, categoriesForIndex, 824 curMovesRequired); 825 826 if (fitWidth < 0) { 827 continue; 828 } 829 830 int score = fitWidth - curMovesRequired.cardinality(); 831 832 if (score > maxScore) { 833 maxScore = score; 834 resultRangeStart = rangeStart; 835 resultMovesRequired = curMovesRequired; 836 } 837 838 if (fitWidth == rangeLength) { 839 // We can't do any better than this, so stop here 840 break; 841 } 842 } 843 844 /* 845 * If we were unable to find a plan for a fit centered around 846 * an already-mapped source, just try to find a range of 847 * registers we can move the range into. 848 */ 849 850 if (resultRangeStart == -1) { 851 resultMovesRequired = new BitSet(szSources); 852 853 resultRangeStart = findAnyFittingRange(insn, rangeLength, 854 categoriesForIndex, resultMovesRequired); 855 } 856 857 /* 858 * Now, insert any moves required. 859 */ 860 861 for (int i = resultMovesRequired.nextSetBit(0); i >= 0; 862 i = resultMovesRequired.nextSetBit(i+1)) { 863 insn.changeOneSource(i, insertMoveBefore(insn, sources.get(i))); 864 } 865 866 return resultRangeStart; 867 } 868 869 /** 870 * Finds an unreserved range that will fit the sources of the 871 * specified instruction. Does not bother trying to center the range 872 * around an already-mapped source register; 873 * 874 * @param insn {@code non-null;} insn to build range for 875 * @param rangeLength {@code >=0;} length required in register units 876 * @param categoriesForIndex {@code non-null;} indexed by source index; 877 * the category for each source 878 * @param outMovesRequired {@code non-null;} an output parameter indexed by 879 * source index that will contain the set of sources which need 880 * moves inserted 881 * @return the rop register that starts the fitting range 882 */ 883 private int findAnyFittingRange(NormalSsaInsn insn, int rangeLength, 884 int[] categoriesForIndex, BitSet outMovesRequired) { 885 int rangeStart = paramRangeEnd; 886 while (true) { 887 rangeStart = findNextUnreservedRopReg(rangeStart, rangeLength); 888 int fitWidth 889 = fitPlanForRange(rangeStart, insn, 890 categoriesForIndex, outMovesRequired); 891 892 if (fitWidth >= 0) { 893 break; 894 } 895 rangeStart++; 896 outMovesRequired.clear(); 897 } 898 return rangeStart; 899 } 900 901 /** 902 * Attempts to build a plan for fitting a range of sources into rop 903 * registers. 904 * 905 * @param ropReg {@code >= 0;} rop reg that begins range 906 * @param insn {@code non-null;} insn to plan range for 907 * @param categoriesForIndex {@code non-null;} indexed by source index; 908 * the category for each source 909 * @param outMovesRequired {@code non-null;} an output parameter indexed by 910 * source index that will contain the set of sources which need 911 * moves inserted 912 * @return the width of the fit that that does not involve added moves or 913 * {@code -1} if "no fit possible" 914 */ 915 private int fitPlanForRange(int ropReg, NormalSsaInsn insn, 916 int[] categoriesForIndex, BitSet outMovesRequired) { 917 RegisterSpecList sources = insn.getSources(); 918 int szSources = sources.size(); 919 int fitWidth = 0; 920 IntSet liveOut = insn.getBlock().getLiveOutRegs(); 921 RegisterSpecList liveOutSpecs = ssaSetToSpecs(liveOut); 922 923 // An SSA reg may only be mapped into a range once. 924 BitSet seen = new BitSet(ssaMeth.getRegCount()); 925 926 for (int i = 0; i < szSources ; i++) { 927 RegisterSpec ssaSpec = sources.get(i); 928 int ssaReg = ssaSpec.getReg(); 929 int category = categoriesForIndex[i]; 930 931 if (i != 0) { 932 ropReg += categoriesForIndex[i-1]; 933 } 934 935 if (ssaRegsMapped.get(ssaReg) 936 && mapper.oldToNew(ssaReg) == ropReg) { 937 // This is a register that is already mapped appropriately. 938 fitWidth += category; 939 } else if (rangeContainsReserved(ropReg, category)) { 940 fitWidth = -1; 941 break; 942 } else if (!ssaRegsMapped.get(ssaReg) 943 && canMapReg(ssaSpec, ropReg) 944 && !seen.get(ssaReg)) { 945 // This is a register that can be mapped appropriately. 946 fitWidth += category; 947 } else if (!mapper.areAnyPinned(liveOutSpecs, ropReg, category) 948 && !mapper.areAnyPinned(sources, ropReg, category)) { 949 /* 950 * This is a source that can be moved. We can insert a 951 * move as long as: 952 * 953 * * no SSA register pinned to the desired rop reg 954 * is live out on the block 955 * 956 * * no SSA register pinned to desired rop reg is 957 * a source of this insn (since this may require 958 * overlapping moves, which we can't presently handle) 959 */ 960 961 outMovesRequired.set(i); 962 } else { 963 fitWidth = -1; 964 break; 965 } 966 967 seen.set(ssaReg); 968 } 969 return fitWidth; 970 } 971 972 /** 973 * Converts a bit set of SSA registers into a RegisterSpecList containing 974 * the definition specs of all the registers. 975 * 976 * @param ssaSet {@code non-null;} set of SSA registers 977 * @return list of RegisterSpecs as noted above 978 */ 979 RegisterSpecList ssaSetToSpecs(IntSet ssaSet) { 980 RegisterSpecList result = new RegisterSpecList(ssaSet.elements()); 981 982 IntIterator iter = ssaSet.iterator(); 983 984 int i = 0; 985 while (iter.hasNext()) { 986 result.set(i++, getDefinitionSpecForSsaReg(iter.next())); 987 } 988 989 return result; 990 } 991 992 /** 993 * Gets a local item associated with an ssa register, if one exists. 994 * 995 * @param ssaReg {@code >= 0;} SSA register 996 * @return {@code null-ok;} associated local item or null 997 */ 998 private LocalItem getLocalItemForReg(int ssaReg) { 999 for (Map.Entry<LocalItem, ArrayList<RegisterSpec>> entry : 1000 localVariables.entrySet()) { 1001 for (RegisterSpec spec : entry.getValue()) { 1002 if (spec.getReg() == ssaReg) { 1003 return entry.getKey(); 1004 } 1005 } 1006 } 1007 1008 return null; 1009 } 1010 1011 /** 1012 * Attempts to map the sources and result of a phi to a common register. 1013 * Will try existing mappings first, from most to least common. If none 1014 * of the registers have mappings yet, a new mapping is created. 1015 */ 1016 private void processPhiInsn(PhiInsn insn) { 1017 RegisterSpec result = insn.getResult(); 1018 int resultReg = result.getReg(); 1019 int category = result.getCategory(); 1020 1021 RegisterSpecList sources = insn.getSources(); 1022 int sourcesSize = sources.size(); 1023 1024 // List of phi sources / result that need mapping 1025 ArrayList<RegisterSpec> ssaRegs = new ArrayList<RegisterSpec>(); 1026 1027 // Track how many times a particular mapping is found 1028 Multiset mapSet = new Multiset(sourcesSize + 1); 1029 1030 /* 1031 * If the result of the phi has an existing mapping, get it. 1032 * Otherwise, add it to the list of regs that need mapping. 1033 */ 1034 if (ssaRegsMapped.get(resultReg)) { 1035 mapSet.add(mapper.oldToNew(resultReg)); 1036 } else { 1037 ssaRegs.add(result); 1038 } 1039 1040 for (int i = 0; i < sourcesSize; i++) { 1041 RegisterSpec source = sources.get(i); 1042 SsaInsn def = ssaMeth.getDefinitionForRegister(source.getReg()); 1043 RegisterSpec sourceDef = def.getResult(); 1044 int sourceReg = sourceDef.getReg(); 1045 1046 /* 1047 * If a source of the phi has an existing mapping, get it. 1048 * Otherwise, add it to the list of regs that need mapping. 1049 */ 1050 if (ssaRegsMapped.get(sourceReg)) { 1051 mapSet.add(mapper.oldToNew(sourceReg)); 1052 } else { 1053 ssaRegs.add(sourceDef); 1054 } 1055 } 1056 1057 // Try all existing mappings, with the most common ones first 1058 for (int i = 0; i < mapSet.getSize(); i++) { 1059 int maxReg = mapSet.getAndRemoveHighestCount(); 1060 tryMapRegs(ssaRegs, maxReg, category, false); 1061 } 1062 1063 // Map any remaining unmapped regs with whatever fits 1064 int mapReg = findNextUnreservedRopReg(paramRangeEnd, category); 1065 while (!tryMapRegs(ssaRegs, mapReg, category, false)) { 1066 mapReg = findNextUnreservedRopReg(mapReg + 1, category); 1067 } 1068 } 1069 1070 // A set that tracks how often elements are added to it. 1071 private static class Multiset { 1072 private final int[] reg; 1073 private final int[] count; 1074 private int size; 1075 1076 /** 1077 * Constructs an instance. 1078 * 1079 * @param maxSize the maximum distinct elements the set may have 1080 */ 1081 public Multiset(int maxSize) { 1082 reg = new int[maxSize]; 1083 count = new int[maxSize]; 1084 size = 0; 1085 } 1086 1087 /** 1088 * Adds an element to the set. 1089 * 1090 * @param element element to add 1091 */ 1092 public void add(int element) { 1093 for (int i = 0; i < size; i++) { 1094 if (reg[i] == element) { 1095 count[i]++; 1096 return; 1097 } 1098 } 1099 1100 reg[size] = element; 1101 count[size] = 1; 1102 size++; 1103 } 1104 1105 /** 1106 * Searches the set for the element that has been added the most. 1107 * In the case of a tie, the element that was added first is returned. 1108 * Then, it clears the count on that element. The size of the set 1109 * remains unchanged. 1110 * 1111 * @return element with the highest count 1112 */ 1113 public int getAndRemoveHighestCount() { 1114 int maxIndex = -1; 1115 int maxReg = -1; 1116 int maxCount = 0; 1117 1118 for (int i = 0; i < size; i++) { 1119 if (maxCount < count[i]) { 1120 maxIndex = i; 1121 maxReg = reg[i]; 1122 maxCount = count[i]; 1123 } 1124 } 1125 1126 count[maxIndex] = 0; 1127 return maxReg; 1128 } 1129 1130 /** 1131 * Gets the number of distinct elements in the set. 1132 * 1133 * @return size of the set 1134 */ 1135 public int getSize() { 1136 return size; 1137 } 1138 } 1139 } 1140