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 java.util.Enumeration; 016 import java.util.Iterator; 017 import org.jikesrvm.classloader.TypeReference; 018 import org.jikesrvm.compilers.opt.OptimizingCompilerException; 019 import org.jikesrvm.compilers.opt.ir.Empty; 020 import org.jikesrvm.compilers.opt.ir.MIR_BinaryAcc; 021 import org.jikesrvm.compilers.opt.ir.MIR_FSave; 022 import org.jikesrvm.compilers.opt.ir.MIR_Lea; 023 import org.jikesrvm.compilers.opt.ir.MIR_Move; 024 import org.jikesrvm.compilers.opt.ir.MIR_Nullary; 025 import org.jikesrvm.compilers.opt.ir.MIR_TrapIf; 026 import org.jikesrvm.compilers.opt.ir.MIR_UnaryNoRes; 027 import org.jikesrvm.compilers.opt.ir.IR; 028 import org.jikesrvm.compilers.opt.ir.Instruction; 029 import org.jikesrvm.compilers.opt.ir.Operator; 030 import static org.jikesrvm.compilers.opt.ir.Operators.ADVISE_ESP; 031 import static org.jikesrvm.compilers.opt.ir.Operators.BBEND; 032 import static org.jikesrvm.compilers.opt.ir.Operators.CALL_SAVE_VOLATILE; 033 import static org.jikesrvm.compilers.opt.ir.Operators.IA32_ADD; 034 import static org.jikesrvm.compilers.opt.ir.Operators.IA32_FCLEAR; 035 import static org.jikesrvm.compilers.opt.ir.Operators.IA32_FMOV; 036 import static org.jikesrvm.compilers.opt.ir.Operators.IA32_FMOV_opcode; 037 import static org.jikesrvm.compilers.opt.ir.Operators.IA32_FNINIT; 038 import static org.jikesrvm.compilers.opt.ir.Operators.IA32_FNSAVE; 039 import static org.jikesrvm.compilers.opt.ir.Operators.IA32_FRSTOR; 040 import static org.jikesrvm.compilers.opt.ir.Operators.IA32_LEA; 041 import static org.jikesrvm.compilers.opt.ir.Operators.IA32_MOV; 042 import static org.jikesrvm.compilers.opt.ir.Operators.IA32_MOVQ; 043 import static org.jikesrvm.compilers.opt.ir.Operators.IA32_MOVSD; 044 import static org.jikesrvm.compilers.opt.ir.Operators.IA32_MOVSD_opcode; 045 import static org.jikesrvm.compilers.opt.ir.Operators.IA32_MOVSS; 046 import static org.jikesrvm.compilers.opt.ir.Operators.IA32_MOVSS_opcode; 047 import static org.jikesrvm.compilers.opt.ir.Operators.IA32_MOV_opcode; 048 import static org.jikesrvm.compilers.opt.ir.Operators.IA32_POP; 049 import static org.jikesrvm.compilers.opt.ir.Operators.IA32_PUSH; 050 import static org.jikesrvm.compilers.opt.ir.Operators.IA32_RET_opcode; 051 import static org.jikesrvm.compilers.opt.ir.Operators.IA32_SYSCALL; 052 import static org.jikesrvm.compilers.opt.ir.Operators.IA32_TRAPIF; 053 import static org.jikesrvm.compilers.opt.ir.Operators.NOP; 054 import static org.jikesrvm.compilers.opt.ir.Operators.REQUIRE_ESP; 055 import static org.jikesrvm.compilers.opt.ir.Operators.YIELDPOINT_BACKEDGE; 056 import static org.jikesrvm.compilers.opt.ir.Operators.YIELDPOINT_EPILOGUE; 057 import static org.jikesrvm.compilers.opt.ir.Operators.YIELDPOINT_OSR; 058 import static org.jikesrvm.compilers.opt.ir.Operators.YIELDPOINT_PROLOGUE; 059 import static org.jikesrvm.compilers.opt.regalloc.ia32.PhysicalRegisterConstants.DOUBLE_REG; 060 import static org.jikesrvm.compilers.opt.regalloc.ia32.PhysicalRegisterConstants.DOUBLE_VALUE; 061 import static org.jikesrvm.compilers.opt.regalloc.ia32.PhysicalRegisterConstants.FLOAT_VALUE; 062 import static org.jikesrvm.compilers.opt.regalloc.ia32.PhysicalRegisterConstants.INT_REG; 063 import static org.jikesrvm.compilers.opt.regalloc.ia32.PhysicalRegisterConstants.INT_VALUE; 064 065 import org.jikesrvm.compilers.opt.ir.Register; 066 import org.jikesrvm.compilers.opt.ir.ia32.PhysicalDefUse; 067 import org.jikesrvm.compilers.opt.ir.ia32.PhysicalRegisterSet; 068 import org.jikesrvm.compilers.opt.ir.operand.MemoryOperand; 069 import org.jikesrvm.compilers.opt.ir.operand.Operand; 070 import org.jikesrvm.compilers.opt.ir.operand.RegisterOperand; 071 import org.jikesrvm.compilers.opt.ir.operand.StackLocationOperand; 072 import org.jikesrvm.compilers.opt.ir.operand.TrapCodeOperand; 073 import org.jikesrvm.compilers.opt.ir.operand.ia32.IA32ConditionOperand; 074 import org.jikesrvm.compilers.opt.regalloc.GenericStackManager; 075 import org.jikesrvm.compilers.opt.regalloc.RegisterAllocatorState; 076 import org.jikesrvm.ia32.ArchConstants; 077 import static org.jikesrvm.ia32.StackframeLayoutConstants.STACKFRAME_ALIGNMENT; 078 import org.jikesrvm.runtime.ArchEntrypoints; 079 import org.jikesrvm.runtime.Entrypoints; 080 import org.vmmagic.unboxed.Offset; 081 082 /** 083 * Class to manage the allocation of the "compiler-specific" portion of 084 * the stackframe. This class holds only the architecture-specific 085 * functions. 086 */ 087 public abstract class StackManager extends GenericStackManager { 088 089 /** 090 * A frame offset for 108 bytes of stack space to store the 091 * floating point state in the SaveVolatile protocol. 092 */ 093 private int fsaveLocation; 094 095 /** 096 * We allow the stack pointer to float from its normal position at the 097 * bottom of the frame. This field holds the 'current' offset of the 098 * SP. 099 */ 100 private int ESPOffset = 0; 101 102 /** 103 * Should we allow the stack pointer to float in order to avoid scratch 104 * registers in move instructions. Note: as of Feb. 02, we think this 105 * is a bad idea. 106 */ 107 private static boolean FLOAT_ESP = false; 108 109 @Override 110 public final int getFrameFixedSize() { 111 return frameSize - WORDSIZE; 112 } 113 114 /** 115 * Return the size of a type of value, in bytes. 116 * NOTE: For the purpose of register allocation, an x87 FLOAT_VALUE is 64 bits! 117 * 118 * @param type one of INT_VALUE, FLOAT_VALUE, or DOUBLE_VALUE 119 */ 120 private static byte getSizeOfType(byte type) { 121 switch (type) { 122 case INT_VALUE: 123 return (byte) (WORDSIZE); 124 case FLOAT_VALUE: 125 if (ArchConstants.SSE2_FULL) return (byte) WORDSIZE; 126 case DOUBLE_VALUE: 127 return (byte) (2 * WORDSIZE); 128 default: 129 OptimizingCompilerException.TODO("getSizeOfValue: unsupported"); 130 return 0; 131 } 132 } 133 134 /** 135 * Return the move operator for a type of value. 136 * 137 * @param type one of INT_VALUE, FLOAT_VALUE, or DOUBLE_VALUE 138 */ 139 private static Operator getMoveOperator(byte type) { 140 switch (type) { 141 case INT_VALUE: 142 return IA32_MOV; 143 case DOUBLE_VALUE: 144 if (ArchConstants.SSE2_FULL) return IA32_MOVSD; 145 case FLOAT_VALUE: 146 if (ArchConstants.SSE2_FULL) return IA32_MOVSS; 147 return IA32_FMOV; 148 default: 149 OptimizingCompilerException.TODO("getMoveOperator: unsupported"); 150 return null; 151 } 152 } 153 154 @Override 155 public final int allocateNewSpillLocation(int type) { 156 157 // increment by the spill size 158 spillPointer += PhysicalRegisterSet.getSpillSize(type); 159 160 if (spillPointer + WORDSIZE > frameSize) { 161 frameSize = spillPointer + WORDSIZE; 162 } 163 return spillPointer; 164 } 165 166 @Override 167 public final void insertSpillBefore(Instruction s, Register r, byte type, int location) { 168 169 Operator move = getMoveOperator(type); 170 byte size = getSizeOfType(type); 171 RegisterOperand rOp; 172 switch (type) { 173 case FLOAT_VALUE: 174 rOp = F(r); 175 break; 176 case DOUBLE_VALUE: 177 rOp = D(r); 178 break; 179 default: 180 rOp = new RegisterOperand(r, TypeReference.Int); 181 break; 182 } 183 StackLocationOperand spill = new StackLocationOperand(true, -location, size); 184 s.insertBefore(MIR_Move.create(move, spill, rOp)); 185 } 186 187 @Override 188 public final void insertUnspillBefore(Instruction s, Register r, byte type, int location) { 189 Operator move = getMoveOperator(type); 190 byte size = getSizeOfType(type); 191 RegisterOperand rOp; 192 switch (type) { 193 case FLOAT_VALUE: 194 rOp = F(r); 195 break; 196 case DOUBLE_VALUE: 197 rOp = D(r); 198 break; 199 default: 200 rOp = new RegisterOperand(r, TypeReference.Int); 201 break; 202 } 203 StackLocationOperand spill = new StackLocationOperand(true, -location, size); 204 s.insertBefore(MIR_Move.create(move, rOp, spill)); 205 } 206 207 @Override 208 public void computeNonVolatileArea() { 209 PhysicalRegisterSet phys = ir.regpool.getPhysicalRegisterSet(); 210 211 if (ir.compiledMethod.isSaveVolatile()) { 212 // Record that we use every nonvolatile GPR 213 int numGprNv = PhysicalRegisterSet.getNumberOfNonvolatileGPRs(); 214 ir.compiledMethod.setNumberOfNonvolatileGPRs((short) numGprNv); 215 216 // set the frame size 217 frameSize += numGprNv * WORDSIZE; 218 frameSize = align(frameSize, STACKFRAME_ALIGNMENT); 219 220 // TODO!! 221 ir.compiledMethod.setNumberOfNonvolatileFPRs((short) 0); 222 223 // Record that we need a stack frame. 224 setFrameRequired(); 225 226 if (ArchConstants.SSE2_FULL) { 227 for(int i=0; i < 8; i++) { 228 fsaveLocation = allocateNewSpillLocation(DOUBLE_REG); 229 } 230 } else { 231 // Grab 108 bytes (same as 27 4-byte spills) in the stack 232 // frame, as a place to store the floating-point state with FSAVE 233 for (int i = 0; i < 27; i++) { 234 fsaveLocation = allocateNewSpillLocation(INT_REG); 235 } 236 } 237 238 // Map each volatile register to a spill location. 239 int i = 0; 240 for (Enumeration<Register> e = phys.enumerateVolatileGPRs(); e.hasMoreElements(); i++) { 241 e.nextElement(); 242 // Note that as a side effect, the following call bumps up the 243 // frame size. 244 saveVolatileGPRLocation[i] = allocateNewSpillLocation(INT_REG); 245 } 246 247 // Map each non-volatile register to a spill location. 248 i = 0; 249 for (Enumeration<Register> e = phys.enumerateNonvolatileGPRs(); e.hasMoreElements(); i++) { 250 e.nextElement(); 251 // Note that as a side effect, the following call bumps up the 252 // frame size. 253 nonVolatileGPRLocation[i] = allocateNewSpillLocation(INT_REG); 254 } 255 256 // Set the offset to find non-volatiles. 257 int gprOffset = getNonvolatileGPROffset(0); 258 ir.compiledMethod.setUnsignedNonVolatileOffset(gprOffset); 259 260 } else { 261 // Count the number of nonvolatiles used. 262 int numGprNv = 0; 263 int i = 0; 264 for (Enumeration<Register> e = phys.enumerateNonvolatileGPRs(); e.hasMoreElements();) { 265 Register r = e.nextElement(); 266 if (r.isTouched()) { 267 // Note that as a side effect, the following call bumps up the 268 // frame size. 269 nonVolatileGPRLocation[i++] = allocateNewSpillLocation(INT_REG); 270 numGprNv++; 271 } 272 } 273 // Update the OptCompiledMethod object. 274 ir.compiledMethod.setNumberOfNonvolatileGPRs((short) numGprNv); 275 if (numGprNv > 0) { 276 int gprOffset = getNonvolatileGPROffset(0); 277 ir.compiledMethod.setUnsignedNonVolatileOffset(gprOffset); 278 // record that we need a stack frame 279 setFrameRequired(); 280 } else { 281 ir.compiledMethod.setUnsignedNonVolatileOffset(0); 282 } 283 284 ir.compiledMethod.setNumberOfNonvolatileFPRs((short) 0); 285 286 } 287 } 288 289 @Override 290 public void cleanUpAndInsertEpilogue() { 291 292 Instruction inst = ir.firstInstructionInCodeOrder().nextInstructionInCodeOrder(); 293 for (; inst != null; inst = inst.nextInstructionInCodeOrder()) { 294 switch (inst.getOpcode()) { 295 case IA32_MOV_opcode: 296 // remove frivolous moves 297 Operand result = MIR_Move.getResult(inst); 298 Operand val = MIR_Move.getValue(inst); 299 if (result.similar(val)) { 300 inst = inst.remove(); 301 } 302 break; 303 case IA32_FMOV_opcode: 304 case IA32_MOVSS_opcode: 305 case IA32_MOVSD_opcode: 306 // remove frivolous moves 307 result = MIR_Move.getResult(inst); 308 val = MIR_Move.getValue(inst); 309 if (result.similar(val)) { 310 inst = inst.remove(); 311 } 312 break; 313 case IA32_RET_opcode: 314 if (frameIsRequired()) { 315 insertEpilogue(inst); 316 } 317 default: 318 break; 319 } 320 } 321 // now that the frame size is fixed, fix up the spill location code 322 rewriteStackLocations(); 323 } 324 325 /** 326 * Insert an explicit stack overflow check in the prologue <em>after</em> 327 * buying the stack frame.<p> 328 * 329 * SIDE EFFECT: mutates the plg into a trap instruction. We need to 330 * mutate so that the trap instruction is in the GC map data structures. 331 * 332 * @param plg the prologue instruction 333 */ 334 private void insertNormalStackOverflowCheck(Instruction plg) { 335 if (!ir.method.isInterruptible()) { 336 plg.remove(); 337 return; 338 } 339 340 if (ir.compiledMethod.isSaveVolatile()) { 341 return; 342 } 343 344 PhysicalRegisterSet phys = ir.regpool.getPhysicalRegisterSet(); 345 Register ESP = phys.getESP(); 346 MemoryOperand M = 347 MemoryOperand.BD(ir.regpool.makeTROp(), 348 Entrypoints.stackLimitField.getOffset(), 349 (byte) WORDSIZE, 350 null, 351 null); 352 353 // Trap if ESP <= active Thread Stack Limit 354 MIR_TrapIf.mutate(plg, 355 IA32_TRAPIF, 356 null, 357 new RegisterOperand(ESP, TypeReference.Int), 358 M, 359 IA32ConditionOperand.LE(), 360 TrapCodeOperand.StackOverflow()); 361 } 362 363 /** 364 * Insert an explicit stack overflow check in the prologue <em>before</em> 365 * buying the stack frame. 366 * SIDE EFFECT: mutates the plg into a trap instruction. We need to 367 * mutate so that the trap instruction is in the GC map data structures. 368 * 369 * @param plg the prologue instruction 370 */ 371 private void insertBigFrameStackOverflowCheck(Instruction plg) { 372 if (!ir.method.isInterruptible()) { 373 plg.remove(); 374 return; 375 } 376 377 if (ir.compiledMethod.isSaveVolatile()) { 378 return; 379 } 380 381 PhysicalRegisterSet phys = ir.regpool.getPhysicalRegisterSet(); 382 Register ESP = phys.getESP(); 383 Register ECX = phys.getECX(); 384 385 // ECX := active Thread Stack Limit 386 MemoryOperand M = 387 MemoryOperand.BD(ir.regpool.makeTROp(), 388 Entrypoints.stackLimitField.getOffset(), 389 (byte) WORDSIZE, 390 null, 391 null); 392 plg.insertBefore(MIR_Move.create(IA32_MOV, new RegisterOperand((ECX), TypeReference.Int), M)); 393 394 // ECX += frame Size 395 int frameSize = getFrameFixedSize(); 396 plg.insertBefore(MIR_BinaryAcc.create(IA32_ADD, new RegisterOperand(ECX, TypeReference.Int), IC(frameSize))); 397 // Trap if ESP <= ECX 398 MIR_TrapIf.mutate(plg, 399 IA32_TRAPIF, 400 null, 401 new RegisterOperand(ESP, TypeReference.Int), 402 new RegisterOperand(ECX, TypeReference.Int), 403 IA32ConditionOperand.LE(), 404 TrapCodeOperand.StackOverflow()); 405 } 406 407 /** 408 * Insert the prologue for a normal method. 409 * 410 * Assume we are inserting the prologue for method B called from method 411 * A. 412 * <ul> 413 * <li> Perform a stack overflow check. 414 * <li> Store a back pointer to A's frame 415 * <li> Store B's compiled method id 416 * <li> Adjust frame pointer to point to B's frame 417 * <li> Save any used non-volatile registers 418 * </ul> 419 */ 420 @Override 421 public void insertNormalPrologue() { 422 PhysicalRegisterSet phys = ir.regpool.getPhysicalRegisterSet(); 423 Register ESP = phys.getESP(); 424 MemoryOperand fpHome = 425 MemoryOperand.BD(ir.regpool.makeTROp(), 426 ArchEntrypoints.framePointerField.getOffset(), 427 (byte) WORDSIZE, 428 null, 429 null); 430 431 // the prologue instruction 432 Instruction plg = ir.firstInstructionInCodeOrder().nextInstructionInCodeOrder(); 433 // inst is the instruction immediately after the IR_PROLOGUE 434 // instruction 435 Instruction inst = plg.nextInstructionInCodeOrder(); 436 437 int frameFixedSize = getFrameFixedSize(); 438 ir.compiledMethod.setFrameFixedSize(frameFixedSize); 439 440 // I. Buy a stackframe (including overflow check) 441 // NOTE: We play a little game here. If the frame we are buying is 442 // very small (less than 256) then we can be sloppy with the 443 // stackoverflow check and actually allocate the frame in the guard 444 // region. We'll notice when this frame calls someone and take the 445 // stackoverflow in the callee. We can't do this if the frame is too big, 446 // because growing the stack in the callee and/or handling a hardware trap 447 // in this frame will require most of the guard region to complete. 448 // See libvm.C. 449 if (frameFixedSize >= 256) { 450 // 1. Insert Stack overflow check. 451 insertBigFrameStackOverflowCheck(plg); 452 453 // 2. Save caller's frame pointer 454 inst.insertBefore(MIR_UnaryNoRes.create(IA32_PUSH, fpHome)); 455 456 // 3. Set my frame pointer to current value of stackpointer 457 inst.insertBefore(MIR_Move.create(IA32_MOV, fpHome.copy(), new RegisterOperand(ESP, TypeReference.Int))); 458 459 // 4. Store my compiled method id 460 int cmid = ir.compiledMethod.getId(); 461 inst.insertBefore(MIR_UnaryNoRes.create(IA32_PUSH, IC(cmid))); 462 } else { 463 // 1. Save caller's frame pointer 464 inst.insertBefore(MIR_UnaryNoRes.create(IA32_PUSH, fpHome)); 465 466 // 2. Set my frame pointer to current value of stackpointer 467 inst.insertBefore(MIR_Move.create(IA32_MOV, fpHome.copy(), new RegisterOperand(ESP, TypeReference.Int))); 468 469 // 3. Store my compiled method id 470 int cmid = ir.compiledMethod.getId(); 471 inst.insertBefore(MIR_UnaryNoRes.create(IA32_PUSH, IC(cmid))); 472 473 // 4. Insert Stack overflow check. 474 insertNormalStackOverflowCheck(plg); 475 } 476 477 // II. Save any used volatile and non-volatile registers 478 if (ir.compiledMethod.isSaveVolatile()) { 479 saveVolatiles(inst); 480 saveFloatingPointState(inst); 481 } 482 saveNonVolatiles(inst); 483 } 484 485 /** 486 * Insert code into the prologue to save any used non-volatile 487 * registers. 488 * 489 * @param inst the first instruction after the prologue. 490 */ 491 private void saveNonVolatiles(Instruction inst) { 492 PhysicalRegisterSet phys = ir.regpool.getPhysicalRegisterSet(); 493 int nNonvolatileGPRS = ir.compiledMethod.getNumberOfNonvolatileGPRs(); 494 495 // Save each non-volatile GPR used by this method. 496 int n = nNonvolatileGPRS - 1; 497 for (Enumeration<Register> e = phys.enumerateNonvolatileGPRsBackwards(); e.hasMoreElements() && n >= 0; n--) { 498 Register nv = e.nextElement(); 499 int offset = getNonvolatileGPROffset(n); 500 Operand M = new StackLocationOperand(true, -offset, 4); 501 inst.insertBefore(MIR_Move.create(IA32_MOV, M, new RegisterOperand(nv, TypeReference.Int))); 502 } 503 } 504 505 /** 506 * Insert code before a return instruction to restore the nonvolatile 507 * registers. 508 * 509 * @param inst the return instruction 510 */ 511 private void restoreNonVolatiles(Instruction inst) { 512 PhysicalRegisterSet phys = ir.regpool.getPhysicalRegisterSet(); 513 int nNonvolatileGPRS = ir.compiledMethod.getNumberOfNonvolatileGPRs(); 514 515 int n = nNonvolatileGPRS - 1; 516 for (Enumeration<Register> e = phys.enumerateNonvolatileGPRsBackwards(); e.hasMoreElements() && n >= 0; n--) { 517 Register nv = e.nextElement(); 518 int offset = getNonvolatileGPROffset(n); 519 Operand M = new StackLocationOperand(true, -offset, 4); 520 inst.insertBefore(MIR_Move.create(IA32_MOV, new RegisterOperand(nv, TypeReference.Int), M)); 521 } 522 } 523 524 /** 525 * Insert code into the prologue to save the floating point state. 526 * 527 * @param inst the first instruction after the prologue. 528 */ 529 private void saveFloatingPointState(Instruction inst) { 530 531 if (ArchConstants.SSE2_FULL) { 532 PhysicalRegisterSet phys = ir.regpool.getPhysicalRegisterSet(); 533 for (int i=0; i < 8; i++) { 534 inst.insertBefore(MIR_Move.create(IA32_MOVQ, 535 new StackLocationOperand(true, -fsaveLocation + (i * 8), 8), 536 new RegisterOperand(phys.getFPR(i), TypeReference.Double))); 537 } 538 } else { 539 Operand M = new StackLocationOperand(true, -fsaveLocation, 4); 540 inst.insertBefore(MIR_FSave.create(IA32_FNSAVE, M)); 541 } 542 } 543 544 /** 545 * Insert code into the epilogue to restore the floating point state. 546 * 547 * @param inst the return instruction after the epilogue. 548 */ 549 private void restoreFloatingPointState(Instruction inst) { 550 if (ArchConstants.SSE2_FULL) { 551 PhysicalRegisterSet phys = ir.regpool.getPhysicalRegisterSet(); 552 for (int i=0; i < 8; i++) { 553 inst.insertBefore(MIR_Move.create(IA32_MOVQ, 554 new RegisterOperand(phys.getFPR(i), TypeReference.Double), 555 new StackLocationOperand(true, -fsaveLocation + (i * 8), 8))); 556 } 557 } else { 558 Operand M = new StackLocationOperand(true, -fsaveLocation, 4); 559 inst.insertBefore(MIR_FSave.create(IA32_FRSTOR, M)); 560 } 561 } 562 563 /** 564 * Insert code into the prologue to save all volatile 565 * registers. 566 * 567 * @param inst the first instruction after the prologue. 568 */ 569 private void saveVolatiles(Instruction inst) { 570 PhysicalRegisterSet phys = ir.regpool.getPhysicalRegisterSet(); 571 572 // Save each GPR. 573 int i = 0; 574 for (Enumeration<Register> e = phys.enumerateVolatileGPRs(); e.hasMoreElements(); i++) { 575 Register r = e.nextElement(); 576 int location = saveVolatileGPRLocation[i]; 577 Operand M = new StackLocationOperand(true, -location, 4); 578 inst.insertBefore(MIR_Move.create(IA32_MOV, M, new RegisterOperand(r, TypeReference.Int))); 579 } 580 } 581 582 /** 583 * Insert code before a return instruction to restore the volatile 584 * and volatile registers. 585 * 586 * @param inst the return instruction 587 */ 588 private void restoreVolatileRegisters(Instruction inst) { 589 PhysicalRegisterSet phys = ir.regpool.getPhysicalRegisterSet(); 590 591 // Restore every GPR 592 int i = 0; 593 for (Enumeration<Register> e = phys.enumerateVolatileGPRs(); e.hasMoreElements(); i++) { 594 Register r = e.nextElement(); 595 int location = saveVolatileGPRLocation[i]; 596 Operand M = new StackLocationOperand(true, -location, 4); 597 inst.insertBefore(MIR_Move.create(IA32_MOV, new RegisterOperand(r, TypeReference.Int), M)); 598 } 599 } 600 601 /** 602 * Insert the epilogue before a particular return instruction. 603 * 604 * @param ret the return instruction. 605 */ 606 private void insertEpilogue(Instruction ret) { 607 // 1. Restore any saved registers 608 if (ir.compiledMethod.isSaveVolatile()) { 609 restoreVolatileRegisters(ret); 610 restoreFloatingPointState(ret); 611 } 612 restoreNonVolatiles(ret); 613 614 // 2. Restore caller's stackpointer and framepointer 615 int frameSize = getFrameFixedSize(); 616 ret.insertBefore(MIR_UnaryNoRes.create(REQUIRE_ESP, IC(frameSize))); 617 MemoryOperand fpHome = 618 MemoryOperand.BD(ir.regpool.makeTROp(), 619 ArchEntrypoints.framePointerField.getOffset(), 620 (byte) WORDSIZE, 621 null, 622 null); 623 ret.insertBefore(MIR_Nullary.create(IA32_POP, fpHome)); 624 } 625 626 @Override 627 public void replaceOperandWithSpillLocation(Instruction s, RegisterOperand symb) { 628 629 // Get the spill location previously assigned to the symbolic 630 // register. 631 int location = RegisterAllocatorState.getSpill(symb.getRegister()); 632 633 // Create a memory operand M representing the spill location. 634 int size; 635 if (ArchConstants.SSE2_FULL) { 636 size = symb.getType().getMemoryBytes(); 637 if (size < 4) 638 size = 4; 639 } else { 640 int type = PhysicalRegisterSet.getPhysicalRegisterType(symb.getRegister()); 641 size = PhysicalRegisterSet.getSpillSize(type); 642 } 643 StackLocationOperand M = new StackLocationOperand(true, -location, (byte) size); 644 645 M = new StackLocationOperand(true, -location, (byte) size); 646 647 // replace the register operand with the memory operand 648 s.replaceOperand(symb, M); 649 } 650 651 /** 652 * Does a memory operand hold a symbolic register? 653 */ 654 private boolean hasSymbolicRegister(MemoryOperand M) { 655 if (M.base != null && !M.base.getRegister().isPhysical()) return true; 656 if (M.index != null && !M.index.getRegister().isPhysical()) return true; 657 return false; 658 } 659 660 /** 661 * Is s a MOVE instruction that can be generated without resorting to 662 * scratch registers? 663 */ 664 private boolean isScratchFreeMove(Instruction s) { 665 if (s.operator() != IA32_MOV) return false; 666 667 // if we don't allow ESP to float, we will always use scratch 668 // registers in these move instructions. 669 if (!FLOAT_ESP) return false; 670 671 Operand result = MIR_Move.getResult(s); 672 Operand value = MIR_Move.getValue(s); 673 674 // We need scratch registers for spilled registers that appear in 675 // memory operands. 676 if (result.isMemory()) { 677 MemoryOperand M = result.asMemory(); 678 if (hasSymbolicRegister(M)) return false; 679 // We will perform this transformation by changing the MOV to a PUSH 680 // or POP. Note that IA32 cannot PUSH/POP 8-bit quantities, so 681 // disable the transformation for that case. Also, (TODO), our 682 // assembler does not emit the prefix to allow 16-bit push/pops, so 683 // disable these too. What's left? 32-bit only. 684 if (M.size != 4) return false; 685 } 686 if (value.isMemory()) { 687 MemoryOperand M = value.asMemory(); 688 if (hasSymbolicRegister(M)) return false; 689 // We will perform this transformation by changing the MOV to a PUSH 690 // or POP. Note that IA32 cannot PUSH/POP 8-bit quantities, so 691 // disable the transformation for that case. Also, (TODO), our 692 // assembler does not emit the prefix to allow 16-bit push/pops, so 693 // disable these too. What's left? 32-bit only. 694 if (M.size != 4) return false; 695 } 696 // If we get here, all is kosher. 697 return true; 698 } 699 700 @Override 701 public boolean needScratch(Register r, Instruction s) { 702 // We never need a scratch register for a floating point value in an 703 // FMOV instruction. 704 if (r.isFloatingPoint() && s.operator == IA32_FMOV) return false; 705 706 // never need a scratch register for a YIELDPOINT_OSR 707 if (s.operator == YIELDPOINT_OSR) return false; 708 709 // Some MOVEs never need scratch registers 710 if (isScratchFreeMove(s)) return false; 711 712 // If s already has a memory operand, it is illegal to introduce 713 // another. 714 if (s.hasMemoryOperand()) return true; 715 716 // Check the architecture restrictions. 717 if (RegisterRestrictions.mustBeInRegister(r, s)) return true; 718 719 // Otherwise, everything is OK. 720 return false; 721 } 722 723 /** 724 * Before instruction s, insert code to adjust ESP so that it lies at a 725 * particular offset from its usual location. 726 */ 727 private void moveESPBefore(Instruction s, int desiredOffset) { 728 PhysicalRegisterSet phys = ir.regpool.getPhysicalRegisterSet(); 729 Register ESP = phys.getESP(); 730 int delta = desiredOffset - ESPOffset; 731 if (delta != 0) { 732 if (canModifyEFLAGS(s)) { 733 s.insertBefore(MIR_BinaryAcc.create(IA32_ADD, new RegisterOperand(ESP, TypeReference.Int), IC(delta))); 734 } else { 735 MemoryOperand M = 736 MemoryOperand.BD(new RegisterOperand(ESP, TypeReference.Int), 737 Offset.fromIntSignExtend(delta), 738 (byte) 4, 739 null, 740 null); 741 s.insertBefore(MIR_Lea.create(IA32_LEA, new RegisterOperand(ESP, TypeReference.Int), M)); 742 } 743 ESPOffset = desiredOffset; 744 } 745 } 746 747 private boolean canModifyEFLAGS(Instruction s) { 748 if (PhysicalDefUse.usesEFLAGS(s.operator())) { 749 return false; 750 } 751 if (PhysicalDefUse.definesEFLAGS(s.operator())) { 752 return true; 753 } 754 if (s.operator == BBEND) return true; 755 return canModifyEFLAGS(s.nextInstructionInCodeOrder()); 756 } 757 758 /** 759 * Attempt to rewrite a move instruction to a NOP. 760 * 761 * @return true iff the transformation applies 762 */ 763 private boolean mutateMoveToNop(Instruction s) { 764 Operand result = MIR_Move.getResult(s); 765 Operand val = MIR_Move.getValue(s); 766 if (result.isStackLocation() && val.isStackLocation()) { 767 if (result.similar(val)) { 768 Empty.mutate(s, NOP); 769 return true; 770 } 771 } 772 return false; 773 } 774 775 /** 776 * Rewrite a move instruction if it has 2 memory operands. 777 * One of the 2 memory operands must be a stack location operand. Move 778 * the SP to the appropriate location and use a push or pop instruction. 779 */ 780 private void rewriteMoveInstruction(Instruction s) { 781 // first attempt to mutate the move into a noop 782 if (mutateMoveToNop(s)) return; 783 784 Operand result = MIR_Move.getResult(s); 785 Operand val = MIR_Move.getValue(s); 786 if (result instanceof StackLocationOperand) { 787 if (val instanceof MemoryOperand || val instanceof StackLocationOperand) { 788 int offset = ((StackLocationOperand) result).getOffset(); 789 byte size = ((StackLocationOperand) result).getSize(); 790 offset = FPOffset2SPOffset(offset) + size; 791 moveESPBefore(s, offset); 792 MIR_UnaryNoRes.mutate(s, IA32_PUSH, val); 793 } 794 } else { 795 if (result instanceof MemoryOperand) { 796 if (val instanceof StackLocationOperand) { 797 int offset = ((StackLocationOperand) val).getOffset(); 798 offset = FPOffset2SPOffset(offset); 799 moveESPBefore(s, offset); 800 MIR_Nullary.mutate(s, IA32_POP, result); 801 } 802 } 803 } 804 } 805 806 /** 807 * Walk through the IR. For each StackLocationOperand, replace the 808 * operand with the appropriate MemoryOperand. 809 */ 810 private void rewriteStackLocations() { 811 // ESP is initially 4 bytes above where the framepointer is going to be. 812 ESPOffset = getFrameFixedSize() + 4; 813 Register ESP = ir.regpool.getPhysicalRegisterSet().getESP(); 814 815 boolean seenReturn = false; 816 for (Enumeration<Instruction> e = ir.forwardInstrEnumerator(); e.hasMoreElements();) { 817 Instruction s = e.nextElement(); 818 819 if (s.isReturn()) { 820 seenReturn = true; 821 continue; 822 } 823 824 if (s.isBranch()) { 825 // restore ESP to home location at end of basic block. 826 moveESPBefore(s, 0); 827 continue; 828 } 829 830 if (s.operator() == BBEND) { 831 if (seenReturn) { 832 // at a return ESP will be at FrameFixedSize, 833 seenReturn = false; 834 ESPOffset = 0; 835 } else { 836 moveESPBefore(s, 0); 837 } 838 continue; 839 } 840 841 if (s.operator() == ADVISE_ESP) { 842 ESPOffset = MIR_UnaryNoRes.getVal(s).asIntConstant().value; 843 continue; 844 } 845 846 if (s.operator() == REQUIRE_ESP) { 847 // ESP is required to be at the given offset from the bottom of the frame 848 moveESPBefore(s, MIR_UnaryNoRes.getVal(s).asIntConstant().value); 849 continue; 850 } 851 852 if (s.operator() == YIELDPOINT_PROLOGUE || 853 s.operator() == YIELDPOINT_BACKEDGE || 854 s.operator() == YIELDPOINT_EPILOGUE) { 855 moveESPBefore(s, 0); 856 continue; 857 } 858 859 if (s.operator() == IA32_MOV) { 860 rewriteMoveInstruction(s); 861 } 862 863 // pop computes the effective address of its operand after ESP 864 // is incremented. Therefore update ESPOffset before rewriting 865 // stacklocation and memory operands. 866 if (s.operator() == IA32_POP) { 867 ESPOffset += 4; 868 } 869 870 for (Enumeration<Operand> ops = s.getOperands(); ops.hasMoreElements();) { 871 Operand op = ops.nextElement(); 872 if (op instanceof StackLocationOperand) { 873 StackLocationOperand sop = (StackLocationOperand) op; 874 int offset = sop.getOffset(); 875 if (sop.isFromTop()) { 876 offset = FPOffset2SPOffset(offset); 877 } 878 offset -= ESPOffset; 879 byte size = sop.getSize(); 880 MemoryOperand M = 881 MemoryOperand.BD(new RegisterOperand(ESP, TypeReference.Int), 882 Offset.fromIntSignExtend(offset), 883 size, 884 null, 885 null); 886 s.replaceOperand(op, M); 887 } else if (op instanceof MemoryOperand) { 888 MemoryOperand M = op.asMemory(); 889 if ((M.base != null && M.base.getRegister() == ESP) || (M.index != null && M.index.getRegister() == ESP)) { 890 M.disp = M.disp.minus(ESPOffset); 891 } 892 } 893 } 894 895 // push computes the effective address of its operand after ESP 896 // is decremented. Therefore update ESPOffset after rewriting 897 // stacklocation and memory operands. 898 if (s.operator() == IA32_PUSH) { 899 ESPOffset -= 4; 900 } 901 } 902 } 903 904 /** 905 * PRECONDITION: The final frameSize is calculated before calling this 906 * routine. 907 * 908 * @param fpOffset offset in bytes from the top of the stack frame 909 * @return offset in bytes from the stack pointer. 910 */ 911 private int FPOffset2SPOffset(int fpOffset) { 912 // Note that SP = FP - frameSize + WORDSIZE; 913 // So, FP + fpOffset = SP + frameSize - WORDSIZE 914 // + fpOffset 915 return frameSize + fpOffset - WORDSIZE; 916 } 917 918 @Override 919 public void restoreScratchRegistersBefore(Instruction s) { 920 for (Iterator<ScratchRegister> i = scratchInUse.iterator(); i.hasNext();) { 921 ScratchRegister scratch = i.next(); 922 923 if (scratch.currentContents == null) continue; 924 if (VERBOSE_DEBUG) { 925 System.out.println("RESTORE: consider " + scratch); 926 } 927 boolean removed = false; 928 boolean unloaded = false; 929 if (definedIn(scratch.scratch, s) || 930 (s.isCall() && s.operator != CALL_SAVE_VOLATILE && scratch.scratch.isVolatile()) || 931 (s.operator == IA32_FNINIT && scratch.scratch.isFloatingPoint()) || 932 (s.operator == IA32_FCLEAR && scratch.scratch.isFloatingPoint())) { 933 // s defines the scratch register, so save its contents before they 934 // are killed. 935 if (VERBOSE_DEBUG) { 936 System.out.println("RESTORE : unload because defined " + scratch); 937 } 938 unloadScratchRegisterBefore(s, scratch); 939 940 // update mapping information 941 if (VERBOSE_DEBUG) { 942 System.out.println("RSRB: End scratch interval " + scratch.scratch + " " + s); 943 } 944 scratchMap.endScratchInterval(scratch.scratch, s); 945 Register scratchContents = scratch.currentContents; 946 if (scratchContents != null) { 947 if (VERBOSE_DEBUG) { 948 System.out.println("RSRB: End symbolic interval " + scratch.currentContents + " " + s); 949 } 950 scratchMap.endSymbolicInterval(scratch.currentContents, s); 951 } 952 953 i.remove(); 954 removed = true; 955 unloaded = true; 956 } 957 958 if (usedIn(scratch.scratch, s) || 959 !isLegal(scratch.currentContents, scratch.scratch, s) || 960 (s.operator == IA32_FCLEAR && scratch.scratch.isFloatingPoint())) { 961 // first spill the currents contents of the scratch register to 962 // memory 963 if (!unloaded) { 964 if (VERBOSE_DEBUG) { 965 System.out.println("RESTORE : unload because used " + scratch); 966 } 967 unloadScratchRegisterBefore(s, scratch); 968 969 // update mapping information 970 if (VERBOSE_DEBUG) { 971 System.out.println("RSRB2: End scratch interval " + scratch.scratch + " " + s); 972 } 973 scratchMap.endScratchInterval(scratch.scratch, s); 974 Register scratchContents = scratch.currentContents; 975 if (scratchContents != null) { 976 if (VERBOSE_DEBUG) { 977 System.out.println("RSRB2: End symbolic interval " + scratch.currentContents + " " + s); 978 } 979 scratchMap.endSymbolicInterval(scratch.currentContents, s); 980 } 981 982 } 983 // s or some future instruction uses the scratch register, 984 // so restore the correct contents. 985 if (VERBOSE_DEBUG) { 986 System.out.println("RESTORE : reload because used " + scratch); 987 } 988 reloadScratchRegisterBefore(s, scratch); 989 990 if (!removed) { 991 i.remove(); 992 removed = true; 993 } 994 } 995 } 996 } 997 998 /** 999 * Initialize some architecture-specific state needed for register 1000 * allocation. 1001 */ 1002 @Override 1003 public void initForArch(IR ir) { 1004 PhysicalRegisterSet phys = ir.regpool.getPhysicalRegisterSet(); 1005 1006 // We reserve the last (bottom) slot in the FPR stack as a scratch register. 1007 // This allows us to do one push/pop sequence in order to use the 1008 // top of the stack as a scratch location 1009 phys.getFPR(7).reserveRegister(); 1010 } 1011 1012 @Override 1013 public boolean isSysCall(Instruction s) { 1014 return s.operator == IA32_SYSCALL; 1015 } 1016 }