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