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