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.mir2mc.ia32; 014 015 import java.util.Enumeration; 016 017 import org.jikesrvm.VM; 018 import org.jikesrvm.classloader.RVMMethod; 019 import org.jikesrvm.compilers.opt.ir.BBend; 020 import org.jikesrvm.compilers.opt.ir.Label; 021 import org.jikesrvm.compilers.opt.ir.MIR_BinaryAcc; 022 import org.jikesrvm.compilers.opt.ir.MIR_Branch; 023 import org.jikesrvm.compilers.opt.ir.MIR_Call; 024 import org.jikesrvm.compilers.opt.ir.MIR_Compare; 025 import org.jikesrvm.compilers.opt.ir.MIR_CondBranch; 026 import org.jikesrvm.compilers.opt.ir.MIR_CondBranch2; 027 import org.jikesrvm.compilers.opt.ir.MIR_Empty; 028 import org.jikesrvm.compilers.opt.ir.MIR_Lea; 029 import org.jikesrvm.compilers.opt.ir.MIR_Move; 030 import org.jikesrvm.compilers.opt.ir.MIR_Nullary; 031 import org.jikesrvm.compilers.opt.ir.MIR_Set; 032 import org.jikesrvm.compilers.opt.ir.MIR_Test; 033 import org.jikesrvm.compilers.opt.ir.MIR_Trap; 034 import org.jikesrvm.compilers.opt.ir.MIR_TrapIf; 035 import org.jikesrvm.compilers.opt.ir.MIR_Unary; 036 import org.jikesrvm.compilers.opt.ir.MIR_UnaryNoRes; 037 import org.jikesrvm.compilers.opt.ir.MIR_XChng; 038 import org.jikesrvm.compilers.opt.ir.NullCheck; 039 import org.jikesrvm.compilers.opt.ir.BasicBlock; 040 import org.jikesrvm.compilers.opt.ir.IR; 041 import org.jikesrvm.compilers.opt.ir.IRTools; 042 import org.jikesrvm.compilers.opt.ir.Instruction; 043 044 import static org.jikesrvm.compilers.opt.ir.Operators.ADVISE_ESP_opcode; 045 import static org.jikesrvm.compilers.opt.ir.Operators.CALL_SAVE_VOLATILE; 046 import static org.jikesrvm.compilers.opt.ir.Operators.CALL_SAVE_VOLATILE_opcode; 047 import static org.jikesrvm.compilers.opt.ir.Operators.DUMMY_DEF_opcode; 048 import static org.jikesrvm.compilers.opt.ir.Operators.DUMMY_USE_opcode; 049 import static org.jikesrvm.compilers.opt.ir.Operators.IA32_ADD; 050 import static org.jikesrvm.compilers.opt.ir.Operators.IA32_CALL; 051 import static org.jikesrvm.compilers.opt.ir.Operators.IA32_CMP; 052 import static org.jikesrvm.compilers.opt.ir.Operators.IA32_CMPXCHG; 053 import static org.jikesrvm.compilers.opt.ir.Operators.IA32_CMPXCHG8B; 054 import static org.jikesrvm.compilers.opt.ir.Operators.IA32_FCLEAR_opcode; 055 import static org.jikesrvm.compilers.opt.ir.Operators.IA32_FFREE; 056 import static org.jikesrvm.compilers.opt.ir.Operators.IA32_FLD; 057 import static org.jikesrvm.compilers.opt.ir.Operators.IA32_FMOV_ENDING_LIVE_RANGE_opcode; 058 import static org.jikesrvm.compilers.opt.ir.Operators.IA32_FMOV_opcode; 059 import static org.jikesrvm.compilers.opt.ir.Operators.IA32_FST; 060 import static org.jikesrvm.compilers.opt.ir.Operators.IA32_FSTP; 061 import static org.jikesrvm.compilers.opt.ir.Operators.IA32_FXCH; 062 import static org.jikesrvm.compilers.opt.ir.Operators.IA32_INT; 063 import static org.jikesrvm.compilers.opt.ir.Operators.IA32_JCC; 064 import static org.jikesrvm.compilers.opt.ir.Operators.IA32_JCC2_opcode; 065 import static org.jikesrvm.compilers.opt.ir.Operators.IA32_JMP; 066 import static org.jikesrvm.compilers.opt.ir.Operators.IA32_LEA_opcode; 067 import static org.jikesrvm.compilers.opt.ir.Operators.IA32_LOCK; 068 import static org.jikesrvm.compilers.opt.ir.Operators.IA32_LOCK_CMPXCHG8B_opcode; 069 import static org.jikesrvm.compilers.opt.ir.Operators.IA32_LOCK_CMPXCHG_opcode; 070 import static org.jikesrvm.compilers.opt.ir.Operators.IA32_MOV; 071 import static org.jikesrvm.compilers.opt.ir.Operators.IA32_MOV_opcode; 072 import static org.jikesrvm.compilers.opt.ir.Operators.IA32_MOVZX__B; 073 import static org.jikesrvm.compilers.opt.ir.Operators.IA32_SET__B_opcode; 074 import static org.jikesrvm.compilers.opt.ir.Operators.IA32_SHL; 075 import static org.jikesrvm.compilers.opt.ir.Operators.IA32_TEST_opcode; 076 import static org.jikesrvm.compilers.opt.ir.Operators.IA32_TRAPIF; 077 import static org.jikesrvm.compilers.opt.ir.Operators.IA32_TRAPIF_opcode; 078 import static org.jikesrvm.compilers.opt.ir.Operators.IA32_XOR; 079 import static org.jikesrvm.compilers.opt.ir.Operators.NULL_CHECK_opcode; 080 import static org.jikesrvm.compilers.opt.ir.Operators.REQUIRE_ESP_opcode; 081 import static org.jikesrvm.compilers.opt.ir.Operators.YIELDPOINT_BACKEDGE_opcode; 082 import static org.jikesrvm.compilers.opt.ir.Operators.YIELDPOINT_EPILOGUE_opcode; 083 import static org.jikesrvm.compilers.opt.ir.Operators.YIELDPOINT_OSR_opcode; 084 import static org.jikesrvm.compilers.opt.ir.Operators.YIELDPOINT_PROLOGUE_opcode; 085 import org.jikesrvm.compilers.opt.ir.Register; 086 import org.jikesrvm.compilers.opt.ir.ia32.PhysicalDefUse; 087 import org.jikesrvm.compilers.opt.ir.ia32.PhysicalRegisterSet; 088 import org.jikesrvm.compilers.opt.ir.operand.BranchProfileOperand; 089 import org.jikesrvm.compilers.opt.ir.operand.IntConstantOperand; 090 import org.jikesrvm.compilers.opt.ir.operand.LocationOperand; 091 import org.jikesrvm.compilers.opt.ir.operand.MemoryOperand; 092 import org.jikesrvm.compilers.opt.ir.operand.MethodOperand; 093 import org.jikesrvm.compilers.opt.ir.operand.Operand; 094 import org.jikesrvm.compilers.opt.ir.operand.RegisterOperand; 095 import org.jikesrvm.compilers.opt.ir.operand.TrapCodeOperand; 096 import org.jikesrvm.compilers.opt.ir.operand.ia32.IA32ConditionOperand; 097 import org.jikesrvm.runtime.ArchEntrypoints; 098 import org.jikesrvm.runtime.Entrypoints; 099 import org.jikesrvm.runtime.Magic; 100 import org.vmmagic.unboxed.Offset; 101 102 /** 103 * Final acts of MIR expansion for the IA32 architecture. 104 * Things that are expanded here (immediately before final assembly) 105 * should only be those sequences that cannot be expanded earlier 106 * due to difficulty in keeping optimizations from interfering with them. 107 * <p> 108 * One job of this phase is to handle the expansion of the remains of 109 * table switch. The code looks like a mess (which it is), but there 110 * is little choice for relocatable IA32 code that does this. And the 111 * details of this code are shared with the baseline compiler and 112 * dependent in detail on the Assembler (see {@link 113 * org.jikesrvm.compilers.common.assembler.ia32.Assembler#emitOFFSET_Imm_ImmOrLabel}). If you want to mess with 114 * it, you will probably need to mess with them as well. 115 */ 116 public class FinalMIRExpansion extends IRTools { 117 118 /** 119 * @param ir the IR to expand 120 * @return return value is garbage for IA32 121 */ 122 public static int expand(IR ir) { 123 PhysicalRegisterSet phys = ir.regpool.getPhysicalRegisterSet(); 124 125 for (Instruction next, p = ir.firstInstructionInCodeOrder(); p != null; p = next) { 126 next = p.nextInstructionInCodeOrder(); 127 p.setmcOffset(-1); 128 p.scratchObject = null; 129 130 switch (p.getOpcode()) { 131 case IA32_TEST_opcode: 132 // don't bother telling rest of compiler that memory operand 133 // must be first; we can just commute it here. 134 if (MIR_Test.getVal2(p).isMemory()) { 135 Operand tmp = MIR_Test.getClearVal1(p); 136 MIR_Test.setVal1(p, MIR_Test.getClearVal2(p)); 137 MIR_Test.setVal2(p, tmp); 138 } 139 break; 140 141 case NULL_CHECK_opcode: { 142 // mutate this into a TRAPIF, and then fall through to the the 143 // TRAP_IF case. 144 Operand ref = NullCheck.getRef(p); 145 MIR_TrapIf.mutate(p, 146 IA32_TRAPIF, 147 null, 148 ref.copy(), 149 IC(0), 150 IA32ConditionOperand.EQ(), 151 TrapCodeOperand.NullPtr()); 152 } 153 // There is no break statement here on purpose! 154 case IA32_TRAPIF_opcode: { 155 // split the basic block right before the IA32_TRAPIF 156 BasicBlock thisBlock = p.getBasicBlock(); 157 BasicBlock trap = thisBlock.createSubBlock(p.bcIndex, ir, 0f); 158 thisBlock.insertOut(trap); 159 BasicBlock nextBlock = thisBlock.splitNodeWithLinksAt(p, ir); 160 thisBlock.insertOut(trap); 161 TrapCodeOperand tc = MIR_TrapIf.getClearTrapCode(p); 162 p.remove(); 163 nextBlock.firstInstruction().setmcOffset(-1); 164 // add code to thisBlock to conditionally jump to trap 165 Instruction cmp = MIR_Compare.create(IA32_CMP, MIR_TrapIf.getVal1(p), MIR_TrapIf.getVal2(p)); 166 if (p.isMarkedAsPEI()) { 167 // The trap if was explictly marked, which means that it has 168 // a memory operand into which we've folded a null check. 169 // Actually need a GC map for both the compare and the INT. 170 cmp.markAsPEI(); 171 cmp.copyPosition(p); 172 ir.MIRInfo.gcIRMap.insertTwin(p, cmp); 173 } 174 thisBlock.appendInstruction(cmp); 175 thisBlock.appendInstruction(MIR_CondBranch.create(IA32_JCC, 176 MIR_TrapIf.getCond(p), 177 trap.makeJumpTarget(), 178 null)); 179 180 // add block at end to hold trap instruction, and 181 // insert trap sequence 182 ir.cfg.addLastInCodeOrder(trap); 183 if (tc.isArrayBounds()) { 184 // attempt to store index expression in processor object for 185 // C trap handler 186 Operand index = MIR_TrapIf.getVal2(p); 187 if (!(index instanceof RegisterOperand || index instanceof IntConstantOperand)) { 188 index = IC(0xdeadbeef); // index was spilled, and 189 // we can't get it back here. 190 } 191 MemoryOperand mo = 192 MemoryOperand.BD(ir.regpool.makeTROp(), 193 ArchEntrypoints.arrayIndexTrapParamField.getOffset(), 194 (byte) 4, 195 null, 196 null); 197 trap.appendInstruction(MIR_Move.create(IA32_MOV, mo, index.copy())); 198 } 199 // NOTE: must make p the trap instruction: it is the GC point! 200 // IMPORTANT: must also inform the GCMap that the instruction has 201 // been moved!!! 202 trap.appendInstruction(MIR_Trap.mutate(p, IA32_INT, null, tc)); 203 ir.MIRInfo.gcIRMap.moveToEnd(p); 204 205 if (tc.isStackOverflow()) { 206 // only stackoverflow traps resume at next instruction. 207 trap.appendInstruction(MIR_Branch.create(IA32_JMP, nextBlock.makeJumpTarget())); 208 } 209 } 210 break; 211 212 case IA32_FMOV_ENDING_LIVE_RANGE_opcode: { 213 Operand result = MIR_Move.getResult(p); 214 Operand value = MIR_Move.getValue(p); 215 if (result.isRegister() && value.isRegister()) { 216 if (result.similar(value)) { 217 // eliminate useless move 218 p.remove(); 219 } else { 220 int i = PhysicalRegisterSet.getFPRIndex(result.asRegister().getRegister()); 221 int j = PhysicalRegisterSet.getFPRIndex(value.asRegister().getRegister()); 222 if (i == 0) { 223 MIR_XChng.mutate(p, IA32_FXCH, result, value); 224 } else if (j == 0) { 225 MIR_XChng.mutate(p, IA32_FXCH, value, result); 226 } else { 227 expandFmov(p, phys); 228 } 229 } 230 } else { 231 expandFmov(p, phys); 232 } 233 break; 234 } 235 236 case DUMMY_DEF_opcode: 237 case DUMMY_USE_opcode: 238 case REQUIRE_ESP_opcode: 239 case ADVISE_ESP_opcode: 240 p.remove(); 241 break; 242 243 case IA32_FMOV_opcode: 244 expandFmov(p, phys); 245 break; 246 247 case IA32_MOV_opcode: 248 // Replace result = IA32_MOV 0 with result = IA32_XOR result, result 249 if (MIR_Move.getResult(p).isRegister() && 250 MIR_Move.getValue(p).isIntConstant() && 251 MIR_Move.getValue(p).asIntConstant().value == 0) { 252 // Calculate what flags are defined in coming instructions before a use of a flag or BBend 253 Instruction x = next; 254 int futureDefs = 0; 255 while(!BBend.conforms(x) && !PhysicalDefUse.usesEFLAGS(x.operator)) { 256 futureDefs |= x.operator.implicitDefs; 257 x = x.nextInstructionInCodeOrder(); 258 } 259 // If the flags will be destroyed prior to use or we reached the end of the basic block 260 if (BBend.conforms(x) || 261 (futureDefs & PhysicalDefUse.maskAF_CF_OF_PF_SF_ZF) == PhysicalDefUse.maskAF_CF_OF_PF_SF_ZF) { 262 Operand result = MIR_Move.getClearResult(p); 263 MIR_BinaryAcc.mutate(p, IA32_XOR, result, result.copy()); 264 } 265 } 266 break; 267 268 case IA32_SET__B_opcode: 269 // Replace <cmp>, set__b, movzx__b with xor, <cmp>, set__b 270 if (MIR_Set.getResult(p).isRegister() && 271 MIR_Unary.conforms(next) && 272 (next.operator() == IA32_MOVZX__B) && 273 MIR_Unary.getResult(next).isRegister() && 274 MIR_Unary.getVal(next).similar(MIR_Unary.getResult(next)) && 275 MIR_Unary.getVal(next).similar(MIR_Set.getResult(p))) { 276 // Find instruction in this basic block that defines flags 277 Instruction x = p.prevInstructionInCodeOrder(); 278 Operand result = MIR_Unary.getResult(next); 279 boolean foundCmp = false; 280 outer: 281 while(!Label.conforms(x)) { 282 Enumeration<Operand> e = x.getUses(); 283 while(e.hasMoreElements()) { 284 // We can't use an xor to clear the register if that register is 285 // used by the <cmp> or intervening instruction 286 if (e.nextElement().similar(result)) { 287 break outer; 288 } 289 } 290 if (PhysicalDefUse.definesEFLAGS(x.operator) && 291 !PhysicalDefUse.usesEFLAGS(x.operator)) { 292 // we found a <cmp> that doesn't use the result or the flags 293 // that would be clobbered by the xor 294 foundCmp = true; 295 break outer; 296 } 297 x = x.prevInstructionInCodeOrder(); 298 } 299 if (foundCmp) { 300 // We found the <cmp>, mutate the movzx__b into an xor and insert it before the <cmp> 301 next.remove(); 302 MIR_BinaryAcc.mutate(next, IA32_XOR, result, MIR_Unary.getVal(next)); 303 x.insertBefore(next); 304 // get ready for the next instruction 305 next = p.nextInstructionInCodeOrder(); 306 } 307 } 308 break; 309 310 case IA32_LEA_opcode: { 311 // Sometimes we're over eager in BURS in using LEAs and after register 312 // allocation we can simplify to the accumulate form 313 // replace reg1 = LEA [reg1 + reg2] with reg1 = reg1 + reg2 314 // replace reg1 = LEA [reg1 + c1] with reg1 = reg1 + c1 315 // replace reg1 = LEA [reg1 << c1] with reg1 = reg1 << c1 316 MemoryOperand value = MIR_Lea.getValue(p); 317 RegisterOperand result = MIR_Lea.getResult(p); 318 if ((value.base != null && value.base.getRegister() == result.getRegister()) || 319 (value.index != null && value.index.getRegister() == result.getRegister())) { 320 // Calculate what flags are defined in coming instructions before a use of a flag or BBend 321 Instruction x = next; 322 int futureDefs = 0; 323 while(!BBend.conforms(x) && !PhysicalDefUse.usesEFLAGS(x.operator)) { 324 futureDefs |= x.operator.implicitDefs; 325 x = x.nextInstructionInCodeOrder(); 326 } 327 // If the flags will be destroyed prior to use or we reached the end of the basic block 328 if (BBend.conforms(x) || 329 (futureDefs & PhysicalDefUse.maskAF_CF_OF_PF_SF_ZF) == PhysicalDefUse.maskAF_CF_OF_PF_SF_ZF) { 330 if (value.base != null && 331 value.index != null && value.index.getRegister() == result.getRegister() && 332 value.disp.isZero() && 333 value.scale == 0) { 334 // reg1 = lea [base + reg1] -> add reg1, base 335 MIR_BinaryAcc.mutate(p, IA32_ADD, result, value.base); 336 } else if (value.base != null && value.base.getRegister() == result.getRegister() && 337 value.index != null && 338 value.disp.isZero() && 339 value.scale == 0) { 340 // reg1 = lea [reg1 + index] -> add reg1, index 341 MIR_BinaryAcc.mutate(p, IA32_ADD, result, value.index); 342 } else if (value.base != null && value.base.getRegister() == result.getRegister() && 343 value.index == null) { 344 // reg1 = lea [reg1 + disp] -> add reg1, disp 345 MIR_BinaryAcc.mutate(p, IA32_ADD, result, IC(value.disp.toInt())); 346 } else if (value.base == null && 347 value.index != null && value.index.getRegister() == result.getRegister() && 348 value.scale == 0) { 349 // reg1 = lea [reg1 + disp] -> add reg1, disp 350 MIR_BinaryAcc.mutate(p, IA32_ADD, result, IC(value.disp.toInt())); 351 } else if (value.base == null && 352 value.index != null && value.index.getRegister() == result.getRegister() && 353 value.disp.isZero()) { 354 // reg1 = lea [reg1 << scale] -> shl reg1, scale 355 if (value.scale == 0) { 356 p.remove(); 357 } else if (value.scale == 1) { 358 MIR_BinaryAcc.mutate(p, IA32_ADD, result, value.index); 359 } else { 360 MIR_BinaryAcc.mutate(p, IA32_SHL, result, IC(value.scale)); 361 } 362 } 363 } 364 } 365 } 366 break; 367 368 case IA32_FCLEAR_opcode: 369 expandFClear(p, ir); 370 break; 371 372 case IA32_JCC2_opcode: 373 p.insertBefore(MIR_CondBranch.create(IA32_JCC, 374 MIR_CondBranch2.getCond1(p), 375 MIR_CondBranch2.getTarget1(p), 376 MIR_CondBranch2.getBranchProfile1(p))); 377 MIR_CondBranch.mutate(p, 378 IA32_JCC, 379 MIR_CondBranch2.getCond2(p), 380 MIR_CondBranch2.getTarget2(p), 381 MIR_CondBranch2.getBranchProfile2(p)); 382 break; 383 384 case CALL_SAVE_VOLATILE_opcode: 385 p.operator = IA32_CALL; 386 break; 387 388 case IA32_LOCK_CMPXCHG_opcode: 389 p.insertBefore(MIR_Empty.create(IA32_LOCK)); 390 p.operator = IA32_CMPXCHG; 391 break; 392 393 case IA32_LOCK_CMPXCHG8B_opcode: 394 p.insertBefore(MIR_Empty.create(IA32_LOCK)); 395 p.operator = IA32_CMPXCHG8B; 396 break; 397 398 case YIELDPOINT_PROLOGUE_opcode: 399 expandYieldpoint(p, ir, Entrypoints.optThreadSwitchFromPrologueMethod, IA32ConditionOperand.NE()); 400 break; 401 402 case YIELDPOINT_EPILOGUE_opcode: 403 expandYieldpoint(p, ir, Entrypoints.optThreadSwitchFromEpilogueMethod, IA32ConditionOperand.NE()); 404 break; 405 406 case YIELDPOINT_BACKEDGE_opcode: 407 expandYieldpoint(p, ir, Entrypoints.optThreadSwitchFromBackedgeMethod, IA32ConditionOperand.GT()); 408 break; 409 410 case YIELDPOINT_OSR_opcode: 411 // must yield, does not check threadSwitch request 412 expandUnconditionalYieldpoint(p, ir, Entrypoints.optThreadSwitchFromOsrOptMethod); 413 break; 414 415 } 416 } 417 return 0; 418 } 419 420 /** 421 * expand an FCLEAR pseudo-insruction using FFREEs. 422 * 423 * @param s the instruction to expand 424 * @param ir the containing IR 425 */ 426 private static void expandFClear(Instruction s, IR ir) { 427 int nSave = MIR_UnaryNoRes.getVal(s).asIntConstant().value; 428 int fpStackHeight = ir.MIRInfo.fpStackHeight; 429 PhysicalRegisterSet phys = ir.regpool.getPhysicalRegisterSet(); 430 431 for (int i = nSave; i < fpStackHeight; i++) { 432 Register f = phys.getFPR(i); 433 s.insertBefore(MIR_Nullary.create(IA32_FFREE, D(f))); 434 } 435 436 // Remove the FCLEAR. 437 s.remove(); 438 } 439 440 /** 441 * expand an FMOV pseudo-insruction. 442 * 443 * @param s the instruction to expand 444 * @param phys controlling physical register set 445 */ 446 private static void expandFmov(Instruction s, PhysicalRegisterSet phys) { 447 Operand result = MIR_Move.getResult(s); 448 Operand value = MIR_Move.getValue(s); 449 450 if (result.isRegister() && value.isRegister()) { 451 if (result.similar(value)) { 452 // eliminate useless move 453 s.remove(); 454 } else { 455 int i = PhysicalRegisterSet.getFPRIndex(result.asRegister().getRegister()); 456 int j = PhysicalRegisterSet.getFPRIndex(value.asRegister().getRegister()); 457 if (j == 0) { 458 // We have FMOV Fi, F0 459 // Expand as: 460 // FST F(i) (copy F0 to F(i)) 461 MIR_Move.mutate(s, IA32_FST, D(phys.getFPR(i)), D(phys.getFPR(0))); 462 } else { 463 // We have FMOV Fi, Fj 464 // Expand as: 465 // FLD Fj (push Fj on FP stack). 466 // FSTP F(i+1) (copy F0 to F(i+1) and then pop register stack) 467 s.insertBefore(MIR_Move.create(IA32_FLD, D(phys.getFPR(0)), value)); 468 469 MIR_Move.mutate(s, IA32_FSTP, D(phys.getFPR(i + 1)), D(phys.getFPR(0))); 470 } 471 472 } 473 } else if (value instanceof MemoryOperand) { 474 if (result instanceof MemoryOperand) { 475 // We have FMOV M1, M2 476 // Expand as: 477 // FLD M1 (push M1 on FP stack). 478 // FSTP M2 (copy F0 to M2 and pop register stack) 479 s.insertBefore(MIR_Move.create(IA32_FLD, D(phys.getFPR(0)), value)); 480 MIR_Move.mutate(s, IA32_FSTP, result, D(phys.getFPR(0))); 481 } else { 482 // We have FMOV Fi, M 483 // Expand as: 484 // FLD M (push M on FP stack). 485 // FSTP F(i+1) (copy F0 to F(i+1) and pop register stack) 486 if (VM.VerifyAssertions) VM._assert(result.isRegister()); 487 int i = PhysicalRegisterSet.getFPRIndex(result.asRegister().getRegister()); 488 s.insertBefore(MIR_Move.create(IA32_FLD, D(phys.getFPR(0)), value)); 489 MIR_Move.mutate(s, IA32_FSTP, D(phys.getFPR(i + 1)), D(phys.getFPR(0))); 490 } 491 } else { 492 // We have FMOV M, Fi 493 if (VM.VerifyAssertions) VM._assert(value.isRegister()); 494 if (VM.VerifyAssertions) { 495 VM._assert(result instanceof MemoryOperand); 496 } 497 int i = PhysicalRegisterSet.getFPRIndex(value.asRegister().getRegister()); 498 if (i != 0) { 499 // Expand as: 500 // FLD Fi (push Fi on FP stack). 501 // FSTP M (store F0 in M and pop register stack); 502 s.insertBefore(MIR_Move.create(IA32_FLD, D(phys.getFPR(0)), value)); 503 MIR_Move.mutate(s, IA32_FSTP, result, D(phys.getFPR(0))); 504 } else { 505 // Expand as: 506 // FST M (store F0 in M); 507 MIR_Move.mutate(s, IA32_FST, result, value); 508 } 509 } 510 } 511 512 private static void expandYieldpoint(Instruction s, IR ir, RVMMethod meth, IA32ConditionOperand ypCond) { 513 // split the basic block after the yieldpoint, create a new 514 // block at the end of the IR to hold the yieldpoint, 515 // remove the yieldpoint (to prepare to out it in the new block at the end) 516 BasicBlock thisBlock = s.getBasicBlock(); 517 BasicBlock nextBlock = thisBlock.splitNodeWithLinksAt(s, ir); 518 BasicBlock yieldpoint = thisBlock.createSubBlock(s.bcIndex, ir, 0); 519 thisBlock.insertOut(yieldpoint); 520 yieldpoint.insertOut(nextBlock); 521 ir.cfg.addLastInCodeOrder(yieldpoint); 522 s.remove(); 523 524 // change thread switch instruction into call to thread switch routine 525 // NOTE: must make s the call instruction: it is the GC point! 526 // must also inform the GCMap that s has been moved!!! 527 Offset offset = meth.getOffset(); 528 LocationOperand loc = new LocationOperand(offset); 529 Operand guard = TG(); 530 Operand target = MemoryOperand.D(Magic.getTocPointer().plus(offset), (byte) 4, loc, guard); 531 MIR_Call.mutate0(s, CALL_SAVE_VOLATILE, null, null, target, MethodOperand.STATIC(meth)); 532 yieldpoint.appendInstruction(s); 533 ir.MIRInfo.gcIRMap.moveToEnd(s); 534 535 yieldpoint.appendInstruction(MIR_Branch.create(IA32_JMP, nextBlock.makeJumpTarget())); 536 537 // Check to see if threadSwitch requested 538 Offset tsr = Entrypoints.takeYieldpointField.getOffset(); 539 MemoryOperand M = 540 MemoryOperand.BD(ir.regpool.makeTROp(), tsr, (byte) 4, null, null); 541 thisBlock.appendInstruction(MIR_Compare.create(IA32_CMP, M, IC(0))); 542 thisBlock.appendInstruction(MIR_CondBranch.create(IA32_JCC, 543 ypCond, 544 yieldpoint.makeJumpTarget(), 545 BranchProfileOperand.never())); 546 } 547 548 /* generate yieldpoint without checking threadSwith request 549 */ 550 private static void expandUnconditionalYieldpoint(Instruction s, IR ir, RVMMethod meth) { 551 // split the basic block after the yieldpoint, create a new 552 // block at the end of the IR to hold the yieldpoint, 553 // remove the yieldpoint (to prepare to out it in the new block at the end) 554 BasicBlock thisBlock = s.getBasicBlock(); 555 BasicBlock nextBlock = thisBlock.splitNodeWithLinksAt(s, ir); 556 BasicBlock yieldpoint = thisBlock.createSubBlock(s.bcIndex, ir); 557 thisBlock.insertOut(yieldpoint); 558 yieldpoint.insertOut(nextBlock); 559 ir.cfg.addLastInCodeOrder(yieldpoint); 560 s.remove(); 561 562 // change thread switch instruction into call to thread switch routine 563 // NOTE: must make s the call instruction: it is the GC point! 564 // must also inform the GCMap that s has been moved!!! 565 Offset offset = meth.getOffset(); 566 LocationOperand loc = new LocationOperand(offset); 567 Operand guard = TG(); 568 Operand target = MemoryOperand.D(Magic.getTocPointer().plus(offset), (byte) 4, loc, guard); 569 MIR_Call.mutate0(s, CALL_SAVE_VOLATILE, null, null, target, MethodOperand.STATIC(meth)); 570 yieldpoint.appendInstruction(s); 571 ir.MIRInfo.gcIRMap.moveToEnd(s); 572 573 yieldpoint.appendInstruction(MIR_Branch.create(IA32_JMP, nextBlock.makeJumpTarget())); 574 575 // make a jump to yield block 576 thisBlock.appendInstruction(MIR_Branch.create(IA32_JMP, yieldpoint.makeJumpTarget())); 577 } 578 }