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