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 static org.jikesrvm.SizeConstants.BYTES_IN_ADDRESS;
016    
017    import java.util.Enumeration;
018    import org.jikesrvm.ArchitectureSpecificOpt.PhysicalRegisterSet;
019    import org.jikesrvm.VM;
020    import org.jikesrvm.classloader.InterfaceMethodSignature;
021    import org.jikesrvm.classloader.TypeReference;
022    import org.jikesrvm.compilers.opt.DefUse;
023    import org.jikesrvm.compilers.opt.ir.Call;
024    import org.jikesrvm.compilers.opt.ir.MIR_Call;
025    import org.jikesrvm.compilers.opt.ir.MIR_Move;
026    import org.jikesrvm.compilers.opt.ir.MIR_Return;
027    import org.jikesrvm.compilers.opt.ir.MIR_UnaryNoRes;
028    import org.jikesrvm.compilers.opt.ir.IR;
029    import org.jikesrvm.compilers.opt.ir.IRTools;
030    import org.jikesrvm.compilers.opt.ir.Instruction;
031    import org.jikesrvm.compilers.opt.ir.Operators;
032    import org.jikesrvm.compilers.opt.ir.Register;
033    import org.jikesrvm.compilers.opt.ir.Prologue;
034    import org.jikesrvm.compilers.opt.ir.ia32.PhysicalRegisterTools;
035    import org.jikesrvm.compilers.opt.ir.operand.LocationOperand;
036    import org.jikesrvm.compilers.opt.ir.operand.MemoryOperand;
037    import org.jikesrvm.compilers.opt.ir.operand.MethodOperand;
038    import org.jikesrvm.compilers.opt.ir.operand.Operand;
039    import org.jikesrvm.compilers.opt.ir.operand.RegisterOperand;
040    import org.jikesrvm.compilers.opt.ir.operand.StackLocationOperand;
041    import org.jikesrvm.ia32.ArchConstants;
042    import org.jikesrvm.runtime.ArchEntrypoints;
043    import org.jikesrvm.runtime.Entrypoints;
044    
045    /**
046     * This class contains IA32 calling conventions
047     * The two public methods are:
048     * <ol>
049     *  <li>expandCallingConventions(IR) which is called by the
050     *  register allocator immediately before allocation to make manifest the
051     *  use of registers by the calling convention.
052     *  <li>expandSysCall(Instruction, IR) which is called to expand
053     *  a SYSCALL HIR instruction into the appropriate sequence of
054     *  LIR instructions.
055     * </ol>
056     * <p>
057     * TODO: Much of this code could still be factored out as
058     * architecture-independent.
059     */
060    public abstract class CallingConvention extends IRTools
061        implements Operators, PhysicalRegisterConstants {
062    
063      /**
064       * Size of a word, in bytes
065       */
066      private static final int WORDSIZE = BYTES_IN_ADDRESS;
067    
068      /**
069       * Expand calling conventions to make physical registers explicit in the
070       * IR when required for calls, returns, and the prologue.
071       */
072      public static void expandCallingConventions(IR ir) {
073        // expand each call and return instruction
074        for (Instruction inst = ir.firstInstructionInCodeOrder(); inst != null; inst =
075            inst.nextInstructionInCodeOrder()) {
076          if (inst.isCall()) {
077            callExpand(inst, ir);
078          } else if (inst.isReturn()) {
079            returnExpand(inst, ir);
080          }
081        }
082    
083        // expand the prologue instruction
084        expandPrologue(ir);
085      }
086    
087      /**
088       * Expand the calling convention for a particular call instruction
089       */
090      private static void callExpand(Instruction call, IR ir) {
091        boolean isSysCall = call.operator() == IA32_SYSCALL;
092    
093        // 0. Handle the parameters
094        int parameterBytes = isSysCall ? expandParametersToSysCall(call, ir) : expandParametersToCall(call, ir);
095    
096        // 1. Clear the floating-point stack if dirty.
097        if (!ArchConstants.SSE2_FULL) {
098          if (call.operator != CALL_SAVE_VOLATILE) {
099            int FPRRegisterParams = countFPRParams(call);
100            FPRRegisterParams = Math.min(FPRRegisterParams, PhysicalRegisterSet.getNumberOfFPRParams());
101            call.insertBefore(MIR_UnaryNoRes.create(IA32_FCLEAR, IC(FPRRegisterParams)));
102          }
103        }
104    
105        // 2. Move the return value into a register
106        expandResultOfCall(call, isSysCall, ir);
107    
108        // 3. If this is an interface invocation, set up the hidden parameter
109        //    in the processor object to hold the interface signature id.
110        if (VM.BuildForIMTInterfaceInvocation) {
111          if (MIR_Call.hasMethod(call)) {
112            MethodOperand mo = MIR_Call.getMethod(call);
113            if (mo.isInterface()) {
114              InterfaceMethodSignature sig = InterfaceMethodSignature.findOrCreate(mo.getMemberRef());
115              MemoryOperand M =
116                  MemoryOperand.BD(ir.regpool.makeTROp(),
117                                       ArchEntrypoints.hiddenSignatureIdField.getOffset(),
118                                       (byte) WORDSIZE,
119                                       null,
120                                       null);
121              call.insertBefore(MIR_Move.create(IA32_MOV, M, IC(sig.getId())));
122            }
123          }
124        }
125    
126        // 4. ESP must be parameterBytes before call, will be at either parameterBytes
127        //    or 0 afterwards depending on whether or it is an RVM method or a sysCall.
128        call.insertBefore(MIR_UnaryNoRes.create(REQUIRE_ESP, IC(parameterBytes)));
129        call.insertAfter(MIR_UnaryNoRes.create(ADVISE_ESP, IC(isSysCall ? parameterBytes : 0)));
130      }
131    
132      /**
133       * Expand the calling convention for a particular return instruction
134       */
135      private static void returnExpand(Instruction ret, IR ir) {
136        PhysicalRegisterSet phys = ir.regpool.getPhysicalRegisterSet();
137    
138        if (MIR_Return.hasVal(ret)) {
139          Operand symb1 = MIR_Return.getClearVal(ret);
140          MIR_Return.setVal(ret, null);
141          TypeReference type = symb1.getType();
142          if (type.isFloatType() || type.isDoubleType()) {
143            Register r = phys.getReturnFPR();
144            RegisterOperand rOp = new RegisterOperand(r, type);
145            if (ArchConstants.SSE2_FULL) {
146              if (type.isFloatType()) {
147                ret.insertBefore(MIR_Move.create(IA32_MOVSS, rOp, symb1));
148              } else {
149                ret.insertBefore(MIR_Move.create(IA32_MOVSD, rOp, symb1));
150              }
151            } else {
152              ret.insertBefore(MIR_Move.create(IA32_FMOV, rOp, symb1));
153            }
154            MIR_Return.setVal(ret, rOp.copyD2U());
155          } else {
156            Register r = phys.getFirstReturnGPR();
157            RegisterOperand rOp = new RegisterOperand(r, type);
158            ret.insertBefore(MIR_Move.create(IA32_MOV, rOp, symb1));
159            MIR_Return.setVal(ret, rOp.copyD2U());
160          }
161        }
162    
163        if (MIR_Return.hasVal2(ret)) {
164          Operand symb2 = MIR_Return.getClearVal2(ret);
165          MIR_Return.setVal2(ret, null);
166          TypeReference type = symb2.getType();
167          Register r = phys.getSecondReturnGPR();
168          RegisterOperand rOp = new RegisterOperand(r, type);
169          ret.insertBefore(MIR_Move.create(IA32_MOV, rOp, symb2));
170          MIR_Return.setVal2(ret, rOp.copyD2U());
171        }
172    
173        // Clear the floating-point stack if dirty.
174        if (!ArchConstants.SSE2_FULL) {
175          int nSave = 0;
176          if (MIR_Return.hasVal(ret)) {
177            Operand symb1 = MIR_Return.getClearVal(ret);
178            TypeReference type = symb1.getType();
179            if (type.isFloatType() || type.isDoubleType()) {
180              nSave = 1;
181            }
182          }
183          ret.insertBefore(MIR_UnaryNoRes.create(IA32_FCLEAR, IC(nSave)));
184        }
185    
186        // Set the first 'Val' in the return instruction to hold an integer
187        // constant which is the number of words to pop from the stack while
188        // returning from this method.
189        MIR_Return.setPopBytes(ret, IC(ir.incomingParameterBytes()));
190      }
191    
192      /**
193       * Explicitly copy the result of a call instruction from the result
194       * register to the appropriate symbolic register,
195       * as defined by the calling convention.
196       */
197      private static void expandResultOfCall(Instruction call, boolean isSysCall, IR ir) {
198        PhysicalRegisterSet phys = ir.regpool.getPhysicalRegisterSet();
199    
200        // copy the first result parameter
201        if (MIR_Call.hasResult(call)) {
202          RegisterOperand result1 = MIR_Call.getClearResult(call);
203          if (result1.getType().isFloatType() || result1.getType().isDoubleType()) {
204            if (ArchConstants.SSE2_FULL && isSysCall) {
205              byte size = (byte)(result1.getType().isFloatType() ? 4 : 8);
206              RegisterOperand st0 = new RegisterOperand(phys.getST0(), result1.getType());
207              MIR_Call.setResult(call, st0); // result is in st0, set it to avoid extending the live range of st0
208              RegisterOperand pr = ir.regpool.makeTROp();
209              MemoryOperand scratch = new MemoryOperand(pr, null, (byte)0, Entrypoints.scratchStorageField.getOffset(), size, new LocationOperand(Entrypoints.scratchStorageField), null);
210    
211              Instruction pop = MIR_Move.create(IA32_FSTP, scratch, st0.copyRO());
212              call.insertAfter(pop);
213              if (result1.getType().isFloatType()) {
214                pop.insertAfter(MIR_Move.create(IA32_MOVSS, result1, scratch.copy()));
215              } else /* if (result1.type.isDoubleType()) */ {
216                pop.insertAfter(MIR_Move.create(IA32_MOVSD, result1, scratch.copy()));
217              }
218            } else {
219              Register r = phys.getReturnFPR();
220              RegisterOperand physical = new RegisterOperand(r, result1.getType());
221              MIR_Call.setResult(call, physical.copyRO()); // result is in physical, set it to avoid extending its live range
222              Instruction tmp;
223              if (ArchConstants.SSE2_FULL) {
224                if (result1.getType().isFloatType()) {
225                  tmp = MIR_Move.create(IA32_MOVSS, result1, physical);
226                } else {
227                  tmp = MIR_Move.create(IA32_MOVSD, result1, physical);
228                }
229              } else {
230                tmp = MIR_Move.create(IA32_FMOV, result1, physical);
231              }
232              call.insertAfter(tmp);
233            }
234          } else {
235            // first GPR result register
236            Register r = phys.getFirstReturnGPR();
237            RegisterOperand physical = new RegisterOperand(r, result1.getType());
238            Instruction tmp = MIR_Move.create(IA32_MOV, result1, physical);
239            call.insertAfter(tmp);
240            MIR_Call.setResult(call, physical.copyRO());  // result is in physical, set it to avoid extending its live range
241          }
242        }
243    
244        // copy the second result parameter
245        if (MIR_Call.hasResult2(call)) {
246          RegisterOperand result2 = MIR_Call.getClearResult2(call);
247          // second GPR result register
248          Register r = phys.getSecondReturnGPR();
249          RegisterOperand physical = new RegisterOperand(r, result2.getType());
250          Instruction tmp = MIR_Move.create(IA32_MOV, result2, physical);
251          call.insertAfter(tmp);
252          MIR_Call.setResult2(call, physical.copyRO());  // result is in physical, set it to avoid extending its live range
253        }
254      }
255    
256      /**
257       * Explicitly copy parameters to a call into the appropriate physical
258       * registers as defined by the calling convention.<p>
259       *
260       * Note: Assumes that ESP points to the word before the slot where the
261       * first parameter should be stored.
262       */
263      private static int expandParametersToCall(Instruction call, IR ir) {
264        int nGPRParams = 0;
265        int nFPRParams = 0;
266    
267        PhysicalRegisterSet phys = ir.regpool.getPhysicalRegisterSet();
268        // count the number FPR parameters in a pre-pass
269        int FPRRegisterParams = countFPRParams(call);
270        FPRRegisterParams = Math.min(FPRRegisterParams, PhysicalRegisterSet.getNumberOfFPRParams());
271    
272        // offset, in bytes, from the SP, for the next parameter slot on the
273        // stack
274        int parameterBytes = 0;
275    
276        // Require ESP to be at bottom of frame before a call,
277        call.insertBefore(MIR_UnaryNoRes.create(REQUIRE_ESP, IC(0)));
278    
279        // walk over each parameter
280        // must count then before we start nulling them out!
281        int numParams = MIR_Call.getNumberOfParams(call);
282        int nParamsInRegisters = 0;
283        for (int i = 0; i < numParams; i++) {
284          Operand param = MIR_Call.getClearParam(call, i);
285          MIR_Call.setParam(call, i, null);
286          TypeReference paramType = param.getType();
287          if (paramType.isFloatType() || paramType.isDoubleType()) {
288            nFPRParams++;
289            int size = paramType.isFloatType() ? 4 : 8;
290            parameterBytes -= size;
291            if (nFPRParams > PhysicalRegisterSet.getNumberOfFPRParams()) {
292              // pass the FP parameter on the stack
293              Operand M = new StackLocationOperand(false, parameterBytes, size);
294              if (ArchConstants.SSE2_FULL) {
295                if (paramType.isFloatType()) {
296                  call.insertBefore(MIR_Move.create(IA32_MOVSS, M, param));
297                } else {
298                  call.insertBefore(MIR_Move.create(IA32_MOVSD, M, param));
299                }
300              } else {
301                call.insertBefore(MIR_Move.create(IA32_FMOV, M, param));
302              }
303            } else {
304              // Pass the parameter in a register.
305              RegisterOperand real;
306              if (ArchConstants.SSE2_FULL) {
307                real = new RegisterOperand(phys.getFPRParam(nFPRParams-1), paramType);
308                if (paramType.isFloatType()) {
309                  call.insertBefore(MIR_Move.create(IA32_MOVSS, real, param));
310                } else {
311                  call.insertBefore(MIR_Move.create(IA32_MOVSD, real, param));
312                }
313              } else {
314                // Note that if k FPRs are passed in registers,
315                // the 1st goes in F(k-1),
316                // the 2nd goes in F(k-2), etc...
317                real = new RegisterOperand(phys.getFPRParam(FPRRegisterParams - nFPRParams), paramType);
318                call.insertBefore(MIR_Move.create(IA32_FMOV, real, param));
319              }
320              // Record that the call now has a use of the real register.
321              MIR_Call.setParam(call, nParamsInRegisters++, real.copy());
322            }
323          } else {
324            nGPRParams++;
325            parameterBytes -= 4;
326            if (nGPRParams > PhysicalRegisterSet.getNumberOfGPRParams()) {
327              // Too many parameters to pass in registers.  Write the
328              // parameter into the appropriate stack frame location.
329              call.insertBefore(MIR_UnaryNoRes.create(REQUIRE_ESP, IC(parameterBytes + 4)));
330              call.insertBefore(MIR_UnaryNoRes.create(IA32_PUSH, param));
331            } else {
332              // Pass the parameter in a register.
333              Register phy = phys.getGPRParam(nGPRParams - 1);
334              RegisterOperand real = new RegisterOperand(phy, paramType);
335              call.insertBefore(MIR_Move.create(IA32_MOV, real, param));
336              // Record that the call now has a use of the real register.
337              MIR_Call.setParam(call, nParamsInRegisters++, real.copy());
338            }
339          }
340        }
341        return parameterBytes;
342      }
343    
344      /**
345       * Save and restore all nonvolatile registers around a syscall.
346       * We do this in case the sys call does not respect our
347       * register conventions.<p>
348       *
349       * We save/restore all nonvolatiles and the PR, whether
350       * or not this routine uses them.  This may be a tad inefficient, but if
351       * you're making a system call, you probably don't care.<p>
352       *
353       * Side effect: changes the operator of the call instruction to
354       * IA32_CALL.
355       *
356       * @param call the sys call
357       */
358      public static void saveNonvolatilesAroundSysCall(Instruction call, IR ir) {
359        saveNonvolatilesBeforeSysCall(call, ir);
360        restoreNonvolatilesAfterSysCall(call, ir);
361        call.operator = IA32_CALL;
362      }
363    
364      /**
365       * Save all nonvolatile registers before a syscall.
366       * We do this in case the sys call does not respect our
367       * register conventions.<p>
368       *
369       * We save/restore all nonvolatiles and the PR, whether
370       * or not this routine uses them.  This may be a tad inefficient, but if
371       * you're making a system call, you probably don't care.
372       *
373       * @param call the sys call
374       */
375      static void saveNonvolatilesBeforeSysCall(Instruction call, IR ir) {
376        PhysicalRegisterSet phys = ir.regpool.getPhysicalRegisterSet();
377        StackManager sm = (StackManager) ir.stackManager;
378    
379        // get the offset into the stack frame of where to stash the first
380        // nonvolatile for this case.
381        int location = sm.getOffsetForSysCall();
382    
383        // save each non-volatile
384        for (Enumeration<Register> e = phys.enumerateNonvolatileGPRs(); e.hasMoreElements();) {
385          Register r = e.nextElement();
386          Operand M = new StackLocationOperand(true, -location, (byte) WORDSIZE);
387          call.insertBefore(MIR_Move.create(IA32_MOV, M, new RegisterOperand(r, TypeReference.Int)));
388          location += WORDSIZE;
389        }
390    
391        // save the thread register
392        Operand M = new StackLocationOperand(true, -location, (byte) WORDSIZE);
393        call.insertBefore(MIR_Move.create(IA32_MOV, M, ir.regpool.makeTROp()));
394      }
395    
396      /**
397       * Restore all nonvolatile registers after a syscall.
398       * We do this in case the sys call does not respect our
399       * register conventions.<p>
400       *
401       * We save/restore all nonvolatiles and the PR, whether
402       * or not this routine uses them.  This may be a tad inefficient, but if
403       * you're making a system call, you probably don't care.
404       *
405       * @param call the sys call
406       */
407      static void restoreNonvolatilesAfterSysCall(Instruction call, IR ir) {
408        PhysicalRegisterSet phys = ir.regpool.getPhysicalRegisterSet();
409        StackManager sm = (StackManager) ir.stackManager;
410    
411        // get the offset into the stack frame of where to stash the first
412        // nonvolatile for this case.
413        int location = sm.getOffsetForSysCall();
414    
415        // restore each non-volatile
416        for (Enumeration<Register> e = phys.enumerateNonvolatileGPRs(); e.hasMoreElements();) {
417          Register r = e.nextElement();
418          Operand M = new StackLocationOperand(true, -location, (byte) WORDSIZE);
419          call.insertAfter(MIR_Move.create(IA32_MOV, new RegisterOperand(r, TypeReference.Int), M));
420          location += WORDSIZE;
421        }
422    
423        // restore the thread register
424        Operand M = new StackLocationOperand(true, -location, (byte) WORDSIZE);
425        call.insertAfter(MIR_Move.create(IA32_MOV, ir.regpool.makeTROp(), M));
426      }
427    
428      /**
429       * Explicitly copy parameters to a system call into the appropriate physical
430       * registers as defined by the calling convention.  Note that for a system
431       * call (ie., a call to C), the order of parameters on the stack is
432       * <em> reversed </em> compared to the normal RVM calling convention<p>
433       *
434       * Note: Assumes that ESP points to the word before the slot where the
435       * first parameter should be stored.<p>
436       *
437       * TODO: much of this code is exactly the same as in expandParametersToCall().
438       *       factor out the common code.
439       *
440       */
441      private static int expandParametersToSysCall(Instruction call, IR ir) {
442        int nGPRParams = 0;
443        int nFPRParams = 0;
444        int parameterBytes = 0;
445    
446        // walk over the parameters in reverse order
447        // NOTE: All params to syscall are passed on the stack!
448        int numParams = MIR_Call.getNumberOfParams(call);
449        for (int i = numParams - 1; i >= 0; i--) {
450          Operand param = MIR_Call.getClearParam(call, i);
451          MIR_Call.setParam(call, i, null);
452          TypeReference paramType = param.getType();
453          if (paramType.isFloatType() || paramType.isDoubleType()) {
454            nFPRParams++;
455            int size = paramType.isFloatType() ? 4 : 8;
456            parameterBytes -= size;
457            Operand M = new StackLocationOperand(false, parameterBytes, size);
458            if (ArchConstants.SSE2_FULL) {
459              if (paramType.isFloatType()) {
460                call.insertBefore(MIR_Move.create(IA32_MOVSS, M, param));
461              } else {
462                call.insertBefore(MIR_Move.create(IA32_MOVSD, M, param));
463              }
464            } else {
465              call.insertBefore(MIR_Move.create(IA32_FMOV, M, param));
466            }
467          } else {
468            nGPRParams++;
469            parameterBytes -= 4;
470            call.insertBefore(MIR_UnaryNoRes.create(REQUIRE_ESP, IC(parameterBytes + 4)));
471            call.insertBefore(MIR_UnaryNoRes.create(IA32_PUSH, param));
472          }
473        }
474        return parameterBytes;
475      }
476    
477      /**
478       * We have to save/restore the non-volatile registers around syscalls,
479       * to protect ourselves from malicious C compilers and Linux kernels.<p>
480       *
481       * Although the register allocator is not yet ready to insert these
482       * spills, allocate space on the stack in preparation.<p>
483       *
484       * For now, we naively save/restore all nonvolatiles.
485       */
486      public static void allocateSpaceForSysCall(IR ir) {
487        StackManager sm = (StackManager) ir.stackManager;
488    
489        // add one to account for the processor register.
490        int nToSave = PhysicalRegisterSet.getNumberOfNonvolatileGPRs() + 1;
491    
492        sm.allocateSpaceForSysCall(nToSave);
493      }
494    
495      /**
496       * Calling convention to implement calls to native (C) routines
497       * using the Linux linkage conventions.<p>
498       */
499      public static void expandSysCall(Instruction s, IR ir) {
500        Operand ip = Call.getClearAddress(s);
501    
502        // Allocate space to save non-volatiles.
503        allocateSpaceForSysCall(ir);
504    
505        // Make sure we allocate enough space for the parameters to this call.
506        int numberParams = Call.getNumberOfParams(s);
507        int parameterWords = 0;
508        for (int i = 0; i < numberParams; i++) {
509          parameterWords++;
510          Operand op = Call.getParam(s, i);
511          parameterWords += op.getType().getStackWords();
512        }
513        // allocate space for each parameter, plus one word on the stack to
514        // hold the address of the callee.
515        ir.stackManager.allocateParameterSpace((1 + parameterWords) * 4);
516    
517        // Convert to a SYSCALL instruction with a null method operand.
518        Call.mutate0(s, SYSCALL, Call.getClearResult(s), ip, null);
519      }
520    
521      /**
522       * Count the number of FPR parameters in a call instruction.
523       */
524      private static int countFPRParams(Instruction call) {
525        int result = 0;
526        // walk over the parameters
527        int numParams = MIR_Call.getNumberOfParams(call);
528        for (int i = 0; i < numParams; i++) {
529          Operand param = MIR_Call.getParam(call, i);
530          if (param.isRegister()) {
531            RegisterOperand symb = (RegisterOperand) param;
532            if (symb.getType().isFloatType() || symb.getType().isDoubleType()) {
533              result++;
534            }
535          }
536        }
537        return result;
538      }
539    
540      /**
541       * Count the number of FPR parameters in a prologue instruction.
542       */
543      private static int countFPRParamsInPrologue(Instruction p) {
544        int result = 0;
545        // walk over the parameters
546        for (Enumeration<Operand> e = p.getDefs(); e.hasMoreElements();) {
547          Operand param = e.nextElement();
548          if (param.isRegister()) {
549            RegisterOperand symb = (RegisterOperand) param;
550            if (symb.getType().isFloatType() || symb.getType().isDoubleType()) {
551              result++;
552            }
553          }
554        }
555        return result;
556      }
557    
558      /**
559       * Expand the prologue instruction.
560       */
561      private static void expandPrologue(IR ir) {
562        boolean useDU = ir.options.getOptLevel() >= 1;
563        if (useDU) {
564          // set up register lists for dead code elimination.
565          DefUse.computeDU(ir);
566        }
567    
568        Instruction p = ir.firstInstructionInCodeOrder().
569            nextInstructionInCodeOrder();
570        if (VM.VerifyAssertions) VM._assert(p.operator == IR_PROLOGUE);
571        Instruction start = p.nextInstructionInCodeOrder();
572        PhysicalRegisterSet phys = ir.regpool.getPhysicalRegisterSet();
573    
574        int gprIndex = 0;
575        int fprIndex = 0;
576        int paramByteOffset = ir.incomingParameterBytes() + 8;
577    
578        // count the number of FPR params in a pre-pass
579        int FPRRegisterParams = countFPRParamsInPrologue(p);
580        FPRRegisterParams = Math.min(FPRRegisterParams, PhysicalRegisterSet.getNumberOfFPRParams());
581        ir.MIRInfo.fpStackHeight = Math.max(ir.MIRInfo.fpStackHeight, FPRRegisterParams);
582    
583        // deal with each parameter
584        for (Enumeration<Operand> e = p.getDefs(); e.hasMoreElements();) {
585          RegisterOperand symbOp = (RegisterOperand) e.nextElement();
586          TypeReference rType = symbOp.getType();
587          if (rType.isFloatType() || rType.isDoubleType()) {
588            int size = rType.isFloatType() ? 4 : 8;
589            paramByteOffset -= size;
590            // if optimizing, only define the register if it has uses
591            if (!useDU || symbOp.getRegister().useList != null) {
592              if (fprIndex < PhysicalRegisterSet.getNumberOfFPRParams()) {
593                // insert a MOVE symbolic register = parameter
594                // Note that if k FPRs are passed in registers,
595                // the 1st goes in F(k-1),
596                // the 2nd goes in F(k-2), etc...
597                if (ArchConstants.SSE2_FULL) {
598                  Register param = phys.getFPRParam(fprIndex);
599                  if (rType.isFloatType()) {
600                    start.insertBefore(MIR_Move.create(IA32_MOVSS, symbOp.copyRO(), F(param)));
601                  } else {
602                    start.insertBefore(MIR_Move.create(IA32_MOVSD, symbOp.copyRO(), D(param)));
603                  }
604                } else {
605                  Register param = phys.getFPRParam(FPRRegisterParams - fprIndex - 1);
606                  start.insertBefore(MIR_Move.create(IA32_FMOV, symbOp.copyRO(), D(param)));
607                }
608              } else {
609                Operand M = new StackLocationOperand(true, paramByteOffset, size);
610                if (ArchConstants.SSE2_FULL) {
611                  if (rType.isFloatType()) {
612                    start.insertBefore(MIR_Move.create(IA32_MOVSS, symbOp.copyRO(), M));
613                  } else {
614                    start.insertBefore(MIR_Move.create(IA32_MOVSD, symbOp.copyRO(), M));
615                  }
616                } else {
617                  start.insertBefore(MIR_Move.create(IA32_FMOV, symbOp.copyRO(), M));
618                }
619              }
620            }
621            fprIndex++;
622          } else {
623            // if optimizing, only define the register if it has uses
624            paramByteOffset -= 4;
625            if (!useDU || symbOp.getRegister().useList != null) {
626              // t is object, 1/2 of a long, int, short, char, byte, or boolean
627              if (gprIndex < PhysicalRegisterSet.getNumberOfGPRParams()) {
628                // to give the register allocator more freedom, we
629                // insert two move instructions to get the physical into
630                // the symbolic.  First a move from the physical to a fresh temp
631                // before start and second a move from the temp to the
632                // 'real' parameter symbolic after start.
633                RegisterOperand tmp = ir.regpool.makeTemp(TypeReference.Int);
634                Register param = phys.getGPRParam(gprIndex);
635                RegisterOperand pOp = new RegisterOperand(param, rType);
636                start.insertBefore(PhysicalRegisterTools.makeMoveInstruction(tmp, pOp));
637                Instruction m2 = PhysicalRegisterTools.makeMoveInstruction(symbOp.copyRO(), tmp.copyD2U());
638                start.insertBefore(m2);
639                start = m2;
640              } else {
641                Operand M = new StackLocationOperand(true, paramByteOffset, 4);
642                start.insertBefore(MIR_Move.create(IA32_MOV, symbOp.copyRO(), M));
643              }
644            }
645            gprIndex++;
646          }
647        }
648    
649        if (VM.VerifyAssertions && paramByteOffset != 8) {
650          VM._assert(VM.NOT_REACHED, "pb = " + paramByteOffset + "; expected 8");
651        }
652    
653        // Now that we've made the calling convention explicit in the prologue,
654        // set IR_PROLOGUE to have no defs.
655        p.replace(Prologue.create(IR_PROLOGUE, 0));
656      }
657    }