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     */
013    package org.jikesrvm.compilers.opt.regalloc.ia32;
014    
015    import java.util.Enumeration;
016    import java.util.Iterator;
017    import org.jikesrvm.classloader.TypeReference;
018    import org.jikesrvm.compilers.opt.OptimizingCompilerException;
019    import org.jikesrvm.compilers.opt.ir.Empty;
020    import org.jikesrvm.compilers.opt.ir.MIR_BinaryAcc;
021    import org.jikesrvm.compilers.opt.ir.MIR_FSave;
022    import org.jikesrvm.compilers.opt.ir.MIR_Lea;
023    import org.jikesrvm.compilers.opt.ir.MIR_Move;
024    import org.jikesrvm.compilers.opt.ir.MIR_Nullary;
025    import org.jikesrvm.compilers.opt.ir.MIR_TrapIf;
026    import org.jikesrvm.compilers.opt.ir.MIR_UnaryNoRes;
027    import org.jikesrvm.compilers.opt.ir.IR;
028    import org.jikesrvm.compilers.opt.ir.Instruction;
029    import org.jikesrvm.compilers.opt.ir.Operator;
030    import static org.jikesrvm.compilers.opt.ir.Operators.ADVISE_ESP;
031    import static org.jikesrvm.compilers.opt.ir.Operators.BBEND;
032    import static org.jikesrvm.compilers.opt.ir.Operators.CALL_SAVE_VOLATILE;
033    import static org.jikesrvm.compilers.opt.ir.Operators.IA32_ADD;
034    import static org.jikesrvm.compilers.opt.ir.Operators.IA32_FCLEAR;
035    import static org.jikesrvm.compilers.opt.ir.Operators.IA32_FMOV;
036    import static org.jikesrvm.compilers.opt.ir.Operators.IA32_FMOV_opcode;
037    import static org.jikesrvm.compilers.opt.ir.Operators.IA32_FNINIT;
038    import static org.jikesrvm.compilers.opt.ir.Operators.IA32_FNSAVE;
039    import static org.jikesrvm.compilers.opt.ir.Operators.IA32_FRSTOR;
040    import static org.jikesrvm.compilers.opt.ir.Operators.IA32_LEA;
041    import static org.jikesrvm.compilers.opt.ir.Operators.IA32_MOV;
042    import static org.jikesrvm.compilers.opt.ir.Operators.IA32_MOVQ;
043    import static org.jikesrvm.compilers.opt.ir.Operators.IA32_MOVSD;
044    import static org.jikesrvm.compilers.opt.ir.Operators.IA32_MOVSD_opcode;
045    import static org.jikesrvm.compilers.opt.ir.Operators.IA32_MOVSS;
046    import static org.jikesrvm.compilers.opt.ir.Operators.IA32_MOVSS_opcode;
047    import static org.jikesrvm.compilers.opt.ir.Operators.IA32_MOV_opcode;
048    import static org.jikesrvm.compilers.opt.ir.Operators.IA32_POP;
049    import static org.jikesrvm.compilers.opt.ir.Operators.IA32_PUSH;
050    import static org.jikesrvm.compilers.opt.ir.Operators.IA32_RET_opcode;
051    import static org.jikesrvm.compilers.opt.ir.Operators.IA32_SYSCALL;
052    import static org.jikesrvm.compilers.opt.ir.Operators.IA32_TRAPIF;
053    import static org.jikesrvm.compilers.opt.ir.Operators.NOP;
054    import static org.jikesrvm.compilers.opt.ir.Operators.REQUIRE_ESP;
055    import static org.jikesrvm.compilers.opt.ir.Operators.YIELDPOINT_BACKEDGE;
056    import static org.jikesrvm.compilers.opt.ir.Operators.YIELDPOINT_EPILOGUE;
057    import static org.jikesrvm.compilers.opt.ir.Operators.YIELDPOINT_OSR;
058    import static org.jikesrvm.compilers.opt.ir.Operators.YIELDPOINT_PROLOGUE;
059    import static org.jikesrvm.compilers.opt.regalloc.ia32.PhysicalRegisterConstants.DOUBLE_REG;
060    import static org.jikesrvm.compilers.opt.regalloc.ia32.PhysicalRegisterConstants.DOUBLE_VALUE;
061    import static org.jikesrvm.compilers.opt.regalloc.ia32.PhysicalRegisterConstants.FLOAT_VALUE;
062    import static org.jikesrvm.compilers.opt.regalloc.ia32.PhysicalRegisterConstants.INT_REG;
063    import static org.jikesrvm.compilers.opt.regalloc.ia32.PhysicalRegisterConstants.INT_VALUE;
064    
065    import org.jikesrvm.compilers.opt.ir.Register;
066    import org.jikesrvm.compilers.opt.ir.ia32.PhysicalDefUse;
067    import org.jikesrvm.compilers.opt.ir.ia32.PhysicalRegisterSet;
068    import org.jikesrvm.compilers.opt.ir.operand.MemoryOperand;
069    import org.jikesrvm.compilers.opt.ir.operand.Operand;
070    import org.jikesrvm.compilers.opt.ir.operand.RegisterOperand;
071    import org.jikesrvm.compilers.opt.ir.operand.StackLocationOperand;
072    import org.jikesrvm.compilers.opt.ir.operand.TrapCodeOperand;
073    import org.jikesrvm.compilers.opt.ir.operand.ia32.IA32ConditionOperand;
074    import org.jikesrvm.compilers.opt.regalloc.GenericStackManager;
075    import org.jikesrvm.compilers.opt.regalloc.RegisterAllocatorState;
076    import org.jikesrvm.ia32.ArchConstants;
077    import static org.jikesrvm.ia32.StackframeLayoutConstants.STACKFRAME_ALIGNMENT;
078    import org.jikesrvm.runtime.ArchEntrypoints;
079    import org.jikesrvm.runtime.Entrypoints;
080    import org.vmmagic.unboxed.Offset;
081    
082    /**
083     * Class to manage the allocation of the "compiler-specific" portion of
084     * the stackframe.  This class holds only the architecture-specific
085     * functions.
086     */
087    public abstract class StackManager extends GenericStackManager {
088    
089      /**
090       * A frame offset for 108 bytes of stack space to store the
091       * floating point state in the SaveVolatile protocol.
092       */
093      private int fsaveLocation;
094    
095      /**
096       * We allow the stack pointer to float from its normal position at the
097       * bottom of the frame.  This field holds the 'current' offset of the
098       * SP.
099       */
100      private int ESPOffset = 0;
101    
102      /**
103       * Should we allow the stack pointer to float in order to avoid scratch
104       * registers in move instructions.  Note: as of Feb. 02, we think this
105       * is a bad idea.
106       */
107      private static boolean FLOAT_ESP = false;
108    
109      @Override
110      public final int getFrameFixedSize() {
111        return frameSize - WORDSIZE;
112      }
113    
114      /**
115       * Return the size of a type of value, in bytes.
116       * NOTE: For the purpose of register allocation, an x87 FLOAT_VALUE is 64 bits!
117       *
118       * @param type one of INT_VALUE, FLOAT_VALUE, or DOUBLE_VALUE
119       */
120      private static byte getSizeOfType(byte type) {
121        switch (type) {
122          case INT_VALUE:
123            return (byte) (WORDSIZE);
124          case FLOAT_VALUE:
125            if (ArchConstants.SSE2_FULL) return (byte) WORDSIZE;
126          case DOUBLE_VALUE:
127            return (byte) (2 * WORDSIZE);
128          default:
129            OptimizingCompilerException.TODO("getSizeOfValue: unsupported");
130            return 0;
131        }
132      }
133    
134      /**
135       * Return the move operator for a type of value.
136       *
137       * @param type one of INT_VALUE, FLOAT_VALUE, or DOUBLE_VALUE
138       */
139      private static Operator getMoveOperator(byte type) {
140        switch (type) {
141          case INT_VALUE:
142            return IA32_MOV;
143          case DOUBLE_VALUE:
144            if (ArchConstants.SSE2_FULL) return IA32_MOVSD;
145          case FLOAT_VALUE:
146            if (ArchConstants.SSE2_FULL) return IA32_MOVSS;
147            return IA32_FMOV;
148          default:
149            OptimizingCompilerException.TODO("getMoveOperator: unsupported");
150            return null;
151        }
152      }
153    
154      @Override
155      public final int allocateNewSpillLocation(int type) {
156    
157        // increment by the spill size
158        spillPointer += PhysicalRegisterSet.getSpillSize(type);
159    
160        if (spillPointer + WORDSIZE > frameSize) {
161          frameSize = spillPointer + WORDSIZE;
162        }
163        return spillPointer;
164      }
165    
166      @Override
167      public final void insertSpillBefore(Instruction s, Register r, byte type, int location) {
168    
169        Operator move = getMoveOperator(type);
170        byte size = getSizeOfType(type);
171        RegisterOperand rOp;
172        switch (type) {
173          case FLOAT_VALUE:
174            rOp = F(r);
175            break;
176          case DOUBLE_VALUE:
177            rOp = D(r);
178            break;
179          default:
180            rOp = new RegisterOperand(r, TypeReference.Int);
181            break;
182        }
183        StackLocationOperand spill = new StackLocationOperand(true, -location, size);
184        s.insertBefore(MIR_Move.create(move, spill, rOp));
185      }
186    
187      @Override
188      public final void insertUnspillBefore(Instruction s, Register r, byte type, int location) {
189        Operator move = getMoveOperator(type);
190        byte size = getSizeOfType(type);
191        RegisterOperand rOp;
192        switch (type) {
193          case FLOAT_VALUE:
194            rOp = F(r);
195            break;
196          case DOUBLE_VALUE:
197            rOp = D(r);
198            break;
199          default:
200            rOp = new RegisterOperand(r, TypeReference.Int);
201            break;
202        }
203        StackLocationOperand spill = new StackLocationOperand(true, -location, size);
204        s.insertBefore(MIR_Move.create(move, rOp, spill));
205      }
206    
207      @Override
208      public void computeNonVolatileArea() {
209        PhysicalRegisterSet phys = ir.regpool.getPhysicalRegisterSet();
210    
211        if (ir.compiledMethod.isSaveVolatile()) {
212          // Record that we use every nonvolatile GPR
213          int numGprNv = PhysicalRegisterSet.getNumberOfNonvolatileGPRs();
214          ir.compiledMethod.setNumberOfNonvolatileGPRs((short) numGprNv);
215    
216          // set the frame size
217          frameSize += numGprNv * WORDSIZE;
218          frameSize = align(frameSize, STACKFRAME_ALIGNMENT);
219    
220          // TODO!!
221          ir.compiledMethod.setNumberOfNonvolatileFPRs((short) 0);
222    
223          // Record that we need a stack frame.
224          setFrameRequired();
225    
226          if (ArchConstants.SSE2_FULL) {
227            for(int i=0; i < 8; i++) {
228              fsaveLocation = allocateNewSpillLocation(DOUBLE_REG);
229            }
230          } else {
231            // Grab 108 bytes (same as 27 4-byte spills) in the stack
232            // frame, as a place to store the floating-point state with FSAVE
233            for (int i = 0; i < 27; i++) {
234              fsaveLocation = allocateNewSpillLocation(INT_REG);
235            }
236          }
237    
238          // Map each volatile register to a spill location.
239          int i = 0;
240          for (Enumeration<Register> e = phys.enumerateVolatileGPRs(); e.hasMoreElements(); i++) {
241            e.nextElement();
242            // Note that as a side effect, the following call bumps up the
243            // frame size.
244            saveVolatileGPRLocation[i] = allocateNewSpillLocation(INT_REG);
245          }
246    
247          // Map each non-volatile register to a spill location.
248          i = 0;
249          for (Enumeration<Register> e = phys.enumerateNonvolatileGPRs(); e.hasMoreElements(); i++) {
250            e.nextElement();
251            // Note that as a side effect, the following call bumps up the
252            // frame size.
253            nonVolatileGPRLocation[i] = allocateNewSpillLocation(INT_REG);
254          }
255    
256          // Set the offset to find non-volatiles.
257          int gprOffset = getNonvolatileGPROffset(0);
258          ir.compiledMethod.setUnsignedNonVolatileOffset(gprOffset);
259    
260        } else {
261          // Count the number of nonvolatiles used.
262          int numGprNv = 0;
263          int i = 0;
264          for (Enumeration<Register> e = phys.enumerateNonvolatileGPRs(); e.hasMoreElements();) {
265            Register r = e.nextElement();
266            if (r.isTouched()) {
267              // Note that as a side effect, the following call bumps up the
268              // frame size.
269              nonVolatileGPRLocation[i++] = allocateNewSpillLocation(INT_REG);
270              numGprNv++;
271            }
272          }
273          // Update the OptCompiledMethod object.
274          ir.compiledMethod.setNumberOfNonvolatileGPRs((short) numGprNv);
275          if (numGprNv > 0) {
276            int gprOffset = getNonvolatileGPROffset(0);
277            ir.compiledMethod.setUnsignedNonVolatileOffset(gprOffset);
278            // record that we need a stack frame
279            setFrameRequired();
280          } else {
281            ir.compiledMethod.setUnsignedNonVolatileOffset(0);
282          }
283    
284          ir.compiledMethod.setNumberOfNonvolatileFPRs((short) 0);
285    
286        }
287      }
288    
289      @Override
290      public void cleanUpAndInsertEpilogue() {
291    
292        Instruction inst = ir.firstInstructionInCodeOrder().nextInstructionInCodeOrder();
293        for (; inst != null; inst = inst.nextInstructionInCodeOrder()) {
294          switch (inst.getOpcode()) {
295            case IA32_MOV_opcode:
296              // remove frivolous moves
297              Operand result = MIR_Move.getResult(inst);
298              Operand val = MIR_Move.getValue(inst);
299              if (result.similar(val)) {
300                inst = inst.remove();
301              }
302              break;
303            case IA32_FMOV_opcode:
304            case IA32_MOVSS_opcode:
305            case IA32_MOVSD_opcode:
306              // remove frivolous moves
307              result = MIR_Move.getResult(inst);
308              val = MIR_Move.getValue(inst);
309              if (result.similar(val)) {
310                inst = inst.remove();
311              }
312              break;
313            case IA32_RET_opcode:
314              if (frameIsRequired()) {
315                insertEpilogue(inst);
316              }
317            default:
318              break;
319          }
320        }
321        // now that the frame size is fixed, fix up the spill location code
322        rewriteStackLocations();
323      }
324    
325      /**
326       * Insert an explicit stack overflow check in the prologue <em>after</em>
327       * buying the stack frame.<p>
328       *
329       * SIDE EFFECT: mutates the plg into a trap instruction.  We need to
330       * mutate so that the trap instruction is in the GC map data structures.
331       *
332       * @param plg the prologue instruction
333       */
334      private void insertNormalStackOverflowCheck(Instruction plg) {
335        if (!ir.method.isInterruptible()) {
336          plg.remove();
337          return;
338        }
339    
340        if (ir.compiledMethod.isSaveVolatile()) {
341          return;
342        }
343    
344        PhysicalRegisterSet phys = ir.regpool.getPhysicalRegisterSet();
345        Register ESP = phys.getESP();
346        MemoryOperand M =
347            MemoryOperand.BD(ir.regpool.makeTROp(),
348                                 Entrypoints.stackLimitField.getOffset(),
349                                 (byte) WORDSIZE,
350                                 null,
351                                 null);
352    
353        //    Trap if ESP <= active Thread Stack Limit
354        MIR_TrapIf.mutate(plg,
355                          IA32_TRAPIF,
356                          null,
357                          new RegisterOperand(ESP, TypeReference.Int),
358                          M,
359                          IA32ConditionOperand.LE(),
360                          TrapCodeOperand.StackOverflow());
361      }
362    
363      /**
364       * Insert an explicit stack overflow check in the prologue <em>before</em>
365       * buying the stack frame.
366       * SIDE EFFECT: mutates the plg into a trap instruction.  We need to
367       * mutate so that the trap instruction is in the GC map data structures.
368       *
369       * @param plg the prologue instruction
370       */
371      private void insertBigFrameStackOverflowCheck(Instruction plg) {
372        if (!ir.method.isInterruptible()) {
373          plg.remove();
374          return;
375        }
376    
377        if (ir.compiledMethod.isSaveVolatile()) {
378          return;
379        }
380    
381        PhysicalRegisterSet phys = ir.regpool.getPhysicalRegisterSet();
382        Register ESP = phys.getESP();
383        Register ECX = phys.getECX();
384    
385        //    ECX := active Thread Stack Limit
386        MemoryOperand M =
387            MemoryOperand.BD(ir.regpool.makeTROp(),
388                                 Entrypoints.stackLimitField.getOffset(),
389                                 (byte) WORDSIZE,
390                                 null,
391                                 null);
392        plg.insertBefore(MIR_Move.create(IA32_MOV, new RegisterOperand((ECX), TypeReference.Int), M));
393    
394        //    ECX += frame Size
395        int frameSize = getFrameFixedSize();
396        plg.insertBefore(MIR_BinaryAcc.create(IA32_ADD, new RegisterOperand(ECX, TypeReference.Int), IC(frameSize)));
397        //    Trap if ESP <= ECX
398        MIR_TrapIf.mutate(plg,
399                          IA32_TRAPIF,
400                          null,
401                          new RegisterOperand(ESP, TypeReference.Int),
402                          new RegisterOperand(ECX, TypeReference.Int),
403                          IA32ConditionOperand.LE(),
404                          TrapCodeOperand.StackOverflow());
405      }
406    
407      /**
408       * Insert the prologue for a normal method.
409       *
410       * Assume we are inserting the prologue for method B called from method
411       * A.
412       *    <ul>
413       *    <li> Perform a stack overflow check.
414       *    <li> Store a back pointer to A's frame
415       *    <li> Store B's compiled method id
416       *    <li> Adjust frame pointer to point to B's frame
417       *    <li> Save any used non-volatile registers
418       *    </ul>
419       */
420      @Override
421      public void insertNormalPrologue() {
422        PhysicalRegisterSet phys = ir.regpool.getPhysicalRegisterSet();
423        Register ESP = phys.getESP();
424        MemoryOperand fpHome =
425            MemoryOperand.BD(ir.regpool.makeTROp(),
426                                 ArchEntrypoints.framePointerField.getOffset(),
427                                 (byte) WORDSIZE,
428                                 null,
429                                 null);
430    
431        // the prologue instruction
432        Instruction plg = ir.firstInstructionInCodeOrder().nextInstructionInCodeOrder();
433        // inst is the instruction immediately after the IR_PROLOGUE
434        // instruction
435        Instruction inst = plg.nextInstructionInCodeOrder();
436    
437        int frameFixedSize = getFrameFixedSize();
438        ir.compiledMethod.setFrameFixedSize(frameFixedSize);
439    
440        // I. Buy a stackframe (including overflow check)
441        // NOTE: We play a little game here.  If the frame we are buying is
442        //       very small (less than 256) then we can be sloppy with the
443        //       stackoverflow check and actually allocate the frame in the guard
444        //       region.  We'll notice when this frame calls someone and take the
445        //       stackoverflow in the callee. We can't do this if the frame is too big,
446        //       because growing the stack in the callee and/or handling a hardware trap
447        //       in this frame will require most of the guard region to complete.
448        //       See libvm.C.
449        if (frameFixedSize >= 256) {
450          // 1. Insert Stack overflow check.
451          insertBigFrameStackOverflowCheck(plg);
452    
453          // 2. Save caller's frame pointer
454          inst.insertBefore(MIR_UnaryNoRes.create(IA32_PUSH, fpHome));
455    
456          // 3. Set my frame pointer to current value of stackpointer
457          inst.insertBefore(MIR_Move.create(IA32_MOV, fpHome.copy(), new RegisterOperand(ESP, TypeReference.Int)));
458    
459          // 4. Store my compiled method id
460          int cmid = ir.compiledMethod.getId();
461          inst.insertBefore(MIR_UnaryNoRes.create(IA32_PUSH, IC(cmid)));
462        } else {
463          // 1. Save caller's frame pointer
464          inst.insertBefore(MIR_UnaryNoRes.create(IA32_PUSH, fpHome));
465    
466          // 2. Set my frame pointer to current value of stackpointer
467          inst.insertBefore(MIR_Move.create(IA32_MOV, fpHome.copy(), new RegisterOperand(ESP, TypeReference.Int)));
468    
469          // 3. Store my compiled method id
470          int cmid = ir.compiledMethod.getId();
471          inst.insertBefore(MIR_UnaryNoRes.create(IA32_PUSH, IC(cmid)));
472    
473          // 4. Insert Stack overflow check.
474          insertNormalStackOverflowCheck(plg);
475        }
476    
477        // II. Save any used volatile and non-volatile registers
478        if (ir.compiledMethod.isSaveVolatile()) {
479          saveVolatiles(inst);
480          saveFloatingPointState(inst);
481        }
482        saveNonVolatiles(inst);
483      }
484    
485      /**
486       * Insert code into the prologue to save any used non-volatile
487       * registers.
488       *
489       * @param inst the first instruction after the prologue.
490       */
491      private void saveNonVolatiles(Instruction inst) {
492        PhysicalRegisterSet phys = ir.regpool.getPhysicalRegisterSet();
493        int nNonvolatileGPRS = ir.compiledMethod.getNumberOfNonvolatileGPRs();
494    
495        // Save each non-volatile GPR used by this method.
496        int n = nNonvolatileGPRS - 1;
497        for (Enumeration<Register> e = phys.enumerateNonvolatileGPRsBackwards(); e.hasMoreElements() && n >= 0; n--) {
498          Register nv = e.nextElement();
499          int offset = getNonvolatileGPROffset(n);
500          Operand M = new StackLocationOperand(true, -offset, 4);
501          inst.insertBefore(MIR_Move.create(IA32_MOV, M, new RegisterOperand(nv, TypeReference.Int)));
502        }
503      }
504    
505      /**
506       * Insert code before a return instruction to restore the nonvolatile
507       * registers.
508       *
509       * @param inst the return instruction
510       */
511      private void restoreNonVolatiles(Instruction inst) {
512        PhysicalRegisterSet phys = ir.regpool.getPhysicalRegisterSet();
513        int nNonvolatileGPRS = ir.compiledMethod.getNumberOfNonvolatileGPRs();
514    
515        int n = nNonvolatileGPRS - 1;
516        for (Enumeration<Register> e = phys.enumerateNonvolatileGPRsBackwards(); e.hasMoreElements() && n >= 0; n--) {
517          Register nv = e.nextElement();
518          int offset = getNonvolatileGPROffset(n);
519          Operand M = new StackLocationOperand(true, -offset, 4);
520          inst.insertBefore(MIR_Move.create(IA32_MOV, new RegisterOperand(nv, TypeReference.Int), M));
521        }
522      }
523    
524      /**
525       * Insert code into the prologue to save the floating point state.
526       *
527       * @param inst the first instruction after the prologue.
528       */
529      private void saveFloatingPointState(Instruction inst) {
530    
531        if (ArchConstants.SSE2_FULL) {
532          PhysicalRegisterSet phys = ir.regpool.getPhysicalRegisterSet();
533          for (int i=0; i < 8; i++) {
534            inst.insertBefore(MIR_Move.create(IA32_MOVQ,
535                new StackLocationOperand(true, -fsaveLocation + (i * 8), 8),
536                new RegisterOperand(phys.getFPR(i), TypeReference.Double)));
537          }
538        } else {
539          Operand M = new StackLocationOperand(true, -fsaveLocation, 4);
540          inst.insertBefore(MIR_FSave.create(IA32_FNSAVE, M));
541        }
542      }
543    
544      /**
545       * Insert code into the epilogue to restore the floating point state.
546       *
547       * @param inst the return instruction after the epilogue.
548       */
549      private void restoreFloatingPointState(Instruction inst) {
550        if (ArchConstants.SSE2_FULL) {
551          PhysicalRegisterSet phys = ir.regpool.getPhysicalRegisterSet();
552          for (int i=0; i < 8; i++) {
553            inst.insertBefore(MIR_Move.create(IA32_MOVQ,
554                new RegisterOperand(phys.getFPR(i), TypeReference.Double),
555                new StackLocationOperand(true, -fsaveLocation + (i * 8), 8)));
556          }
557        } else {
558          Operand M = new StackLocationOperand(true, -fsaveLocation, 4);
559          inst.insertBefore(MIR_FSave.create(IA32_FRSTOR, M));
560        }
561      }
562    
563      /**
564       * Insert code into the prologue to save all volatile
565       * registers.
566       *
567       * @param inst the first instruction after the prologue.
568       */
569      private void saveVolatiles(Instruction inst) {
570        PhysicalRegisterSet phys = ir.regpool.getPhysicalRegisterSet();
571    
572        // Save each GPR.
573        int i = 0;
574        for (Enumeration<Register> e = phys.enumerateVolatileGPRs(); e.hasMoreElements(); i++) {
575          Register r = e.nextElement();
576          int location = saveVolatileGPRLocation[i];
577          Operand M = new StackLocationOperand(true, -location, 4);
578          inst.insertBefore(MIR_Move.create(IA32_MOV, M, new RegisterOperand(r, TypeReference.Int)));
579        }
580      }
581    
582      /**
583       * Insert code before a return instruction to restore the volatile
584       * and volatile registers.
585       *
586       * @param inst the return instruction
587       */
588      private void restoreVolatileRegisters(Instruction inst) {
589        PhysicalRegisterSet phys = ir.regpool.getPhysicalRegisterSet();
590    
591        // Restore every GPR
592        int i = 0;
593        for (Enumeration<Register> e = phys.enumerateVolatileGPRs(); e.hasMoreElements(); i++) {
594          Register r = e.nextElement();
595          int location = saveVolatileGPRLocation[i];
596          Operand M = new StackLocationOperand(true, -location, 4);
597          inst.insertBefore(MIR_Move.create(IA32_MOV, new RegisterOperand(r, TypeReference.Int), M));
598        }
599      }
600    
601      /**
602       * Insert the epilogue before a particular return instruction.
603       *
604       * @param ret the return instruction.
605       */
606      private void insertEpilogue(Instruction ret) {
607        // 1. Restore any saved registers
608        if (ir.compiledMethod.isSaveVolatile()) {
609          restoreVolatileRegisters(ret);
610          restoreFloatingPointState(ret);
611        }
612        restoreNonVolatiles(ret);
613    
614        // 2. Restore caller's stackpointer and framepointer
615        int frameSize = getFrameFixedSize();
616        ret.insertBefore(MIR_UnaryNoRes.create(REQUIRE_ESP, IC(frameSize)));
617        MemoryOperand fpHome =
618            MemoryOperand.BD(ir.regpool.makeTROp(),
619                                 ArchEntrypoints.framePointerField.getOffset(),
620                                 (byte) WORDSIZE,
621                                 null,
622                                 null);
623        ret.insertBefore(MIR_Nullary.create(IA32_POP, fpHome));
624      }
625    
626      @Override
627      public void replaceOperandWithSpillLocation(Instruction s, RegisterOperand symb) {
628    
629        // Get the spill location previously assigned to the symbolic
630        // register.
631        int location = RegisterAllocatorState.getSpill(symb.getRegister());
632    
633        // Create a memory operand M representing the spill location.
634        int size;
635        if (ArchConstants.SSE2_FULL) {
636          size = symb.getType().getMemoryBytes();
637          if (size < 4)
638            size = 4;
639        } else {
640          int type = PhysicalRegisterSet.getPhysicalRegisterType(symb.getRegister());
641          size = PhysicalRegisterSet.getSpillSize(type);
642        }
643        StackLocationOperand M = new StackLocationOperand(true, -location, (byte) size);
644    
645        M = new StackLocationOperand(true, -location, (byte) size);
646    
647        // replace the register operand with the memory operand
648        s.replaceOperand(symb, M);
649      }
650    
651      /**
652       * Does a memory operand hold a symbolic register?
653       */
654      private boolean hasSymbolicRegister(MemoryOperand M) {
655        if (M.base != null && !M.base.getRegister().isPhysical()) return true;
656        if (M.index != null && !M.index.getRegister().isPhysical()) return true;
657        return false;
658      }
659    
660      /**
661       * Is s a MOVE instruction that can be generated without resorting to
662       * scratch registers?
663       */
664      private boolean isScratchFreeMove(Instruction s) {
665        if (s.operator() != IA32_MOV) return false;
666    
667        // if we don't allow ESP to float, we will always use scratch
668        // registers in these move instructions.
669        if (!FLOAT_ESP) return false;
670    
671        Operand result = MIR_Move.getResult(s);
672        Operand value = MIR_Move.getValue(s);
673    
674        // We need scratch registers for spilled registers that appear in
675        // memory operands.
676        if (result.isMemory()) {
677          MemoryOperand M = result.asMemory();
678          if (hasSymbolicRegister(M)) return false;
679          // We will perform this transformation by changing the MOV to a PUSH
680          // or POP.  Note that IA32 cannot PUSH/POP 8-bit quantities, so
681          // disable the transformation for that case.  Also, (TODO), our
682          // assembler does not emit the prefix to allow 16-bit push/pops, so
683          // disable these too.  What's left?  32-bit only.
684          if (M.size != 4) return false;
685        }
686        if (value.isMemory()) {
687          MemoryOperand M = value.asMemory();
688          if (hasSymbolicRegister(M)) return false;
689          // We will perform this transformation by changing the MOV to a PUSH
690          // or POP.  Note that IA32 cannot PUSH/POP 8-bit quantities, so
691          // disable the transformation for that case.  Also, (TODO), our
692          // assembler does not emit the prefix to allow 16-bit push/pops, so
693          // disable these too.  What's left?  32-bit only.
694          if (M.size != 4) return false;
695        }
696        // If we get here, all is kosher.
697        return true;
698      }
699    
700      @Override
701      public boolean needScratch(Register r, Instruction s) {
702        // We never need a scratch register for a floating point value in an
703        // FMOV instruction.
704        if (r.isFloatingPoint() && s.operator == IA32_FMOV) return false;
705    
706        // never need a scratch register for a YIELDPOINT_OSR
707        if (s.operator == YIELDPOINT_OSR) return false;
708    
709        // Some MOVEs never need scratch registers
710        if (isScratchFreeMove(s)) return false;
711    
712        // If s already has a memory operand, it is illegal to introduce
713        // another.
714        if (s.hasMemoryOperand()) return true;
715    
716        // Check the architecture restrictions.
717        if (RegisterRestrictions.mustBeInRegister(r, s)) return true;
718    
719        // Otherwise, everything is OK.
720        return false;
721      }
722    
723      /**
724       * Before instruction s, insert code to adjust ESP so that it lies at a
725       * particular offset from its usual location.
726       */
727      private void moveESPBefore(Instruction s, int desiredOffset) {
728        PhysicalRegisterSet phys = ir.regpool.getPhysicalRegisterSet();
729        Register ESP = phys.getESP();
730        int delta = desiredOffset - ESPOffset;
731        if (delta != 0) {
732          if (canModifyEFLAGS(s)) {
733            s.insertBefore(MIR_BinaryAcc.create(IA32_ADD, new RegisterOperand(ESP, TypeReference.Int), IC(delta)));
734          } else {
735            MemoryOperand M =
736                MemoryOperand.BD(new RegisterOperand(ESP, TypeReference.Int),
737                                     Offset.fromIntSignExtend(delta),
738                                     (byte) 4,
739                                     null,
740                                     null);
741            s.insertBefore(MIR_Lea.create(IA32_LEA, new RegisterOperand(ESP, TypeReference.Int), M));
742          }
743          ESPOffset = desiredOffset;
744        }
745      }
746    
747      private boolean canModifyEFLAGS(Instruction s) {
748        if (PhysicalDefUse.usesEFLAGS(s.operator())) {
749          return false;
750        }
751        if (PhysicalDefUse.definesEFLAGS(s.operator())) {
752          return true;
753        }
754        if (s.operator == BBEND) return true;
755        return canModifyEFLAGS(s.nextInstructionInCodeOrder());
756      }
757    
758      /**
759       * Attempt to rewrite a move instruction to a NOP.
760       *
761       * @return true iff the transformation applies
762       */
763      private boolean mutateMoveToNop(Instruction s) {
764        Operand result = MIR_Move.getResult(s);
765        Operand val = MIR_Move.getValue(s);
766        if (result.isStackLocation() && val.isStackLocation()) {
767          if (result.similar(val)) {
768            Empty.mutate(s, NOP);
769            return true;
770          }
771        }
772        return false;
773      }
774    
775      /**
776       * Rewrite a move instruction if it has 2 memory operands.
777       * One of the 2 memory operands must be a stack location operand.  Move
778       * the SP to the appropriate location and use a push or pop instruction.
779       */
780      private void rewriteMoveInstruction(Instruction s) {
781        // first attempt to mutate the move into a noop
782        if (mutateMoveToNop(s)) return;
783    
784        Operand result = MIR_Move.getResult(s);
785        Operand val = MIR_Move.getValue(s);
786        if (result instanceof StackLocationOperand) {
787          if (val instanceof MemoryOperand || val instanceof StackLocationOperand) {
788            int offset = ((StackLocationOperand) result).getOffset();
789            byte size = ((StackLocationOperand) result).getSize();
790            offset = FPOffset2SPOffset(offset) + size;
791            moveESPBefore(s, offset);
792            MIR_UnaryNoRes.mutate(s, IA32_PUSH, val);
793          }
794        } else {
795          if (result instanceof MemoryOperand) {
796            if (val instanceof StackLocationOperand) {
797              int offset = ((StackLocationOperand) val).getOffset();
798              offset = FPOffset2SPOffset(offset);
799              moveESPBefore(s, offset);
800              MIR_Nullary.mutate(s, IA32_POP, result);
801            }
802          }
803        }
804      }
805    
806      /**
807       * Walk through the IR.  For each StackLocationOperand, replace the
808       * operand with the appropriate MemoryOperand.
809       */
810      private void rewriteStackLocations() {
811        // ESP is initially 4 bytes above where the framepointer is going to be.
812        ESPOffset = getFrameFixedSize() + 4;
813        Register ESP = ir.regpool.getPhysicalRegisterSet().getESP();
814    
815        boolean seenReturn = false;
816        for (Enumeration<Instruction> e = ir.forwardInstrEnumerator(); e.hasMoreElements();) {
817          Instruction s = e.nextElement();
818    
819          if (s.isReturn()) {
820            seenReturn = true;
821            continue;
822          }
823    
824          if (s.isBranch()) {
825            // restore ESP to home location at end of basic block.
826            moveESPBefore(s, 0);
827            continue;
828          }
829    
830          if (s.operator() == BBEND) {
831            if (seenReturn) {
832              // at a return ESP will be at FrameFixedSize,
833              seenReturn = false;
834              ESPOffset = 0;
835            } else {
836              moveESPBefore(s, 0);
837            }
838            continue;
839          }
840    
841          if (s.operator() == ADVISE_ESP) {
842            ESPOffset = MIR_UnaryNoRes.getVal(s).asIntConstant().value;
843            continue;
844          }
845    
846          if (s.operator() == REQUIRE_ESP) {
847            // ESP is required to be at the given offset from the bottom of the frame
848            moveESPBefore(s, MIR_UnaryNoRes.getVal(s).asIntConstant().value);
849            continue;
850          }
851    
852          if (s.operator() == YIELDPOINT_PROLOGUE ||
853              s.operator() == YIELDPOINT_BACKEDGE ||
854              s.operator() == YIELDPOINT_EPILOGUE) {
855            moveESPBefore(s, 0);
856            continue;
857          }
858    
859          if (s.operator() == IA32_MOV) {
860            rewriteMoveInstruction(s);
861          }
862    
863          // pop computes the effective address of its operand after ESP
864          // is incremented.  Therefore update ESPOffset before rewriting
865          // stacklocation and memory operands.
866          if (s.operator() == IA32_POP) {
867            ESPOffset += 4;
868          }
869    
870          for (Enumeration<Operand> ops = s.getOperands(); ops.hasMoreElements();) {
871            Operand op = ops.nextElement();
872            if (op instanceof StackLocationOperand) {
873              StackLocationOperand sop = (StackLocationOperand) op;
874              int offset = sop.getOffset();
875              if (sop.isFromTop()) {
876                offset = FPOffset2SPOffset(offset);
877              }
878              offset -= ESPOffset;
879              byte size = sop.getSize();
880              MemoryOperand M =
881                  MemoryOperand.BD(new RegisterOperand(ESP, TypeReference.Int),
882                                       Offset.fromIntSignExtend(offset),
883                                       size,
884                                       null,
885                                       null);
886              s.replaceOperand(op, M);
887            } else if (op instanceof MemoryOperand) {
888              MemoryOperand M = op.asMemory();
889              if ((M.base != null && M.base.getRegister() == ESP) || (M.index != null && M.index.getRegister() == ESP)) {
890                M.disp = M.disp.minus(ESPOffset);
891              }
892            }
893          }
894    
895          // push computes the effective address of its operand after ESP
896          // is decremented.  Therefore update ESPOffset after rewriting
897          // stacklocation and memory operands.
898          if (s.operator() == IA32_PUSH) {
899            ESPOffset -= 4;
900          }
901        }
902      }
903    
904      /**
905       * PRECONDITION: The final frameSize is calculated before calling this
906       * routine.
907       *
908       * @param fpOffset offset in bytes from the top of the stack frame
909       * @return offset in bytes from the stack pointer.
910       */
911      private int FPOffset2SPOffset(int fpOffset) {
912        // Note that SP = FP - frameSize + WORDSIZE;
913        // So, FP + fpOffset = SP + frameSize - WORDSIZE
914        // + fpOffset
915        return frameSize + fpOffset - WORDSIZE;
916      }
917    
918      @Override
919      public void restoreScratchRegistersBefore(Instruction s) {
920        for (Iterator<ScratchRegister> i = scratchInUse.iterator(); i.hasNext();) {
921          ScratchRegister scratch = i.next();
922    
923          if (scratch.currentContents == null) continue;
924          if (VERBOSE_DEBUG) {
925            System.out.println("RESTORE: consider " + scratch);
926          }
927          boolean removed = false;
928          boolean unloaded = false;
929          if (definedIn(scratch.scratch, s) ||
930              (s.isCall() && s.operator != CALL_SAVE_VOLATILE && scratch.scratch.isVolatile()) ||
931              (s.operator == IA32_FNINIT && scratch.scratch.isFloatingPoint()) ||
932              (s.operator == IA32_FCLEAR && scratch.scratch.isFloatingPoint())) {
933            // s defines the scratch register, so save its contents before they
934            // are killed.
935            if (VERBOSE_DEBUG) {
936              System.out.println("RESTORE : unload because defined " + scratch);
937            }
938            unloadScratchRegisterBefore(s, scratch);
939    
940            // update mapping information
941            if (VERBOSE_DEBUG) {
942              System.out.println("RSRB: End scratch interval " + scratch.scratch + " " + s);
943            }
944            scratchMap.endScratchInterval(scratch.scratch, s);
945            Register scratchContents = scratch.currentContents;
946            if (scratchContents != null) {
947              if (VERBOSE_DEBUG) {
948                System.out.println("RSRB: End symbolic interval " + scratch.currentContents + " " + s);
949              }
950              scratchMap.endSymbolicInterval(scratch.currentContents, s);
951            }
952    
953            i.remove();
954            removed = true;
955            unloaded = true;
956          }
957    
958          if (usedIn(scratch.scratch, s) ||
959              !isLegal(scratch.currentContents, scratch.scratch, s) ||
960              (s.operator == IA32_FCLEAR && scratch.scratch.isFloatingPoint())) {
961            // first spill the currents contents of the scratch register to
962            // memory
963            if (!unloaded) {
964              if (VERBOSE_DEBUG) {
965                System.out.println("RESTORE : unload because used " + scratch);
966              }
967              unloadScratchRegisterBefore(s, scratch);
968    
969              // update mapping information
970              if (VERBOSE_DEBUG) {
971                System.out.println("RSRB2: End scratch interval " + scratch.scratch + " " + s);
972              }
973              scratchMap.endScratchInterval(scratch.scratch, s);
974              Register scratchContents = scratch.currentContents;
975              if (scratchContents != null) {
976                if (VERBOSE_DEBUG) {
977                  System.out.println("RSRB2: End symbolic interval " + scratch.currentContents + " " + s);
978                }
979                scratchMap.endSymbolicInterval(scratch.currentContents, s);
980              }
981    
982            }
983            // s or some future instruction uses the scratch register,
984            // so restore the correct contents.
985            if (VERBOSE_DEBUG) {
986              System.out.println("RESTORE : reload because used " + scratch);
987            }
988            reloadScratchRegisterBefore(s, scratch);
989    
990            if (!removed) {
991              i.remove();
992              removed = true;
993            }
994          }
995        }
996      }
997    
998      /**
999       * Initialize some architecture-specific state needed for register
1000       * allocation.
1001       */
1002      @Override
1003      public void initForArch(IR ir) {
1004        PhysicalRegisterSet phys = ir.regpool.getPhysicalRegisterSet();
1005    
1006        // We reserve the last (bottom) slot in the FPR stack as a scratch register.
1007        // This allows us to do one push/pop sequence in order to use the
1008        // top of the stack as a scratch location
1009        phys.getFPR(7).reserveRegister();
1010      }
1011    
1012      @Override
1013      public boolean isSysCall(Instruction s) {
1014        return s.operator == IA32_SYSCALL;
1015      }
1016    }