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