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