MoveEmitter-loong64.cpp (11097B)
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/loong64/MoveEmitter-loong64.h" 8 9 #include "jit/MacroAssembler-inl.h" 10 11 using namespace js; 12 using namespace js::jit; 13 14 void MoveEmitterLOONG64::breakCycle(const MoveOperand& from, 15 const MoveOperand& to, MoveOp::Type type, 16 uint32_t slotId) { 17 // There is some pattern: 18 // (A -> B) 19 // (B -> A) 20 // 21 // This case handles (A -> B), which we reach first. We save B, then allow 22 // the original move to continue. 23 switch (type) { 24 case MoveOp::FLOAT32: 25 if (to.isMemory()) { 26 ScratchFloat32Scope fpscratch32(masm); 27 masm.loadFloat32(getAdjustedAddress(to), fpscratch32); 28 masm.storeFloat32(fpscratch32, cycleSlot(slotId)); 29 } else { 30 masm.storeFloat32(to.floatReg(), cycleSlot(slotId)); 31 } 32 break; 33 case MoveOp::DOUBLE: 34 if (to.isMemory()) { 35 ScratchDoubleScope fpscratch64(masm); 36 masm.loadDouble(getAdjustedAddress(to), fpscratch64); 37 masm.storeDouble(fpscratch64, cycleSlot(slotId)); 38 } else { 39 masm.storeDouble(to.floatReg(), cycleSlot(slotId)); 40 } 41 break; 42 case MoveOp::INT32: 43 if (to.isMemory()) { 44 UseScratchRegisterScope temps(masm); 45 Register scratch = temps.Acquire(); 46 masm.load32(getAdjustedAddress(to), scratch); 47 masm.store32(scratch, cycleSlot(0)); 48 } else { 49 masm.store32(to.reg(), cycleSlot(0)); 50 } 51 break; 52 case MoveOp::GENERAL: 53 if (to.isMemory()) { 54 UseScratchRegisterScope temps(masm); 55 Register scratch = temps.Acquire(); 56 masm.loadPtr(getAdjustedAddress(to), scratch); 57 masm.storePtr(scratch, cycleSlot(0)); 58 } else { 59 masm.storePtr(to.reg(), cycleSlot(0)); 60 } 61 break; 62 default: 63 MOZ_CRASH("Unexpected move type"); 64 } 65 } 66 67 void MoveEmitterLOONG64::completeCycle(const MoveOperand& from, 68 const MoveOperand& to, MoveOp::Type type, 69 uint32_t slotId) { 70 // There is some pattern: 71 // (A -> B) 72 // (B -> A) 73 // 74 // This case handles (B -> A), which we reach last. We emit a move from the 75 // saved value of B, to A. 76 switch (type) { 77 case MoveOp::FLOAT32: 78 if (to.isMemory()) { 79 ScratchFloat32Scope fpscratch32(masm); 80 masm.loadFloat32(cycleSlot(slotId), fpscratch32); 81 masm.storeFloat32(fpscratch32, getAdjustedAddress(to)); 82 } else { 83 masm.loadFloat32(cycleSlot(slotId), to.floatReg()); 84 } 85 break; 86 case MoveOp::DOUBLE: 87 if (to.isMemory()) { 88 ScratchDoubleScope fpscratch64(masm); 89 masm.loadDouble(cycleSlot(slotId), fpscratch64); 90 masm.storeDouble(fpscratch64, getAdjustedAddress(to)); 91 } else { 92 masm.loadDouble(cycleSlot(slotId), to.floatReg()); 93 } 94 break; 95 case MoveOp::INT32: 96 MOZ_ASSERT(slotId == 0); 97 if (to.isMemory()) { 98 UseScratchRegisterScope temps(masm); 99 Register scratch = temps.Acquire(); 100 masm.load32(cycleSlot(0), scratch); 101 masm.store32(scratch, getAdjustedAddress(to)); 102 } else { 103 masm.load32(cycleSlot(0), to.reg()); 104 } 105 break; 106 case MoveOp::GENERAL: 107 MOZ_ASSERT(slotId == 0); 108 if (to.isMemory()) { 109 UseScratchRegisterScope temps(masm); 110 Register scratch = temps.Acquire(); 111 masm.loadPtr(cycleSlot(0), scratch); 112 masm.storePtr(scratch, getAdjustedAddress(to)); 113 } else { 114 masm.loadPtr(cycleSlot(0), to.reg()); 115 } 116 break; 117 default: 118 MOZ_CRASH("Unexpected move type"); 119 } 120 } 121 122 void MoveEmitterLOONG64::emit(const MoveResolver& moves) { 123 if (moves.numCycles()) { 124 // Reserve stack for cycle resolution 125 static_assert(SpillSlotSize == 8); 126 masm.reserveStack(moves.numCycles() * SpillSlotSize); 127 pushedAtCycle_ = masm.framePushed(); 128 } 129 130 for (size_t i = 0; i < moves.numMoves(); i++) { 131 emit(moves.getMove(i)); 132 } 133 } 134 135 Address MoveEmitterLOONG64::cycleSlot(uint32_t slot, uint32_t subslot) const { 136 int32_t offset = masm.framePushed() - pushedAtCycle_; 137 MOZ_ASSERT(Imm16::IsInSignedRange(offset)); 138 return Address(StackPointer, offset + slot * sizeof(double) + subslot); 139 } 140 141 int32_t MoveEmitterLOONG64::getAdjustedOffset(const MoveOperand& operand) { 142 MOZ_ASSERT(operand.isMemoryOrEffectiveAddress()); 143 if (operand.base() != StackPointer) { 144 return operand.disp(); 145 } 146 147 // Adjust offset if stack pointer has been moved. 148 return operand.disp() + masm.framePushed() - pushedAtStart_; 149 } 150 151 Address MoveEmitterLOONG64::getAdjustedAddress(const MoveOperand& operand) { 152 return Address(operand.base(), getAdjustedOffset(operand)); 153 } 154 155 void MoveEmitterLOONG64::emitMove(const MoveOperand& from, 156 const MoveOperand& to) { 157 if (from.isGeneralReg()) { 158 if (to.isGeneralReg()) { 159 masm.movePtr(from.reg(), to.reg()); 160 } else if (to.isMemory()) { 161 masm.storePtr(from.reg(), getAdjustedAddress(to)); 162 } else { 163 MOZ_CRASH("Invalid emitMove arguments."); 164 } 165 } else if (from.isMemory()) { 166 if (to.isGeneralReg()) { 167 masm.loadPtr(getAdjustedAddress(from), to.reg()); 168 } else if (to.isMemory()) { 169 UseScratchRegisterScope temps(masm); 170 Register scratch = temps.Acquire(); 171 masm.loadPtr(getAdjustedAddress(from), scratch); 172 masm.storePtr(scratch, getAdjustedAddress(to)); 173 } else { 174 MOZ_CRASH("Invalid emitMove arguments."); 175 } 176 } else if (from.isEffectiveAddress()) { 177 if (to.isGeneralReg()) { 178 masm.computeEffectiveAddress(getAdjustedAddress(from), to.reg()); 179 } else if (to.isMemory()) { 180 UseScratchRegisterScope temps(masm); 181 Register scratch = temps.Acquire(); 182 masm.computeEffectiveAddress(getAdjustedAddress(from), scratch); 183 masm.storePtr(scratch, getAdjustedAddress(to)); 184 } else { 185 MOZ_CRASH("Invalid emitMove arguments."); 186 } 187 } else { 188 MOZ_CRASH("Invalid emitMove arguments."); 189 } 190 } 191 192 void MoveEmitterLOONG64::emitInt32Move(const MoveOperand& from, 193 const MoveOperand& to) { 194 if (from.isGeneralReg()) { 195 if (to.isGeneralReg()) { 196 masm.move32(from.reg(), to.reg()); 197 } else if (to.isMemory()) { 198 masm.store32(from.reg(), getAdjustedAddress(to)); 199 } else { 200 MOZ_CRASH("Invalid emitInt32Move arguments."); 201 } 202 } else if (from.isMemory()) { 203 if (to.isGeneralReg()) { 204 masm.load32(getAdjustedAddress(from), to.reg()); 205 } else if (to.isMemory()) { 206 UseScratchRegisterScope temps(masm); 207 Register scratch = temps.Acquire(); 208 masm.load32(getAdjustedAddress(from), scratch); 209 masm.store32(scratch, getAdjustedAddress(to)); 210 } else { 211 MOZ_CRASH("Invalid emitInt32Move arguments."); 212 } 213 } else if (from.isEffectiveAddress()) { 214 if (to.isGeneralReg()) { 215 masm.computeEffectiveAddress(getAdjustedAddress(from), to.reg()); 216 } else if (to.isMemory()) { 217 UseScratchRegisterScope temps(masm); 218 Register scratch = temps.Acquire(); 219 masm.computeEffectiveAddress(getAdjustedAddress(from), scratch); 220 masm.store32(scratch, getAdjustedAddress(to)); 221 } else { 222 MOZ_CRASH("Invalid emitInt32Move arguments."); 223 } 224 } else { 225 MOZ_CRASH("Invalid emitInt32Move arguments."); 226 } 227 } 228 229 void MoveEmitterLOONG64::emitFloat32Move(const MoveOperand& from, 230 const MoveOperand& to) { 231 if (from.isFloatReg()) { 232 if (to.isFloatReg()) { 233 masm.moveFloat32(from.floatReg(), to.floatReg()); 234 } else if (to.isGeneralReg()) { 235 // This should only be used when passing float parameter in a1,a2,a3 236 MOZ_ASSERT(to.reg() == a1 || to.reg() == a2 || to.reg() == a3); 237 masm.moveFromFloat32(from.floatReg(), to.reg()); 238 } else { 239 MOZ_ASSERT(to.isMemory()); 240 masm.storeFloat32(from.floatReg(), getAdjustedAddress(to)); 241 } 242 } else if (to.isFloatReg()) { 243 MOZ_ASSERT(from.isMemory()); 244 masm.loadFloat32(getAdjustedAddress(from), to.floatReg()); 245 } else if (to.isGeneralReg()) { 246 MOZ_ASSERT(from.isMemory()); 247 // This should only be used when passing float parameter in a1,a2,a3 248 MOZ_ASSERT(to.reg() == a1 || to.reg() == a2 || to.reg() == a3); 249 masm.loadPtr(getAdjustedAddress(from), to.reg()); 250 } else { 251 MOZ_ASSERT(from.isMemory()); 252 MOZ_ASSERT(to.isMemory()); 253 ScratchFloat32Scope fpscratch32(masm); 254 masm.loadFloat32(getAdjustedAddress(from), fpscratch32); 255 masm.storeFloat32(fpscratch32, getAdjustedAddress(to)); 256 } 257 } 258 259 void MoveEmitterLOONG64::emitDoubleMove(const MoveOperand& from, 260 const MoveOperand& to) { 261 if (from.isFloatReg()) { 262 if (to.isFloatReg()) { 263 masm.moveDouble(from.floatReg(), to.floatReg()); 264 } else if (to.isGeneralReg()) { 265 masm.moveFromDouble(from.floatReg(), to.reg()); 266 } else { 267 MOZ_ASSERT(to.isMemory()); 268 masm.storeDouble(from.floatReg(), getAdjustedAddress(to)); 269 } 270 } else if (to.isFloatReg()) { 271 if (from.isMemory()) { 272 masm.loadDouble(getAdjustedAddress(from), to.floatReg()); 273 } else { 274 masm.moveToDouble(from.reg(), to.floatReg()); 275 } 276 } else { 277 MOZ_ASSERT(from.isMemory()); 278 MOZ_ASSERT(to.isMemory()); 279 ScratchDoubleScope fpscratch64(masm); 280 masm.loadDouble(getAdjustedAddress(from), fpscratch64); 281 masm.storeDouble(fpscratch64, getAdjustedAddress(to)); 282 } 283 } 284 285 void MoveEmitterLOONG64::emit(const MoveOp& move) { 286 const MoveOperand& from = move.from(); 287 const MoveOperand& to = move.to(); 288 289 if (move.isCycleEnd() && move.isCycleBegin()) { 290 // A fun consequence of aliased registers is you can have multiple 291 // cycles at once, and one can end exactly where another begins. 292 breakCycle(from, to, move.endCycleType(), move.cycleBeginSlot()); 293 completeCycle(from, to, move.type(), move.cycleEndSlot()); 294 return; 295 } 296 297 if (move.isCycleEnd()) { 298 MOZ_ASSERT(inCycle_); 299 completeCycle(from, to, move.type(), move.cycleEndSlot()); 300 MOZ_ASSERT(inCycle_ > 0); 301 inCycle_--; 302 return; 303 } 304 305 if (move.isCycleBegin()) { 306 breakCycle(from, to, move.endCycleType(), move.cycleBeginSlot()); 307 inCycle_++; 308 } 309 310 switch (move.type()) { 311 case MoveOp::FLOAT32: 312 emitFloat32Move(from, to); 313 break; 314 case MoveOp::DOUBLE: 315 emitDoubleMove(from, to); 316 break; 317 case MoveOp::INT32: 318 emitInt32Move(from, to); 319 break; 320 case MoveOp::GENERAL: 321 emitMove(from, to); 322 break; 323 default: 324 MOZ_CRASH("Unexpected move type"); 325 } 326 } 327 328 void MoveEmitterLOONG64::assertDone() { MOZ_ASSERT(inCycle_ == 0); } 329 330 void MoveEmitterLOONG64::finish() { 331 assertDone(); 332 333 masm.freeStack(masm.framePushed() - pushedAtStart_); 334 }