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}