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.ir.ia32;
014
015import static org.jikesrvm.compilers.opt.regalloc.ia32.PhysicalRegisterConstants.AF;
016import static org.jikesrvm.compilers.opt.regalloc.ia32.PhysicalRegisterConstants.C0;
017import static org.jikesrvm.compilers.opt.regalloc.ia32.PhysicalRegisterConstants.C1;
018import static org.jikesrvm.compilers.opt.regalloc.ia32.PhysicalRegisterConstants.C2;
019import static org.jikesrvm.compilers.opt.regalloc.ia32.PhysicalRegisterConstants.C3;
020import static org.jikesrvm.compilers.opt.regalloc.ia32.PhysicalRegisterConstants.CF;
021import static org.jikesrvm.compilers.opt.regalloc.ia32.PhysicalRegisterConstants.DOUBLE_REG;
022import static org.jikesrvm.compilers.opt.regalloc.ia32.PhysicalRegisterConstants.FIRST_DOUBLE;
023import static org.jikesrvm.compilers.opt.regalloc.ia32.PhysicalRegisterConstants.FIRST_INT;
024import static org.jikesrvm.compilers.opt.regalloc.ia32.PhysicalRegisterConstants.FIRST_SPECIAL;
025import static org.jikesrvm.compilers.opt.regalloc.ia32.PhysicalRegisterConstants.INT_REG;
026import static org.jikesrvm.compilers.opt.regalloc.ia32.PhysicalRegisterConstants.NUM_SPECIALS;
027import static org.jikesrvm.compilers.opt.regalloc.ia32.PhysicalRegisterConstants.OF;
028import static org.jikesrvm.compilers.opt.regalloc.ia32.PhysicalRegisterConstants.PF;
029import static org.jikesrvm.compilers.opt.regalloc.ia32.PhysicalRegisterConstants.SF;
030import static org.jikesrvm.compilers.opt.regalloc.ia32.PhysicalRegisterConstants.SPECIAL_REG;
031import static org.jikesrvm.compilers.opt.regalloc.ia32.PhysicalRegisterConstants.ST0;
032import static org.jikesrvm.compilers.opt.regalloc.ia32.PhysicalRegisterConstants.ST1;
033import static org.jikesrvm.compilers.opt.regalloc.ia32.PhysicalRegisterConstants.ZF;
034import static org.jikesrvm.ia32.ArchConstants.SSE2_FULL;
035import static org.jikesrvm.ia32.RegisterConstants.EAX;
036import static org.jikesrvm.ia32.RegisterConstants.EBP;
037import static org.jikesrvm.ia32.RegisterConstants.EBX;
038import static org.jikesrvm.ia32.RegisterConstants.ECX;
039import static org.jikesrvm.ia32.RegisterConstants.EDI;
040import static org.jikesrvm.ia32.RegisterConstants.EDX;
041import static org.jikesrvm.ia32.RegisterConstants.ESI;
042import static org.jikesrvm.ia32.RegisterConstants.ESP;
043import static org.jikesrvm.ia32.RegisterConstants.NATIVE_PARAMETER_FPRS;
044import static org.jikesrvm.ia32.RegisterConstants.NATIVE_PARAMETER_GPRS;
045import static org.jikesrvm.ia32.RegisterConstants.NONVOLATILE_FPRS;
046import static org.jikesrvm.ia32.RegisterConstants.NONVOLATILE_GPRS;
047import static org.jikesrvm.ia32.RegisterConstants.NUM_FPRS;
048import static org.jikesrvm.ia32.RegisterConstants.NUM_GPRS;
049import static org.jikesrvm.ia32.RegisterConstants.NUM_NATIVE_PARAMETER_FPRS;
050import static org.jikesrvm.ia32.RegisterConstants.NUM_NATIVE_PARAMETER_GPRS;
051import static org.jikesrvm.ia32.RegisterConstants.NUM_NONVOLATILE_FPRS;
052import static org.jikesrvm.ia32.RegisterConstants.NUM_NONVOLATILE_GPRS;
053import static org.jikesrvm.ia32.RegisterConstants.NUM_PARAMETER_FPRS;
054import static org.jikesrvm.ia32.RegisterConstants.NUM_PARAMETER_GPRS;
055import static org.jikesrvm.ia32.RegisterConstants.NUM_RETURN_FPRS;
056import static org.jikesrvm.ia32.RegisterConstants.NUM_RETURN_GPRS;
057import static org.jikesrvm.ia32.RegisterConstants.NUM_VOLATILE_FPRS;
058import static org.jikesrvm.ia32.RegisterConstants.NUM_VOLATILE_GPRS;
059import static org.jikesrvm.ia32.RegisterConstants.THREAD_REGISTER;
060import static org.jikesrvm.ia32.RegisterConstants.VOLATILE_FPRS;
061import static org.jikesrvm.ia32.RegisterConstants.VOLATILE_GPRS;
062
063import java.util.Enumeration;
064
065import org.jikesrvm.VM;
066import org.jikesrvm.architecture.MachineRegister;
067import org.jikesrvm.compilers.opt.OptimizingCompilerException;
068import org.jikesrvm.compilers.opt.ir.GenericPhysicalRegisterSet;
069import org.jikesrvm.compilers.opt.ir.Register;
070import org.jikesrvm.compilers.opt.util.BitSet;
071import org.jikesrvm.compilers.opt.util.CompoundEnumerator;
072import org.jikesrvm.compilers.opt.util.ReverseEnumerator;
073import org.jikesrvm.ia32.RegisterConstants.FPR;
074import org.jikesrvm.ia32.RegisterConstants.FloatingPointMachineRegister;
075import org.jikesrvm.ia32.RegisterConstants.GPR;
076import org.jikesrvm.ia32.RegisterConstants.XMM;
077import org.jikesrvm.util.EmptyEnumeration;
078
079/**
080 * This class represents a set of Registers corresponding to the
081 * IA32 register set.
082 */
083public final class PhysicalRegisterSet extends GenericPhysicalRegisterSet {
084
085  /**
086   * This array holds a pool of objects representing physical registers
087   */
088  private final Register[] reg = new Register[getSize()];
089
090  /**
091   * Cache the set of volatile registers for efficiency
092   */
093  private final BitSet volatileSet;
094
095  /**
096   * Cache the set of floating-point registers for efficiency
097   */
098  private final BitSet fpSet;
099
100  /**
101   * @return the total number of physical registers.
102   */
103  public static int getSize() {
104    return NUM_GPRS + NUM_FPRS + NUM_SPECIALS;
105  }
106
107  @Override
108  public int getNumberOfPhysicalRegisters() {
109    return getSize();
110  }
111
112  /**
113   * @return the total number of nonvolatile GPRs.
114   */
115  public static int getNumberOfNonvolatileGPRs() {
116    return NUM_NONVOLATILE_GPRS;
117  }
118
119  /**
120   * @return the total number of GPRs that may hold parameters.
121   */
122  public static int getNumberOfGPRParams() {
123    return NUM_PARAMETER_GPRS;
124  }
125
126  /**
127   * @param n register index
128   * @return the (zero-based indexed) nth native GPR that may hold a parameter.
129   */
130  public Register getNativeGPRParam(int n) {
131   return getGPR(NATIVE_PARAMETER_GPRS[n]);
132  }
133
134  /**
135   * @return the total number of FPRs that may hold parameters.
136   */
137  public static int getNumberOfFPRParams() {
138    return NUM_PARAMETER_FPRS;
139  }
140
141  /**
142   * @return the total number of native GPRs that may hold parameters.
143   */
144  public static int getNumberOfNativeGPRParams() {
145    return NUM_NATIVE_PARAMETER_GPRS;
146  }
147
148  /**
149   * @return the total number of native FPRs that may hold parameters.
150   */
151  public static int getNumberOfNativeFPRParams() {
152    return NUM_NATIVE_PARAMETER_FPRS;
153  }
154
155  /**
156   * @param n register index
157   * @return the (zero-based indexed) nth GPR that may hold a parameter.
158   */
159  public Register getGPRParam(int n) {
160    if (VM.VerifyAssertions) VM._assert(n < 2);
161    if (n == 0) {
162      return getEAX();
163    } else {
164      return getEDX();
165    }
166  }
167
168  /**
169   * @param n register index
170   * @return the (zero-based indexed) nth FPR that may hold a parameter.
171   */
172  public Register getFPRParam(int n) {
173    return getFPR(VOLATILE_FPRS[n]);
174  }
175
176  /**
177   * @param n register index
178   * @return the (zero-based indexed) nth native FPR that may hold a parameter.
179   */
180  public Register getNativeFPRParam(int n) {
181    return getFPR(NATIVE_PARAMETER_FPRS[n]);
182  }
183
184  /**
185   * @param n register index
186   * @return the (zero-based indexed) nth GPR that may hold a return value.
187   */
188  public Register getReturnGPR(int n) {
189    if (VM.VerifyAssertions) VM._assert(n < 2);
190    if (n == 0) {
191      return getEAX();
192    } else {
193      return getEDX();
194    }
195  }
196
197  public PhysicalRegisterSet() {
198
199    // 1. Create all the physical registers in the pool.
200    for (int i = 0; i < reg.length; i++) {
201      Register r = new Register(i);
202      r.setPhysical();
203      reg[i] = r;
204    }
205
206    // 2. Set the 'integer' attribute on each GPR
207    for (int i = FIRST_INT; i < FIRST_DOUBLE; i++) {
208      reg[i].setInteger();
209    }
210
211    // 3. Set the 'double' attribute on each FPR
212    for (int i = FIRST_DOUBLE; i < FIRST_SPECIAL; i++) {
213      reg[i].setDouble();
214    }
215
216    // 4. set up the volatile GPRs
217    for (Enumeration<Register> e = enumerateVolatileGPRs(); e.hasMoreElements();) {
218      Register r = e.nextElement();
219      r.setVolatile();
220    }
221
222    // 5. set up the non-volatile GPRs
223    for (Enumeration<Register> e = enumerateNonvolatileGPRs(); e.hasMoreElements();) {
224      Register r = e.nextElement();
225      r.setNonVolatile();
226    }
227
228    // 6. set properties on some special registers
229    reg[AF].setSpansBasicBlock();
230    reg[CF].setSpansBasicBlock();
231    reg[OF].setSpansBasicBlock();
232    reg[PF].setSpansBasicBlock();
233    reg[SF].setSpansBasicBlock();
234    reg[ZF].setSpansBasicBlock();
235    reg[C0].setSpansBasicBlock();
236    reg[C1].setSpansBasicBlock();
237    reg[C2].setSpansBasicBlock();
238    reg[C3].setSpansBasicBlock();
239    reg[THREAD_REGISTER.value()].setSpansBasicBlock();
240
241    // For SSE2
242    reg[ST0].setDouble();
243    reg[ST1].setDouble();
244
245    // 7. set up the volatile FPRs
246    for (Enumeration<Register> e = enumerateVolatileFPRs(); e.hasMoreElements();) {
247      Register r = e.nextElement();
248      r.setVolatile();
249    }
250
251    // 8. set up the non-volatile FPRs
252    for (Enumeration<Register> e = enumerateNonvolatileFPRs(); e.hasMoreElements();) {
253      Register r = e.nextElement();
254      r.setNonVolatile();
255    }
256
257    // 9. Cache the volatile registers for efficiency
258    volatileSet = new BitSet(this);
259    for (Enumeration<Register> e = enumerateVolatiles(); e.hasMoreElements();) {
260      Register r = e.nextElement();
261      volatileSet.add(r);
262    }
263
264    // 10. Cache the FPRs for efficiency
265    fpSet = new BitSet(this);
266    for (Enumeration<Register> e = enumerateFPRs(); e.hasMoreElements();) {
267      Register r = e.nextElement();
268      fpSet.add(r);
269    }
270
271    // Note no registers are excluded from live analysis (as is done for PPC)
272
273  }
274
275  /**
276   * @param r the register to check
277   * @return {@code true} if and only if a particular register is subject to allocation
278   */
279  @Override
280  public boolean isAllocatable(Register r) {
281    return (r.number < FIRST_SPECIAL && r != getTR() && r != getESP());
282  }
283
284  /**
285   * @return the processor register
286   */
287  @Override
288  public Register getTR() {
289    return getGPR(THREAD_REGISTER);
290  }
291
292  /**
293   * @return the frame pointer register
294   */
295  @Override
296  public Register getFP() {
297    throw new OptimizingCompilerException("Framepointer is not a register on IA32");
298  }
299
300  /**
301   * @return the EAX register
302   */
303  public Register getEAX() {
304    return getGPR(EAX);
305  }
306
307  /**
308   * @return the ECX register
309   */
310  public Register getECX() {
311    return getGPR(ECX);
312  }
313
314  /**
315   * @return the EDX register
316   */
317  public Register getEDX() {
318    return getGPR(EDX);
319  }
320
321  /**
322   * @return the EBX register
323   */
324  public Register getEBX() {
325    return getGPR(EBX);
326  }
327
328  /**
329   * @return the ESP register
330   */
331  public Register getESP() {
332    return getGPR(ESP);
333  }
334
335  /**
336   * @return the EBP register
337   */
338  public Register getEBP() {
339    return getGPR(EBP);
340  }
341
342  /**
343   * @return the ESI register
344   */
345  public Register getESI() {
346    return getGPR(ESI);
347  }
348
349  /**
350   * @return the EDI register
351   */
352  public Register getEDI() {
353    return getGPR(EDI);
354  }
355
356  /**
357   * @return a register representing the AF bit of the EFLAGS register.
358   */
359  public Register getAF() {
360    return reg[AF];
361  }
362
363  /**
364   * @return a register representing the CF bit of the EFLAGS register.
365   */
366  public Register getCF() {
367    return reg[CF];
368  }
369
370  /**
371   * @return a register representing the OF bit of the EFLAGS register.
372   */
373  public Register getOF() {
374    return reg[OF];
375  }
376
377  /**
378   * @return a register representing the PF bit of the EFLAGS register.
379   */
380  public Register getPF() {
381    return reg[PF];
382  }
383
384  /**
385   * @return a register representing the SF bit of the EFLAGS register.
386   */
387  public Register getSF() {
388    return reg[SF];
389  }
390
391  /**
392   * @return a register representing the ZF bit of the EFLAGS register.
393   */
394  public Register getZF() {
395    return reg[ZF];
396  }
397
398  /**
399   * @return a register representing the C0 floating-point status bit
400   */
401  public Register getC0() {
402    return reg[C0];
403  }
404
405  /**
406   * @return a register representing the C1 floating-point status bit
407   */
408  public Register getC1() {
409    return reg[C1];
410  }
411
412  /**
413   * @return a register representing the C2 floating-point status bit
414   */
415  public Register getC2() {
416    return reg[C2];
417  }
418
419  /**
420   * @return a register representing the C3 floating-point status bit
421   */
422  public Register getC3() {
423    return reg[C3];
424  }
425
426  @Override
427  public Register getGPR(MachineRegister n) {
428    return reg[FIRST_INT + n.value()];
429  }
430
431  @Override
432  public Register getGPR(int n) {
433    return reg[FIRST_INT + n];
434  }
435
436  /**
437   * @param r a physical GPR
438   * @return the index into the GPR set corresponding to a given register.
439   *
440   * PRECONDITION: r is a physical GPR
441   */
442  public static int getGPRIndex(Register r) {
443    return r.number - FIRST_INT;
444  }
445
446  /**
447   * @return the first GPR register used to hold a return value
448   */
449  @Override
450  public Register getFirstReturnGPR() {
451    if (VM.VerifyAssertions) VM._assert(NUM_RETURN_GPRS > 0);
452    return getEAX();
453  }
454
455  /**
456   * @return the second GPR register used to hold a return value
457   */
458  public Register getSecondReturnGPR() {
459    if (VM.VerifyAssertions) VM._assert(NUM_RETURN_GPRS > 1);
460    return getEDX();
461  }
462
463  /**
464   * @return the FPR register used to hold a return value
465   */
466  public Register getST0() {
467    if (VM.VerifyAssertions) VM._assert(NUM_RETURN_FPRS == 1);
468    if (VM.VerifyAssertions) VM._assert(SSE2_FULL);
469    return reg[ST0];
470  }
471  /**
472   * @return the special ST1 x87 register
473   */
474  public Register getST1() {
475    if (VM.VerifyAssertions) VM._assert(SSE2_FULL);
476    return reg[ST1];
477  }
478
479  /**
480   * @return the FPR register used to hold a return value
481   */
482  public Register getReturnFPR() {
483    if (VM.VerifyAssertions) VM._assert(NUM_RETURN_FPRS == 1);
484    return getFPR(0);
485  }
486
487  public Register getFPR(FloatingPointMachineRegister n) {
488    return reg[FIRST_DOUBLE + n.value()];
489  }
490
491  @Override
492  public Register getFPR(int n) {
493    return reg[FIRST_DOUBLE + n];
494  }
495
496  /**
497   * @param r a physical FPR
498   * @return the index into the FPR set corresponding to a given register.
499   *
500   * PRECONDITION: r is a physical FPR
501   */
502  public static int getFPRIndex(Register r) {
503    return r.number - FIRST_DOUBLE;
504  }
505
506  @Override
507  public Register get(int n) {
508    return reg[n];
509  }
510
511  /**
512   * Given a symbolic register, return a code that gives the physical
513   * register type to hold the value of the symbolic register.
514   * @param r a symbolic register
515   * @return one of INT_REG, DOUBLE_REG
516   */
517  public static int getPhysicalRegisterType(Register r) {
518    if (r.isInteger() || r.isLong() || r.isAddress()) {
519      return INT_REG;
520    } else if (r.isFloatingPoint()) {
521      return DOUBLE_REG;
522    } else {
523      throw new OptimizingCompilerException("getPhysicalRegisterType " + " unexpected " + r);
524    }
525  }
526
527  /**
528   * Register names for each class. used in printing the IR
529   */
530  private static final String[] registerName = new String[getSize()];
531
532  static {
533    String[] regName = registerName;
534    for (GPR r : GPR.values()) {
535      regName[r.ordinal() + FIRST_INT] = r.toString();
536    }
537    if (SSE2_FULL) {
538      for (XMM r : XMM.values()) {
539        regName[r.ordinal() + FIRST_DOUBLE] = r.toString();
540      }
541    } else {
542      for (FPR r : FPR.values()) {
543        regName[r.ordinal() + FIRST_DOUBLE] = r.toString();
544      }
545    }
546    regName[THREAD_REGISTER.value()] = "TR";
547    regName[AF] = "AF";
548    regName[CF] = "CF";
549    regName[OF] = "OF";
550    regName[PF] = "PF";
551    regName[SF] = "SF";
552    regName[ZF] = "ZF";
553    regName[ST0] = "ST0";
554    regName[ST1] = "ST1";
555  }
556
557  /**
558   * Gets the register name for a register with a particular number in the
559   * pool.
560   *
561   * @param number register number
562   * @return register name
563   */
564  public static String getName(int number) {
565    return registerName[number];
566  }
567
568  /**
569   * @param type one of INT_REG, DOUBLE_REG, SPECIAL_REG
570   * @return the spill size for a register with the given type
571   */
572  public static int getSpillSize(int type) {
573    if (VM.VerifyAssertions) {
574      VM._assert((type == INT_REG) || (type == DOUBLE_REG) || (type == SPECIAL_REG));
575    }
576    if (VM.BuildFor32Addr) {
577      if (type == DOUBLE_REG) {
578        return 8;
579      } else {
580        return 4;
581      }
582    } else {
583      return 8;
584    }
585  }
586
587  /**
588   * @param type one of INT_REG, DOUBLE_REG,  SPECIAL_REG
589   * @return the required spill alignment for a register with the given type
590   */
591  public static int getSpillAlignment(int type) {
592    if (VM.VerifyAssertions) {
593      VM._assert((type == INT_REG) || (type == DOUBLE_REG) || (type == SPECIAL_REG));
594    }
595    if (VM.BuildFor32Addr) {
596      if (type == DOUBLE_REG) {
597        return 8;
598      } else {
599        return 4;
600      }
601    } else {
602      return 8;
603    }
604  }
605
606  @Override
607  public Enumeration<Register> enumerateAll() {
608    return new RangeEnumeration(0, getSize() - 1);
609  }
610
611  @Override
612  public Enumeration<Register> enumerateGPRs() {
613    return new RangeEnumeration(FIRST_INT, FIRST_DOUBLE - 1);
614  }
615
616  public Enumeration<Register> enumerateFPRs() {
617    return new RangeEnumeration(FIRST_DOUBLE, FIRST_SPECIAL - 1);
618  }
619
620  @Override
621  public PhysicalRegisterEnumeration enumerateVolatileGPRs() {
622    Register[] r = new Register[NUM_VOLATILE_GPRS];
623    for (int i = 0; i < NUM_VOLATILE_GPRS; i++) {
624      r[i] = getGPR(VOLATILE_GPRS[i]);
625    }
626    return new PhysicalRegisterEnumeration(r);
627  }
628
629  @Override
630  public PhysicalRegisterEnumeration enumerateNonvolatileGPRs() {
631    Register[] r = new Register[NUM_NONVOLATILE_GPRS];
632    for (int i = 0; i < NUM_NONVOLATILE_GPRS; i++) {
633      r[i] = getGPR(NONVOLATILE_GPRS[i]);
634    }
635    return new PhysicalRegisterEnumeration(r);
636  }
637
638  @Override
639  public Enumeration<Register> enumerateNonvolatileGPRsBackwards() {
640    return new ReverseEnumerator<Register>(enumerateNonvolatileGPRs());
641  }
642
643  @Override
644  public PhysicalRegisterEnumeration enumerateVolatileFPRs() {
645    Register[] r = new Register[NUM_VOLATILE_FPRS];
646    for (int i = 0; i < NUM_VOLATILE_FPRS; i++) {
647      r[i] = getFPR(VOLATILE_FPRS[i]);
648    }
649    return new PhysicalRegisterEnumeration(r);
650  }
651
652  @Override
653  public PhysicalRegisterEnumeration enumerateNonvolatileFPRs() {
654    Register[] r = new Register[NUM_NONVOLATILE_FPRS];
655    for (int i = 0; i < NUM_NONVOLATILE_FPRS; i++) {
656      r[i] = getFPR(NONVOLATILE_FPRS[i]);
657    }
658    return new PhysicalRegisterEnumeration(r);
659  }
660
661  @Override
662  public Enumeration<Register> enumerateVolatiles(int regClass) {
663    switch (regClass) {
664      case INT_REG:
665        return enumerateVolatileGPRs();
666      case DOUBLE_REG:
667        return enumerateVolatileFPRs();
668      case SPECIAL_REG:
669        return EmptyEnumeration.emptyEnumeration();
670      default:
671        throw new OptimizingCompilerException("Unsupported volatile type");
672    }
673  }
674
675  @Override
676  public Enumeration<Register> enumerateVolatiles() {
677    Enumeration<Register> e1 = enumerateVolatileGPRs();
678    Enumeration<Register> e2 = enumerateVolatileFPRs();
679    return new CompoundEnumerator<Register>(e1, e2);
680  }
681
682  /**
683   * @return the set of volatile physical registers
684   */
685  public BitSet getVolatiles() {
686    return volatileSet;
687  }
688
689  /**
690   * @return the set of FPR physical registers
691   */
692  public BitSet getFPRs() {
693    return fpSet;
694  }
695
696  public Enumeration<Register> enumerateNonvolatiles(int regClass) {
697    switch (regClass) {
698      case INT_REG:
699        return enumerateNonvolatileGPRs();
700      case DOUBLE_REG:
701        return enumerateNonvolatileFPRs();
702      case SPECIAL_REG:
703        return EmptyEnumeration.emptyEnumeration();
704      default:
705        throw new OptimizingCompilerException("Unsupported non-volatile type");
706    }
707  }
708
709  @Override
710  public Enumeration<Register> enumerateNonvolatilesBackwards(int regClass) {
711    return new ReverseEnumerator<Register>(enumerateNonvolatiles(regClass));
712  }
713
714  /**
715   * An enumerator for use by the physical register utilities.
716   */
717  static final class PhysicalRegisterEnumeration implements Enumeration<Register> {
718    private int index;
719    private final Register[] r;
720
721    PhysicalRegisterEnumeration(Register[] r) {
722      this.r = r;
723      this.index = 0;
724    }
725
726    @Override
727    public Register nextElement() {
728      return r[index++];
729    }
730
731    @Override
732    public boolean hasMoreElements() {
733      return (index < r.length);
734    }
735  }
736
737  /**
738   * An enumerator for use by the physical register utilities.
739   */
740  final class RangeEnumeration implements Enumeration<Register> {
741    private final int end;
742    private int index;
743    private final int exclude; // an index in the register range to exclude
744
745    RangeEnumeration(int start, int end) {
746      this.end = end;
747      this.exclude = -1;
748      this.index = start;
749    }
750
751    RangeEnumeration(int start, int end, int exclude) {
752      this.end = end;
753      this.exclude = exclude;
754      this.index = start;
755    }
756
757    @Override
758    public Register nextElement() {
759      if (index == exclude) index++;
760      return reg[index++];
761    }
762
763    @Override
764    public boolean hasMoreElements() {
765      if (index == exclude) index++;
766      return (index <= end);
767    }
768  }
769}