Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
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/. */
7 #include "jit/mips/MoveEmitter-mips.h"
9 using namespace js;
10 using namespace js::jit;
12 MoveEmitterMIPS::MoveEmitterMIPS(MacroAssemblerMIPSCompat &masm)
13 : inCycle_(false),
14 masm(masm),
15 pushedAtCycle_(-1),
16 pushedAtSpill_(-1),
17 spilledReg_(InvalidReg),
18 spilledFloatReg_(InvalidFloatReg)
19 {
20 pushedAtStart_ = masm.framePushed();
21 }
23 void
24 MoveEmitterMIPS::emit(const MoveResolver &moves)
25 {
26 if (moves.hasCycles()) {
27 // Reserve stack for cycle resolution
28 masm.reserveStack(sizeof(double));
29 pushedAtCycle_ = masm.framePushed();
30 }
32 for (size_t i = 0; i < moves.numMoves(); i++)
33 emit(moves.getMove(i));
34 }
36 MoveEmitterMIPS::~MoveEmitterMIPS()
37 {
38 assertDone();
39 }
41 Address
42 MoveEmitterMIPS::cycleSlot() const
43 {
44 int offset = masm.framePushed() - pushedAtCycle_;
45 MOZ_ASSERT(Imm16::isInSignedRange(offset));
46 return Address(StackPointer, offset);
47 }
49 int32_t
50 MoveEmitterMIPS::getAdjustedOffset(const MoveOperand &operand)
51 {
52 MOZ_ASSERT(operand.isMemoryOrEffectiveAddress());
53 if (operand.base() != StackPointer)
54 return operand.disp();
56 // Adjust offset if stack pointer has been moved.
57 return operand.disp() + masm.framePushed() - pushedAtStart_;
58 }
60 Address
61 MoveEmitterMIPS::getAdjustedAddress(const MoveOperand &operand)
62 {
63 return Address(operand.base(), getAdjustedOffset(operand));
64 }
67 Register
68 MoveEmitterMIPS::tempReg()
69 {
70 spilledReg_ = SecondScratchReg;
71 return SecondScratchReg;
72 }
74 void
75 MoveEmitterMIPS::breakCycle(const MoveOperand &from, const MoveOperand &to, MoveOp::Type type)
76 {
77 // There is some pattern:
78 // (A -> B)
79 // (B -> A)
80 //
81 // This case handles (A -> B), which we reach first. We save B, then allow
82 // the original move to continue.
83 switch (type) {
84 case MoveOp::FLOAT32:
85 if (to.isMemory()) {
86 FloatRegister temp = ScratchFloatReg;
87 masm.loadFloat32(getAdjustedAddress(to), temp);
88 masm.storeFloat32(temp, cycleSlot());
89 } else {
90 masm.storeFloat32(to.floatReg(), cycleSlot());
91 }
92 break;
93 case MoveOp::DOUBLE:
94 if (to.isMemory()) {
95 FloatRegister temp = ScratchFloatReg;
96 masm.loadDouble(getAdjustedAddress(to), temp);
97 masm.storeDouble(temp, cycleSlot());
98 } else {
99 masm.storeDouble(to.floatReg(), cycleSlot());
100 }
101 break;
102 case MoveOp::INT32:
103 MOZ_ASSERT(sizeof(uintptr_t) == sizeof(int32_t));
104 case MoveOp::GENERAL:
105 if (to.isMemory()) {
106 Register temp = tempReg();
107 masm.loadPtr(getAdjustedAddress(to), temp);
108 masm.storePtr(temp, cycleSlot());
109 } else {
110 // Second scratch register should not be moved by MoveEmitter.
111 MOZ_ASSERT(to.reg() != spilledReg_);
112 masm.storePtr(to.reg(), cycleSlot());
113 }
114 break;
115 default:
116 MOZ_ASSUME_UNREACHABLE("Unexpected move type");
117 }
118 }
120 void
121 MoveEmitterMIPS::completeCycle(const MoveOperand &from, const MoveOperand &to, MoveOp::Type type)
122 {
123 // There is some pattern:
124 // (A -> B)
125 // (B -> A)
126 //
127 // This case handles (B -> A), which we reach last. We emit a move from the
128 // saved value of B, to A.
129 switch (type) {
130 case MoveOp::FLOAT32:
131 if (to.isMemory()) {
132 FloatRegister temp = ScratchFloatReg;
133 masm.loadFloat32(cycleSlot(), temp);
134 masm.storeFloat32(temp, getAdjustedAddress(to));
135 } else {
136 masm.loadFloat32(cycleSlot(), to.floatReg());
137 }
138 break;
139 case MoveOp::DOUBLE:
140 if (to.isMemory()) {
141 FloatRegister temp = ScratchFloatReg;
142 masm.loadDouble(cycleSlot(), temp);
143 masm.storeDouble(temp, getAdjustedAddress(to));
144 } else {
145 masm.loadDouble(cycleSlot(), to.floatReg());
146 }
147 break;
148 case MoveOp::INT32:
149 MOZ_ASSERT(sizeof(uintptr_t) == sizeof(int32_t));
150 case MoveOp::GENERAL:
151 if (to.isMemory()) {
152 Register temp = tempReg();
153 masm.loadPtr(cycleSlot(), temp);
154 masm.storePtr(temp, getAdjustedAddress(to));
155 } else {
156 // Second scratch register should not be moved by MoveEmitter.
157 MOZ_ASSERT(to.reg() != spilledReg_);
158 masm.loadPtr(cycleSlot(), to.reg());
159 }
160 break;
161 default:
162 MOZ_ASSUME_UNREACHABLE("Unexpected move type");
163 }
164 }
166 void
167 MoveEmitterMIPS::emitMove(const MoveOperand &from, const MoveOperand &to)
168 {
169 if (from.isGeneralReg()) {
170 // Second scratch register should not be moved by MoveEmitter.
171 MOZ_ASSERT(from.reg() != spilledReg_);
173 if (to.isGeneralReg())
174 masm.movePtr(from.reg(), to.reg());
175 else if (to.isMemory())
176 masm.storePtr(from.reg(), getAdjustedAddress(to));
177 else
178 MOZ_ASSUME_UNREACHABLE("Invalid emitMove arguments.");
179 } else if (from.isMemory()) {
180 if (to.isGeneralReg()) {
181 masm.loadPtr(getAdjustedAddress(from), to.reg());
182 } else if (to.isMemory()) {
183 masm.loadPtr(getAdjustedAddress(from), tempReg());
184 masm.storePtr(tempReg(), getAdjustedAddress(to));
185 } else {
186 MOZ_ASSUME_UNREACHABLE("Invalid emitMove arguments.");
187 }
188 } else if (from.isEffectiveAddress()) {
189 if (to.isGeneralReg()) {
190 masm.computeEffectiveAddress(getAdjustedAddress(from), to.reg());
191 } else if (to.isMemory()) {
192 masm.computeEffectiveAddress(getAdjustedAddress(from), tempReg());
193 masm.storePtr(tempReg(), getAdjustedAddress(to));
194 } else {
195 MOZ_ASSUME_UNREACHABLE("Invalid emitMove arguments.");
196 }
197 } else {
198 MOZ_ASSUME_UNREACHABLE("Invalid emitMove arguments.");
199 }
200 }
202 void
203 MoveEmitterMIPS::emitFloat32Move(const MoveOperand &from, const MoveOperand &to)
204 {
205 // Ensure that we can use ScratchFloatReg in memory move.
206 MOZ_ASSERT_IF(from.isFloatReg(), from.floatReg() != ScratchFloatReg);
207 MOZ_ASSERT_IF(to.isFloatReg(), to.floatReg() != ScratchFloatReg);
209 if (from.isFloatReg()) {
210 if (to.isFloatReg()) {
211 masm.moveFloat32(from.floatReg(), to.floatReg());
212 } else if (to.isGeneralReg()) {
213 // This should only be used when passing float parameter in a1,a2,a3
214 MOZ_ASSERT(to.reg() == a1 || to.reg() == a2 || to.reg() == a3);
215 masm.moveFromFloat32(from.floatReg(), to.reg());
216 } else {
217 MOZ_ASSERT(to.isMemory());
218 masm.storeFloat32(from.floatReg(), getAdjustedAddress(to));
219 }
220 } else if (to.isFloatReg()) {
221 MOZ_ASSERT(from.isMemory());
222 masm.loadFloat32(getAdjustedAddress(from), to.floatReg());
223 } else if (to.isGeneralReg()) {
224 MOZ_ASSERT(from.isMemory());
225 // This should only be used when passing float parameter in a1,a2,a3
226 MOZ_ASSERT(to.reg() == a1 || to.reg() == a2 || to.reg() == a3);
227 masm.loadPtr(getAdjustedAddress(from), to.reg());
228 } else {
229 MOZ_ASSERT(from.isMemory());
230 MOZ_ASSERT(to.isMemory());
231 masm.loadFloat32(getAdjustedAddress(from), ScratchFloatReg);
232 masm.storeFloat32(ScratchFloatReg, getAdjustedAddress(to));
233 }
234 }
236 void
237 MoveEmitterMIPS::emitDoubleMove(const MoveOperand &from, const MoveOperand &to)
238 {
239 // Ensure that we can use ScratchFloatReg in memory move.
240 MOZ_ASSERT_IF(from.isFloatReg(), from.floatReg() != ScratchFloatReg);
241 MOZ_ASSERT_IF(to.isFloatReg(), to.floatReg() != ScratchFloatReg);
243 if (from.isFloatReg()) {
244 if (to.isFloatReg()) {
245 masm.moveDouble(from.floatReg(), to.floatReg());
246 } else if (to.isGeneralReg()) {
247 // Used for passing double parameter in a2,a3 register pair.
248 // Two moves are added for one double parameter by
249 // MacroAssemblerMIPSCompat::passABIArg
250 if(to.reg() == a2)
251 masm.moveFromDoubleLo(from.floatReg(), a2);
252 else if(to.reg() == a3)
253 masm.moveFromDoubleHi(from.floatReg(), a3);
254 else
255 MOZ_ASSUME_UNREACHABLE("Invalid emitDoubleMove arguments.");
256 } else {
257 MOZ_ASSERT(to.isMemory());
258 masm.storeDouble(from.floatReg(), getAdjustedAddress(to));
259 }
260 } else if (to.isFloatReg()) {
261 MOZ_ASSERT(from.isMemory());
262 masm.loadDouble(getAdjustedAddress(from), to.floatReg());
263 } else if (to.isGeneralReg()) {
264 MOZ_ASSERT(from.isMemory());
265 // Used for passing double parameter in a2,a3 register pair.
266 // Two moves are added for one double parameter by
267 // MacroAssemblerMIPSCompat::passABIArg
268 if(to.reg() == a2)
269 masm.loadPtr(getAdjustedAddress(from), a2);
270 else if(to.reg() == a3)
271 masm.loadPtr(Address(from.base(), getAdjustedOffset(from) + sizeof(uint32_t)), a3);
272 else
273 MOZ_ASSUME_UNREACHABLE("Invalid emitDoubleMove arguments.");
274 } else {
275 MOZ_ASSERT(from.isMemory());
276 MOZ_ASSERT(to.isMemory());
277 masm.loadDouble(getAdjustedAddress(from), ScratchFloatReg);
278 masm.storeDouble(ScratchFloatReg, getAdjustedAddress(to));
279 }
280 }
282 void
283 MoveEmitterMIPS::emit(const MoveOp &move)
284 {
285 const MoveOperand &from = move.from();
286 const MoveOperand &to = move.to();
288 if (move.isCycleEnd()) {
289 MOZ_ASSERT(inCycle_);
290 completeCycle(from, to, move.type());
291 inCycle_ = false;
292 return;
293 }
295 if (move.isCycleBegin()) {
296 MOZ_ASSERT(!inCycle_);
297 breakCycle(from, to, move.endCycleType());
298 inCycle_ = true;
299 }
301 switch (move.type()) {
302 case MoveOp::FLOAT32:
303 emitFloat32Move(from, to);
304 break;
305 case MoveOp::DOUBLE:
306 emitDoubleMove(from, to);
307 break;
308 case MoveOp::INT32:
309 MOZ_ASSERT(sizeof(uintptr_t) == sizeof(int32_t));
310 case MoveOp::GENERAL:
311 emitMove(from, to);
312 break;
313 default:
314 MOZ_ASSUME_UNREACHABLE("Unexpected move type");
315 }
316 }
318 void
319 MoveEmitterMIPS::assertDone()
320 {
321 MOZ_ASSERT(!inCycle_);
322 }
324 void
325 MoveEmitterMIPS::finish()
326 {
327 assertDone();
329 masm.freeStack(masm.framePushed() - pushedAtStart_);
330 }