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 }