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/mips32/MoveEmitter-mips32.h" 8 9 #include "jit/MacroAssembler-inl.h" 10 11 using namespace js; 12 using namespace js::jit; 13 14 void 15 MoveEmitterMIPS::breakCycle(const MoveOperand& from, const MoveOperand& to, 16 MoveOp::Type type, uint32_t slotId) 17 { 18 // There is some pattern: 19 // (A -> B) 20 // (B -> A) 21 // 22 // This case handles (A -> B), which we reach first. We save B, then allow 23 // the original move to continue. 24 switch (type) { 25 case MoveOp::FLOAT32: 26 if (to.isMemory()) { 27 FloatRegister temp = ScratchFloat32Reg; 28 masm.loadFloat32(getAdjustedAddress(to), temp); 29 // Since it is uncertain if the load will be aligned or not 30 // just fill both of them with the same value. 31 masm.storeFloat32(temp, cycleSlot(slotId, 0)); 32 masm.storeFloat32(temp, cycleSlot(slotId, 4)); 33 } else { 34 // Just always store the largest possible size. 35 masm.storeDouble(to.floatReg().doubleOverlay(), cycleSlot(slotId, 0)); 36 } 37 break; 38 case MoveOp::DOUBLE: 39 if (to.isMemory()) { 40 FloatRegister temp = ScratchDoubleReg; 41 masm.loadDouble(getAdjustedAddress(to), temp); 42 masm.storeDouble(temp, cycleSlot(slotId, 0)); 43 } else { 44 masm.storeDouble(to.floatReg(), cycleSlot(slotId, 0)); 45 } compatible_ftypes(ftenum_t a,ftenum_t b)46 break; 47 case MoveOp::INT32: 48 MOZ_ASSERT(sizeof(uintptr_t) == sizeof(int32_t)); 49 case MoveOp::GENERAL: 50 if (to.isMemory()) { 51 Register temp = tempReg(); 52 masm.loadPtr(getAdjustedAddress(to), temp); 53 masm.storePtr(temp, cycleSlot(0, 0)); 54 } else { 55 // Second scratch register should not be moved by MoveEmitter. 56 MOZ_ASSERT(to.reg() != spilledReg_); 57 masm.storePtr(to.reg(), cycleSlot(0, 0)); 58 } 59 break; 60 default: 61 MOZ_CRASH("Unexpected move type"); 62 } 63 } 64 65 void 66 MoveEmitterMIPS::completeCycle(const MoveOperand& from, const MoveOperand& to, 67 MoveOp::Type type, uint32_t slotId) 68 { 69 // There is some pattern: 70 // (A -> B) 71 // (B -> A) 72 // 73 // This case handles (B -> A), which we reach last. We emit a move from the 74 // saved value of B, to A. 75 switch (type) { 76 case MoveOp::FLOAT32: 77 if (to.isMemory()) { 78 FloatRegister temp = ScratchFloat32Reg; 79 masm.loadFloat32(cycleSlot(slotId, 0), temp); 80 masm.storeFloat32(temp, getAdjustedAddress(to)); 81 } else { 82 uint32_t offset = 0; 83 if (from.floatReg().numAlignedAliased() == 1) 84 offset = sizeof(float); 85 masm.loadFloat32(cycleSlot(slotId, offset), to.floatReg()); 86 } 87 break; 88 case MoveOp::DOUBLE: 89 if (to.isMemory()) { 90 FloatRegister temp = ScratchDoubleReg; 91 masm.loadDouble(cycleSlot(slotId, 0), temp); 92 masm.storeDouble(temp, getAdjustedAddress(to)); 93 } else { 94 masm.loadDouble(cycleSlot(slotId, 0), to.floatReg()); 95 } 96 break; 97 case MoveOp::INT32: 98 MOZ_ASSERT(sizeof(uintptr_t) == sizeof(int32_t)); 99 case MoveOp::GENERAL: 100 MOZ_ASSERT(slotId == 0); 101 if (to.isMemory()) { 102 Register temp = tempReg(); 103 masm.loadPtr(cycleSlot(0, 0), temp); 104 masm.storePtr(temp, getAdjustedAddress(to)); 105 } else { 106 // Second scratch register should not be moved by MoveEmitter. 107 MOZ_ASSERT(to.reg() != spilledReg_); 108 masm.loadPtr(cycleSlot(0, 0), to.reg()); 109 } 110 break; 111 default: 112 MOZ_CRASH("Unexpected move type"); 113 } 114 } 115 116 void 117 MoveEmitterMIPS::emitDoubleMove(const MoveOperand& from, const MoveOperand& to) 118 { 119 // Ensure that we can use ScratchDoubleReg in memory move. 120 MOZ_ASSERT_IF(from.isFloatReg(), from.floatReg() != ScratchDoubleReg); 121 MOZ_ASSERT_IF(to.isFloatReg(), to.floatReg() != ScratchDoubleReg); 122 123 if (from.isFloatReg()) { 124 if (to.isFloatReg()) { 125 masm.moveDouble(from.floatReg(), to.floatReg()); 126 } else if (to.isGeneralRegPair()) { 127 // Used for passing double parameter in a2,a3 register pair. 128 // Two moves are added for one double parameter by 129 // MacroAssembler::passABIArg 130 MOZ_ASSERT(to.evenReg() == a2 && to.oddReg() == a3, 131 "Invalid emitDoubleMove arguments."); 132 masm.moveFromDoubleLo(from.floatReg(), a2); 133 masm.moveFromDoubleHi(from.floatReg(), a3); 134 } else { 135 MOZ_ASSERT(to.isMemory()); 136 masm.storeDouble(from.floatReg(), getAdjustedAddress(to)); 137 } dfilter_fvalue_from_unparsed(dfwork_t * dfw,ftenum_t ftype,const char * s,gboolean allow_partial_value)138 } else if (to.isFloatReg()) { 139 MOZ_ASSERT(from.isMemory()); 140 masm.loadDouble(getAdjustedAddress(from), to.floatReg()); 141 } else if (to.isGeneralRegPair()) { 142 // Used for passing double parameter in a2,a3 register pair. 143 // Two moves are added for one double parameter by 144 // MacroAssembler::passABIArg 145 MOZ_ASSERT(from.isMemory()); 146 MOZ_ASSERT(to.evenReg() == a2 && to.oddReg() == a3, 147 "Invalid emitDoubleMove arguments."); 148 masm.loadPtr(getAdjustedAddress(from), a2); dfilter_fvalue_from_string(dfwork_t * dfw,ftenum_t ftype,const char * s)149 masm.loadPtr(Address(from.base(), getAdjustedOffset(from) + sizeof(uint32_t)), a3); 150 } else { 151 MOZ_ASSERT(from.isMemory()); 152 MOZ_ASSERT(to.isMemory()); 153 masm.loadDouble(getAdjustedAddress(from), ScratchDoubleReg); 154 masm.storeDouble(ScratchDoubleReg, getAdjustedAddress(to)); 155 } 156 } mk_uint32_fvalue(guint32 val)157