1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/js/src/jit/mips/MoveEmitter-mips.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,330 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- 1.5 + * vim: set ts=8 sts=4 et sw=4 tw=99: 1.6 + * This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#include "jit/mips/MoveEmitter-mips.h" 1.11 + 1.12 +using namespace js; 1.13 +using namespace js::jit; 1.14 + 1.15 +MoveEmitterMIPS::MoveEmitterMIPS(MacroAssemblerMIPSCompat &masm) 1.16 + : inCycle_(false), 1.17 + masm(masm), 1.18 + pushedAtCycle_(-1), 1.19 + pushedAtSpill_(-1), 1.20 + spilledReg_(InvalidReg), 1.21 + spilledFloatReg_(InvalidFloatReg) 1.22 +{ 1.23 + pushedAtStart_ = masm.framePushed(); 1.24 +} 1.25 + 1.26 +void 1.27 +MoveEmitterMIPS::emit(const MoveResolver &moves) 1.28 +{ 1.29 + if (moves.hasCycles()) { 1.30 + // Reserve stack for cycle resolution 1.31 + masm.reserveStack(sizeof(double)); 1.32 + pushedAtCycle_ = masm.framePushed(); 1.33 + } 1.34 + 1.35 + for (size_t i = 0; i < moves.numMoves(); i++) 1.36 + emit(moves.getMove(i)); 1.37 +} 1.38 + 1.39 +MoveEmitterMIPS::~MoveEmitterMIPS() 1.40 +{ 1.41 + assertDone(); 1.42 +} 1.43 + 1.44 +Address 1.45 +MoveEmitterMIPS::cycleSlot() const 1.46 +{ 1.47 + int offset = masm.framePushed() - pushedAtCycle_; 1.48 + MOZ_ASSERT(Imm16::isInSignedRange(offset)); 1.49 + return Address(StackPointer, offset); 1.50 +} 1.51 + 1.52 +int32_t 1.53 +MoveEmitterMIPS::getAdjustedOffset(const MoveOperand &operand) 1.54 +{ 1.55 + MOZ_ASSERT(operand.isMemoryOrEffectiveAddress()); 1.56 + if (operand.base() != StackPointer) 1.57 + return operand.disp(); 1.58 + 1.59 + // Adjust offset if stack pointer has been moved. 1.60 + return operand.disp() + masm.framePushed() - pushedAtStart_; 1.61 +} 1.62 + 1.63 +Address 1.64 +MoveEmitterMIPS::getAdjustedAddress(const MoveOperand &operand) 1.65 +{ 1.66 + return Address(operand.base(), getAdjustedOffset(operand)); 1.67 +} 1.68 + 1.69 + 1.70 +Register 1.71 +MoveEmitterMIPS::tempReg() 1.72 +{ 1.73 + spilledReg_ = SecondScratchReg; 1.74 + return SecondScratchReg; 1.75 +} 1.76 + 1.77 +void 1.78 +MoveEmitterMIPS::breakCycle(const MoveOperand &from, const MoveOperand &to, MoveOp::Type type) 1.79 +{ 1.80 + // There is some pattern: 1.81 + // (A -> B) 1.82 + // (B -> A) 1.83 + // 1.84 + // This case handles (A -> B), which we reach first. We save B, then allow 1.85 + // the original move to continue. 1.86 + switch (type) { 1.87 + case MoveOp::FLOAT32: 1.88 + if (to.isMemory()) { 1.89 + FloatRegister temp = ScratchFloatReg; 1.90 + masm.loadFloat32(getAdjustedAddress(to), temp); 1.91 + masm.storeFloat32(temp, cycleSlot()); 1.92 + } else { 1.93 + masm.storeFloat32(to.floatReg(), cycleSlot()); 1.94 + } 1.95 + break; 1.96 + case MoveOp::DOUBLE: 1.97 + if (to.isMemory()) { 1.98 + FloatRegister temp = ScratchFloatReg; 1.99 + masm.loadDouble(getAdjustedAddress(to), temp); 1.100 + masm.storeDouble(temp, cycleSlot()); 1.101 + } else { 1.102 + masm.storeDouble(to.floatReg(), cycleSlot()); 1.103 + } 1.104 + break; 1.105 + case MoveOp::INT32: 1.106 + MOZ_ASSERT(sizeof(uintptr_t) == sizeof(int32_t)); 1.107 + case MoveOp::GENERAL: 1.108 + if (to.isMemory()) { 1.109 + Register temp = tempReg(); 1.110 + masm.loadPtr(getAdjustedAddress(to), temp); 1.111 + masm.storePtr(temp, cycleSlot()); 1.112 + } else { 1.113 + // Second scratch register should not be moved by MoveEmitter. 1.114 + MOZ_ASSERT(to.reg() != spilledReg_); 1.115 + masm.storePtr(to.reg(), cycleSlot()); 1.116 + } 1.117 + break; 1.118 + default: 1.119 + MOZ_ASSUME_UNREACHABLE("Unexpected move type"); 1.120 + } 1.121 +} 1.122 + 1.123 +void 1.124 +MoveEmitterMIPS::completeCycle(const MoveOperand &from, const MoveOperand &to, MoveOp::Type type) 1.125 +{ 1.126 + // There is some pattern: 1.127 + // (A -> B) 1.128 + // (B -> A) 1.129 + // 1.130 + // This case handles (B -> A), which we reach last. We emit a move from the 1.131 + // saved value of B, to A. 1.132 + switch (type) { 1.133 + case MoveOp::FLOAT32: 1.134 + if (to.isMemory()) { 1.135 + FloatRegister temp = ScratchFloatReg; 1.136 + masm.loadFloat32(cycleSlot(), temp); 1.137 + masm.storeFloat32(temp, getAdjustedAddress(to)); 1.138 + } else { 1.139 + masm.loadFloat32(cycleSlot(), to.floatReg()); 1.140 + } 1.141 + break; 1.142 + case MoveOp::DOUBLE: 1.143 + if (to.isMemory()) { 1.144 + FloatRegister temp = ScratchFloatReg; 1.145 + masm.loadDouble(cycleSlot(), temp); 1.146 + masm.storeDouble(temp, getAdjustedAddress(to)); 1.147 + } else { 1.148 + masm.loadDouble(cycleSlot(), to.floatReg()); 1.149 + } 1.150 + break; 1.151 + case MoveOp::INT32: 1.152 + MOZ_ASSERT(sizeof(uintptr_t) == sizeof(int32_t)); 1.153 + case MoveOp::GENERAL: 1.154 + if (to.isMemory()) { 1.155 + Register temp = tempReg(); 1.156 + masm.loadPtr(cycleSlot(), temp); 1.157 + masm.storePtr(temp, getAdjustedAddress(to)); 1.158 + } else { 1.159 + // Second scratch register should not be moved by MoveEmitter. 1.160 + MOZ_ASSERT(to.reg() != spilledReg_); 1.161 + masm.loadPtr(cycleSlot(), to.reg()); 1.162 + } 1.163 + break; 1.164 + default: 1.165 + MOZ_ASSUME_UNREACHABLE("Unexpected move type"); 1.166 + } 1.167 +} 1.168 + 1.169 +void 1.170 +MoveEmitterMIPS::emitMove(const MoveOperand &from, const MoveOperand &to) 1.171 +{ 1.172 + if (from.isGeneralReg()) { 1.173 + // Second scratch register should not be moved by MoveEmitter. 1.174 + MOZ_ASSERT(from.reg() != spilledReg_); 1.175 + 1.176 + if (to.isGeneralReg()) 1.177 + masm.movePtr(from.reg(), to.reg()); 1.178 + else if (to.isMemory()) 1.179 + masm.storePtr(from.reg(), getAdjustedAddress(to)); 1.180 + else 1.181 + MOZ_ASSUME_UNREACHABLE("Invalid emitMove arguments."); 1.182 + } else if (from.isMemory()) { 1.183 + if (to.isGeneralReg()) { 1.184 + masm.loadPtr(getAdjustedAddress(from), to.reg()); 1.185 + } else if (to.isMemory()) { 1.186 + masm.loadPtr(getAdjustedAddress(from), tempReg()); 1.187 + masm.storePtr(tempReg(), getAdjustedAddress(to)); 1.188 + } else { 1.189 + MOZ_ASSUME_UNREACHABLE("Invalid emitMove arguments."); 1.190 + } 1.191 + } else if (from.isEffectiveAddress()) { 1.192 + if (to.isGeneralReg()) { 1.193 + masm.computeEffectiveAddress(getAdjustedAddress(from), to.reg()); 1.194 + } else if (to.isMemory()) { 1.195 + masm.computeEffectiveAddress(getAdjustedAddress(from), tempReg()); 1.196 + masm.storePtr(tempReg(), getAdjustedAddress(to)); 1.197 + } else { 1.198 + MOZ_ASSUME_UNREACHABLE("Invalid emitMove arguments."); 1.199 + } 1.200 + } else { 1.201 + MOZ_ASSUME_UNREACHABLE("Invalid emitMove arguments."); 1.202 + } 1.203 +} 1.204 + 1.205 +void 1.206 +MoveEmitterMIPS::emitFloat32Move(const MoveOperand &from, const MoveOperand &to) 1.207 +{ 1.208 + // Ensure that we can use ScratchFloatReg in memory move. 1.209 + MOZ_ASSERT_IF(from.isFloatReg(), from.floatReg() != ScratchFloatReg); 1.210 + MOZ_ASSERT_IF(to.isFloatReg(), to.floatReg() != ScratchFloatReg); 1.211 + 1.212 + if (from.isFloatReg()) { 1.213 + if (to.isFloatReg()) { 1.214 + masm.moveFloat32(from.floatReg(), to.floatReg()); 1.215 + } else if (to.isGeneralReg()) { 1.216 + // This should only be used when passing float parameter in a1,a2,a3 1.217 + MOZ_ASSERT(to.reg() == a1 || to.reg() == a2 || to.reg() == a3); 1.218 + masm.moveFromFloat32(from.floatReg(), to.reg()); 1.219 + } else { 1.220 + MOZ_ASSERT(to.isMemory()); 1.221 + masm.storeFloat32(from.floatReg(), getAdjustedAddress(to)); 1.222 + } 1.223 + } else if (to.isFloatReg()) { 1.224 + MOZ_ASSERT(from.isMemory()); 1.225 + masm.loadFloat32(getAdjustedAddress(from), to.floatReg()); 1.226 + } else if (to.isGeneralReg()) { 1.227 + MOZ_ASSERT(from.isMemory()); 1.228 + // This should only be used when passing float parameter in a1,a2,a3 1.229 + MOZ_ASSERT(to.reg() == a1 || to.reg() == a2 || to.reg() == a3); 1.230 + masm.loadPtr(getAdjustedAddress(from), to.reg()); 1.231 + } else { 1.232 + MOZ_ASSERT(from.isMemory()); 1.233 + MOZ_ASSERT(to.isMemory()); 1.234 + masm.loadFloat32(getAdjustedAddress(from), ScratchFloatReg); 1.235 + masm.storeFloat32(ScratchFloatReg, getAdjustedAddress(to)); 1.236 + } 1.237 +} 1.238 + 1.239 +void 1.240 +MoveEmitterMIPS::emitDoubleMove(const MoveOperand &from, const MoveOperand &to) 1.241 +{ 1.242 + // Ensure that we can use ScratchFloatReg in memory move. 1.243 + MOZ_ASSERT_IF(from.isFloatReg(), from.floatReg() != ScratchFloatReg); 1.244 + MOZ_ASSERT_IF(to.isFloatReg(), to.floatReg() != ScratchFloatReg); 1.245 + 1.246 + if (from.isFloatReg()) { 1.247 + if (to.isFloatReg()) { 1.248 + masm.moveDouble(from.floatReg(), to.floatReg()); 1.249 + } else if (to.isGeneralReg()) { 1.250 + // Used for passing double parameter in a2,a3 register pair. 1.251 + // Two moves are added for one double parameter by 1.252 + // MacroAssemblerMIPSCompat::passABIArg 1.253 + if(to.reg() == a2) 1.254 + masm.moveFromDoubleLo(from.floatReg(), a2); 1.255 + else if(to.reg() == a3) 1.256 + masm.moveFromDoubleHi(from.floatReg(), a3); 1.257 + else 1.258 + MOZ_ASSUME_UNREACHABLE("Invalid emitDoubleMove arguments."); 1.259 + } else { 1.260 + MOZ_ASSERT(to.isMemory()); 1.261 + masm.storeDouble(from.floatReg(), getAdjustedAddress(to)); 1.262 + } 1.263 + } else if (to.isFloatReg()) { 1.264 + MOZ_ASSERT(from.isMemory()); 1.265 + masm.loadDouble(getAdjustedAddress(from), to.floatReg()); 1.266 + } else if (to.isGeneralReg()) { 1.267 + MOZ_ASSERT(from.isMemory()); 1.268 + // Used for passing double parameter in a2,a3 register pair. 1.269 + // Two moves are added for one double parameter by 1.270 + // MacroAssemblerMIPSCompat::passABIArg 1.271 + if(to.reg() == a2) 1.272 + masm.loadPtr(getAdjustedAddress(from), a2); 1.273 + else if(to.reg() == a3) 1.274 + masm.loadPtr(Address(from.base(), getAdjustedOffset(from) + sizeof(uint32_t)), a3); 1.275 + else 1.276 + MOZ_ASSUME_UNREACHABLE("Invalid emitDoubleMove arguments."); 1.277 + } else { 1.278 + MOZ_ASSERT(from.isMemory()); 1.279 + MOZ_ASSERT(to.isMemory()); 1.280 + masm.loadDouble(getAdjustedAddress(from), ScratchFloatReg); 1.281 + masm.storeDouble(ScratchFloatReg, getAdjustedAddress(to)); 1.282 + } 1.283 +} 1.284 + 1.285 +void 1.286 +MoveEmitterMIPS::emit(const MoveOp &move) 1.287 +{ 1.288 + const MoveOperand &from = move.from(); 1.289 + const MoveOperand &to = move.to(); 1.290 + 1.291 + if (move.isCycleEnd()) { 1.292 + MOZ_ASSERT(inCycle_); 1.293 + completeCycle(from, to, move.type()); 1.294 + inCycle_ = false; 1.295 + return; 1.296 + } 1.297 + 1.298 + if (move.isCycleBegin()) { 1.299 + MOZ_ASSERT(!inCycle_); 1.300 + breakCycle(from, to, move.endCycleType()); 1.301 + inCycle_ = true; 1.302 + } 1.303 + 1.304 + switch (move.type()) { 1.305 + case MoveOp::FLOAT32: 1.306 + emitFloat32Move(from, to); 1.307 + break; 1.308 + case MoveOp::DOUBLE: 1.309 + emitDoubleMove(from, to); 1.310 + break; 1.311 + case MoveOp::INT32: 1.312 + MOZ_ASSERT(sizeof(uintptr_t) == sizeof(int32_t)); 1.313 + case MoveOp::GENERAL: 1.314 + emitMove(from, to); 1.315 + break; 1.316 + default: 1.317 + MOZ_ASSUME_UNREACHABLE("Unexpected move type"); 1.318 + } 1.319 +} 1.320 + 1.321 +void 1.322 +MoveEmitterMIPS::assertDone() 1.323 +{ 1.324 + MOZ_ASSERT(!inCycle_); 1.325 +} 1.326 + 1.327 +void 1.328 +MoveEmitterMIPS::finish() 1.329 +{ 1.330 + assertDone(); 1.331 + 1.332 + masm.freeStack(masm.framePushed() - pushedAtStart_); 1.333 +}