1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- 2 * vim: set ts=8 sts=4 et sw=4 tw=99: 3 * This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "jit/mips-shared/MoveEmitter-mips-shared.h" 8 9 #include "jit/MacroAssembler-inl.h" 10 11 using namespace js; 12 using namespace js::jit; 13 14 void 15 MoveEmitterMIPSShared::emit(const MoveResolver& moves) 16 { 17 if (moves.numCycles()) { 18 // Reserve stack for cycle resolution 19 masm.reserveStack(moves.numCycles() * sizeof(double)); 20 pushedAtCycle_ = masm.framePushed(); 21 } 22 23 for (size_t i = 0; i < moves.numMoves(); i++) 24 emit(moves.getMove(i)); 25 } 26 27 Address 28 MoveEmitterMIPSShared::cycleSlot(uint32_t slot, uint32_t subslot) const 29 { 30 int32_t offset = masm.framePushed() - pushedAtCycle_; 31 MOZ_ASSERT(Imm16::IsInSignedRange(offset)); 32 return Address(StackPointer, offset + slot * sizeof(double) + subslot); 33 } 34 35 int32_t 36 MoveEmitterMIPSShared::getAdjustedOffset(const MoveOperand& operand) 37 { 38 MOZ_ASSERT(operand.isMemoryOrEffectiveAddress()); 39 if (operand.base() != StackPointer) 40 return operand.disp(); 41 42 // Adjust offset if stack pointer has been moved. 43 return operand.disp() + masm.framePushed() - pushedAtStart_; 44 } 45 46 Address 47 MoveEmitterMIPSShared::getAdjustedAddress(const MoveOperand& operand) 48 { 49 return Address(operand.base(), getAdjustedOffset(operand)); 50 } 51 52 53 Register 54 MoveEmitterMIPSShared::tempReg() 55 { 56 spilledReg_ = SecondScratchReg; 57 return SecondScratchReg; 58 } 59 60 void 61 MoveEmitterMIPSShared::emitMove(const MoveOperand& from, const MoveOperand& to) 62 { 63 if (from.isGeneralReg()) { 64 // Second scratch register should not be moved by MoveEmitter. 65 MOZ_ASSERT(from.reg() != spilledReg_); 66 67 if (to.isGeneralReg()) 68 masm.movePtr(from.reg(), to.reg()); 69 else if (to.isMemory()) 70 masm.storePtr(from.reg(), getAdjustedAddress(to)); 71 else 72 MOZ_CRASH("Invalid emitMove arguments."); 73 } else if (from.isMemory()) { 74 if (to.isGeneralReg()) { 75 masm.loadPtr(getAdjustedAddress(from), to.reg()); 76 } else if (to.isMemory()) { 77 masm.loadPtr(getAdjustedAddress(from), tempReg()); 78 masm.storePtr(tempReg(), getAdjustedAddress(to)); 79 } else { 80 MOZ_CRASH("Invalid emitMove arguments."); 81 } 82 } else if (from.isEffectiveAddress()) { 83 if (to.isGeneralReg()) { 84 masm.computeEffectiveAddress(getAdjustedAddress(from), to.reg()); 85 } else if (to.isMemory()) { 86 masm.computeEffectiveAddress(getAdjustedAddress(from), tempReg()); 87 masm.storePtr(tempReg(), getAdjustedAddress(to)); 88 } else { 89 MOZ_CRASH("Invalid emitMove arguments."); 90 } 91 } else { 92 MOZ_CRASH("Invalid emitMove arguments."); 93 } 94 } 95 96 void 97 MoveEmitterMIPSShared::emitInt32Move(const MoveOperand &from, const MoveOperand &to) 98 { 99 if (from.isGeneralReg()) { 100 // Second scratch register should not be moved by MoveEmitter. 101 MOZ_ASSERT(from.reg() != spilledReg_); 102 103 if (to.isGeneralReg()) 104 masm.move32(from.reg(), to.reg()); 105 else if (to.isMemory()) 106 masm.store32(from.reg(), getAdjustedAddress(to)); 107 else 108 MOZ_CRASH("Invalid emitInt32Move arguments."); 109 } else if (from.isMemory()) { 110 if (to.isGeneralReg()) { 111 masm.load32(getAdjustedAddress(from), to.reg()); 112 } else if (to.isMemory()) { 113 masm.load32(getAdjustedAddress(from), tempReg()); 114 masm.store32(tempReg(), getAdjustedAddress(to)); 115 } else { 116 MOZ_CRASH("Invalid emitInt32Move arguments."); 117 } 118 } else if (from.isEffectiveAddress()) { 119 if (to.isGeneralReg()) { 120 masm.computeEffectiveAddress(getAdjustedAddress(from), to.reg()); 121 } else if (to.isMemory()) { 122 masm.computeEffectiveAddress(getAdjustedAddress(from), tempReg()); 123 masm.store32(tempReg(), getAdjustedAddress(to)); 124 } else { 125 MOZ_CRASH("Invalid emitInt32Move arguments."); 126 } 127 } else { 128 MOZ_CRASH("Invalid emitInt32Move arguments."); 129 } 130 } 131 132 void 133 MoveEmitterMIPSShared::emitFloat32Move(const MoveOperand& from, const MoveOperand& to) 134 { 135 // Ensure that we can use ScratchFloat32Reg in memory move. 136 MOZ_ASSERT_IF(from.isFloatReg(), from.floatReg() != ScratchFloat32Reg); 137 MOZ_ASSERT_IF(to.isFloatReg(), to.floatReg() != ScratchFloat32Reg); 138 139 if (from.isFloatReg()) { 140 if (to.isFloatReg()) { 141 masm.moveFloat32(from.floatReg(), to.floatReg()); 142 } else if (to.isGeneralReg()) { 143 // This should only be used when passing float parameter in a1,a2,a3 144 MOZ_ASSERT(to.reg() == a1 || to.reg() == a2 || to.reg() == a3); 145 masm.moveFromFloat32(from.floatReg(), to.reg()); 146 } else { 147 MOZ_ASSERT(to.isMemory()); 148 masm.storeFloat32(from.floatReg(), getAdjustedAddress(to)); 149 } 150 } else if (to.isFloatReg()) { 151 MOZ_ASSERT(from.isMemory()); 152 masm.loadFloat32(getAdjustedAddress(from), to.floatReg()); 153 } else if (to.isGeneralReg()) { 154 MOZ_ASSERT(from.isMemory()); 155 // This should only be used when passing float parameter in a1,a2,a3 156 MOZ_ASSERT(to.reg() == a1 || to.reg() == a2 || to.reg() == a3); 157 masm.loadPtr(getAdjustedAddress(from), to.reg()); 158 } else { 159 MOZ_ASSERT(from.isMemory()); 160 MOZ_ASSERT(to.isMemory()); 161 masm.loadFloat32(getAdjustedAddress(from), ScratchFloat32Reg); 162 masm.storeFloat32(ScratchFloat32Reg, getAdjustedAddress(to)); 163 } 164 } 165 166 void 167 MoveEmitterMIPSShared::emit(const MoveOp& move) 168 { 169 const MoveOperand& from = move.from(); 170 const MoveOperand& to = move.to(); 171 172 if (move.isCycleEnd() && move.isCycleBegin()) { 173 // A fun consequence of aliased registers is you can have multiple 174 // cycles at once, and one can end exactly where another begins. 175 breakCycle(from, to, move.endCycleType(), move.cycleBeginSlot()); 176 completeCycle(from, to, move.type(), move.cycleEndSlot()); 177 return; 178 } 179 180 if (move.isCycleEnd()) { 181 MOZ_ASSERT(inCycle_); 182 completeCycle(from, to, move.type(), move.cycleEndSlot()); 183 MOZ_ASSERT(inCycle_ > 0); 184 inCycle_--; 185 return; 186 } 187 188 if (move.isCycleBegin()) { 189 breakCycle(from, to, move.endCycleType(), move.cycleBeginSlot()); 190 inCycle_++; 191 } 192 193 switch (move.type()) { 194 case MoveOp::FLOAT32: 195 emitFloat32Move(from, to); 196 break; 197 case MoveOp::DOUBLE: 198 emitDoubleMove(from, to); 199 break; 200 case MoveOp::INT32: 201 emitInt32Move(from, to); 202 break; 203 case MoveOp::GENERAL: 204 emitMove(from, to); 205 break; 206 default: 207 MOZ_CRASH("Unexpected move type"); 208 } 209 } 210 211 void 212 MoveEmitterMIPSShared::assertDone() 213 { 214 MOZ_ASSERT(inCycle_ == 0); 215 } 216 217 void 218 MoveEmitterMIPSShared::finish() 219 { 220 assertDone(); 221 222 masm.freeStack(masm.framePushed() - pushedAtStart_); 223 } 224