|
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 #ifndef jit_mips_MacroAssembler_mips_h |
|
8 #define jit_mips_MacroAssembler_mips_h |
|
9 |
|
10 #include "jsopcode.h" |
|
11 |
|
12 #include "jit/IonCaches.h" |
|
13 #include "jit/IonFrames.h" |
|
14 #include "jit/mips/Assembler-mips.h" |
|
15 #include "jit/MoveResolver.h" |
|
16 |
|
17 namespace js { |
|
18 namespace jit { |
|
19 |
|
20 enum LoadStoreSize |
|
21 { |
|
22 SizeByte = 8, |
|
23 SizeHalfWord = 16, |
|
24 SizeWord = 32, |
|
25 SizeDouble = 64 |
|
26 }; |
|
27 |
|
28 enum LoadStoreExtension |
|
29 { |
|
30 ZeroExtend = 0, |
|
31 SignExtend = 1 |
|
32 }; |
|
33 |
|
34 enum JumpKind |
|
35 { |
|
36 LongJump = 0, |
|
37 ShortJump = 1 |
|
38 }; |
|
39 |
|
40 struct ImmTag : public Imm32 |
|
41 { |
|
42 ImmTag(JSValueTag mask) |
|
43 : Imm32(int32_t(mask)) |
|
44 { } |
|
45 }; |
|
46 |
|
47 struct ImmType : public ImmTag |
|
48 { |
|
49 ImmType(JSValueType type) |
|
50 : ImmTag(JSVAL_TYPE_TO_TAG(type)) |
|
51 { } |
|
52 }; |
|
53 |
|
54 static const ValueOperand JSReturnOperand = ValueOperand(JSReturnReg_Type, JSReturnReg_Data); |
|
55 static const ValueOperand softfpReturnOperand = ValueOperand(v1, v0); |
|
56 |
|
57 static Register CallReg = t9; |
|
58 static const int defaultShift = 3; |
|
59 static_assert(1 << defaultShift == sizeof(jsval), "The defaultShift is wrong"); |
|
60 |
|
61 class MacroAssemblerMIPS : public Assembler |
|
62 { |
|
63 public: |
|
64 |
|
65 void convertBoolToInt32(Register source, Register dest); |
|
66 void convertInt32ToDouble(const Register &src, const FloatRegister &dest); |
|
67 void convertInt32ToDouble(const Address &src, FloatRegister dest); |
|
68 void convertUInt32ToDouble(const Register &src, const FloatRegister &dest); |
|
69 void convertUInt32ToFloat32(const Register &src, const FloatRegister &dest); |
|
70 void convertDoubleToFloat32(const FloatRegister &src, const FloatRegister &dest); |
|
71 void branchTruncateDouble(const FloatRegister &src, const Register &dest, Label *fail); |
|
72 void convertDoubleToInt32(const FloatRegister &src, const Register &dest, Label *fail, |
|
73 bool negativeZeroCheck = true); |
|
74 void convertFloat32ToInt32(const FloatRegister &src, const Register &dest, Label *fail, |
|
75 bool negativeZeroCheck = true); |
|
76 |
|
77 void convertFloat32ToDouble(const FloatRegister &src, const FloatRegister &dest); |
|
78 void branchTruncateFloat32(const FloatRegister &src, const Register &dest, Label *fail); |
|
79 void convertInt32ToFloat32(const Register &src, const FloatRegister &dest); |
|
80 void convertInt32ToFloat32(const Address &src, FloatRegister dest); |
|
81 |
|
82 |
|
83 void addDouble(FloatRegister src, FloatRegister dest); |
|
84 void subDouble(FloatRegister src, FloatRegister dest); |
|
85 void mulDouble(FloatRegister src, FloatRegister dest); |
|
86 void divDouble(FloatRegister src, FloatRegister dest); |
|
87 |
|
88 void negateDouble(FloatRegister reg); |
|
89 void inc64(AbsoluteAddress dest); |
|
90 |
|
91 public: |
|
92 |
|
93 void ma_move(Register rd, Register rs); |
|
94 |
|
95 void ma_li(Register dest, const ImmGCPtr &ptr); |
|
96 |
|
97 void ma_li(const Register &dest, AbsoluteLabel *label); |
|
98 |
|
99 void ma_li(Register dest, Imm32 imm); |
|
100 void ma_liPatchable(Register dest, Imm32 imm); |
|
101 void ma_liPatchable(Register dest, ImmPtr imm); |
|
102 |
|
103 // Shift operations |
|
104 void ma_sll(Register rd, Register rt, Imm32 shift); |
|
105 void ma_srl(Register rd, Register rt, Imm32 shift); |
|
106 void ma_sra(Register rd, Register rt, Imm32 shift); |
|
107 void ma_ror(Register rd, Register rt, Imm32 shift); |
|
108 void ma_rol(Register rd, Register rt, Imm32 shift); |
|
109 |
|
110 void ma_sll(Register rd, Register rt, Register shift); |
|
111 void ma_srl(Register rd, Register rt, Register shift); |
|
112 void ma_sra(Register rd, Register rt, Register shift); |
|
113 void ma_ror(Register rd, Register rt, Register shift); |
|
114 void ma_rol(Register rd, Register rt, Register shift); |
|
115 |
|
116 // Negate |
|
117 void ma_negu(Register rd, Register rs); |
|
118 |
|
119 void ma_not(Register rd, Register rs); |
|
120 |
|
121 // and |
|
122 void ma_and(Register rd, Register rs); |
|
123 void ma_and(Register rd, Register rs, Register rt); |
|
124 void ma_and(Register rd, Imm32 imm); |
|
125 void ma_and(Register rd, Register rs, Imm32 imm); |
|
126 |
|
127 // or |
|
128 void ma_or(Register rd, Register rs); |
|
129 void ma_or(Register rd, Register rs, Register rt); |
|
130 void ma_or(Register rd, Imm32 imm); |
|
131 void ma_or(Register rd, Register rs, Imm32 imm); |
|
132 |
|
133 // xor |
|
134 void ma_xor(Register rd, Register rs); |
|
135 void ma_xor(Register rd, Register rs, Register rt); |
|
136 void ma_xor(Register rd, Imm32 imm); |
|
137 void ma_xor(Register rd, Register rs, Imm32 imm); |
|
138 |
|
139 // load |
|
140 void ma_load(const Register &dest, Address address, LoadStoreSize size = SizeWord, |
|
141 LoadStoreExtension extension = SignExtend); |
|
142 void ma_load(const Register &dest, const BaseIndex &src, LoadStoreSize size = SizeWord, |
|
143 LoadStoreExtension extension = SignExtend); |
|
144 |
|
145 // store |
|
146 void ma_store(const Register &data, Address address, LoadStoreSize size = SizeWord, |
|
147 LoadStoreExtension extension = SignExtend); |
|
148 void ma_store(const Register &data, const BaseIndex &dest, LoadStoreSize size = SizeWord, |
|
149 LoadStoreExtension extension = SignExtend); |
|
150 void ma_store(const Imm32 &imm, const BaseIndex &dest, LoadStoreSize size = SizeWord, |
|
151 LoadStoreExtension extension = SignExtend); |
|
152 |
|
153 void computeScaledAddress(const BaseIndex &address, Register dest); |
|
154 |
|
155 void computeEffectiveAddress(const Address &address, Register dest) { |
|
156 ma_addu(dest, address.base, Imm32(address.offset)); |
|
157 } |
|
158 |
|
159 void computeEffectiveAddress(const BaseIndex &address, Register dest) { |
|
160 computeScaledAddress(address, dest); |
|
161 if (address.offset) { |
|
162 ma_addu(dest, dest, Imm32(address.offset)); |
|
163 } |
|
164 } |
|
165 |
|
166 // arithmetic based ops |
|
167 // add |
|
168 void ma_addu(Register rd, Register rs, Imm32 imm); |
|
169 void ma_addu(Register rd, Register rs); |
|
170 void ma_addu(Register rd, Imm32 imm); |
|
171 void ma_addTestOverflow(Register rd, Register rs, Register rt, Label *overflow); |
|
172 void ma_addTestOverflow(Register rd, Register rs, Imm32 imm, Label *overflow); |
|
173 |
|
174 // subtract |
|
175 void ma_subu(Register rd, Register rs, Register rt); |
|
176 void ma_subu(Register rd, Register rs, Imm32 imm); |
|
177 void ma_subu(Register rd, Imm32 imm); |
|
178 void ma_subTestOverflow(Register rd, Register rs, Register rt, Label *overflow); |
|
179 void ma_subTestOverflow(Register rd, Register rs, Imm32 imm, Label *overflow); |
|
180 |
|
181 // multiplies. For now, there are only few that we care about. |
|
182 void ma_mult(Register rs, Imm32 imm); |
|
183 void ma_mul_branch_overflow(Register rd, Register rs, Register rt, Label *overflow); |
|
184 void ma_mul_branch_overflow(Register rd, Register rs, Imm32 imm, Label *overflow); |
|
185 |
|
186 // divisions |
|
187 void ma_div_branch_overflow(Register rd, Register rs, Register rt, Label *overflow); |
|
188 void ma_div_branch_overflow(Register rd, Register rs, Imm32 imm, Label *overflow); |
|
189 |
|
190 // fast mod, uses scratch registers, and thus needs to be in the assembler |
|
191 // implicitly assumes that we can overwrite dest at the beginning of the sequence |
|
192 void ma_mod_mask(Register src, Register dest, Register hold, int32_t shift, |
|
193 Label *negZero = nullptr); |
|
194 |
|
195 // memory |
|
196 // shortcut for when we know we're transferring 32 bits of data |
|
197 void ma_lw(Register data, Address address); |
|
198 |
|
199 void ma_sw(Register data, Address address); |
|
200 void ma_sw(Imm32 imm, Address address); |
|
201 |
|
202 void ma_pop(Register r); |
|
203 void ma_push(Register r); |
|
204 |
|
205 // branches when done from within mips-specific code |
|
206 void ma_b(Register lhs, Register rhs, Label *l, Condition c, JumpKind jumpKind = LongJump); |
|
207 void ma_b(Register lhs, Imm32 imm, Label *l, Condition c, JumpKind jumpKind = LongJump); |
|
208 void ma_b(Register lhs, Address addr, Label *l, Condition c, JumpKind jumpKind = LongJump); |
|
209 void ma_b(Address addr, Imm32 imm, Label *l, Condition c, JumpKind jumpKind = LongJump); |
|
210 void ma_b(Label *l, JumpKind jumpKind = LongJump); |
|
211 void ma_bal(Label *l, JumpKind jumpKind = LongJump); |
|
212 |
|
213 // fp instructions |
|
214 void ma_lis(FloatRegister dest, float value); |
|
215 void ma_lid(FloatRegister dest, double value); |
|
216 void ma_liNegZero(FloatRegister dest); |
|
217 |
|
218 void ma_mv(FloatRegister src, ValueOperand dest); |
|
219 void ma_mv(ValueOperand src, FloatRegister dest); |
|
220 |
|
221 void ma_ls(FloatRegister fd, Address address); |
|
222 void ma_ld(FloatRegister fd, Address address); |
|
223 void ma_sd(FloatRegister fd, Address address); |
|
224 void ma_sd(FloatRegister fd, BaseIndex address); |
|
225 void ma_ss(FloatRegister fd, Address address); |
|
226 void ma_ss(FloatRegister fd, BaseIndex address); |
|
227 |
|
228 void ma_pop(FloatRegister fs); |
|
229 void ma_push(FloatRegister fs); |
|
230 |
|
231 //FP branches |
|
232 void ma_bc1s(FloatRegister lhs, FloatRegister rhs, Label *label, DoubleCondition c, |
|
233 JumpKind jumpKind = LongJump, FPConditionBit fcc = FCC0); |
|
234 void ma_bc1d(FloatRegister lhs, FloatRegister rhs, Label *label, DoubleCondition c, |
|
235 JumpKind jumpKind = LongJump, FPConditionBit fcc = FCC0); |
|
236 |
|
237 |
|
238 // These fuctions abstract the access to high part of the double precision |
|
239 // float register. It is intended to work on both 32 bit and 64 bit |
|
240 // floating point coprocessor. |
|
241 // :TODO: (Bug 985881) Modify this for N32 ABI to use mthc1 and mfhc1 |
|
242 void moveToDoubleHi(Register src, FloatRegister dest) { |
|
243 as_mtc1(src, getOddPair(dest)); |
|
244 } |
|
245 void moveFromDoubleHi(FloatRegister src, Register dest) { |
|
246 as_mfc1(dest, getOddPair(src)); |
|
247 } |
|
248 |
|
249 void moveToDoubleLo(Register src, FloatRegister dest) { |
|
250 as_mtc1(src, dest); |
|
251 } |
|
252 void moveFromDoubleLo(FloatRegister src, Register dest) { |
|
253 as_mfc1(dest, src); |
|
254 } |
|
255 |
|
256 void moveToFloat32(Register src, FloatRegister dest) { |
|
257 as_mtc1(src, dest); |
|
258 } |
|
259 void moveFromFloat32(FloatRegister src, Register dest) { |
|
260 as_mfc1(dest, src); |
|
261 } |
|
262 |
|
263 protected: |
|
264 void branchWithCode(InstImm code, Label *label, JumpKind jumpKind); |
|
265 Condition ma_cmp(Register rd, Register lhs, Register rhs, Condition c); |
|
266 |
|
267 void compareFloatingPoint(FloatFormat fmt, FloatRegister lhs, FloatRegister rhs, |
|
268 DoubleCondition c, FloatTestKind *testKind, |
|
269 FPConditionBit fcc = FCC0); |
|
270 |
|
271 public: |
|
272 // calls an Ion function, assumes that the stack is untouched (8 byte alinged) |
|
273 void ma_callIon(const Register reg); |
|
274 // callso an Ion function, assuming that sp has already been decremented |
|
275 void ma_callIonNoPush(const Register reg); |
|
276 // calls an ion function, assuming that the stack is currently not 8 byte aligned |
|
277 void ma_callIonHalfPush(const Register reg); |
|
278 |
|
279 void ma_call(ImmPtr dest); |
|
280 |
|
281 void ma_jump(ImmPtr dest); |
|
282 |
|
283 void ma_cmp_set(Register dst, Register lhs, Register rhs, Condition c); |
|
284 void ma_cmp_set(Register dst, Register lhs, Imm32 imm, Condition c); |
|
285 void ma_cmp_set(Register rd, Register rs, Address addr, Condition c); |
|
286 void ma_cmp_set(Register dst, Address lhs, Register imm, Condition c); |
|
287 void ma_cmp_set_double(Register dst, FloatRegister lhs, FloatRegister rhs, DoubleCondition c); |
|
288 void ma_cmp_set_float32(Register dst, FloatRegister lhs, FloatRegister rhs, DoubleCondition c); |
|
289 }; |
|
290 |
|
291 class MacroAssemblerMIPSCompat : public MacroAssemblerMIPS |
|
292 { |
|
293 // Number of bytes the stack is adjusted inside a call to C. Calls to C may |
|
294 // not be nested. |
|
295 bool inCall_; |
|
296 uint32_t args_; |
|
297 // The actual number of arguments that were passed, used to assert that |
|
298 // the initial number of arguments declared was correct. |
|
299 uint32_t passedArgs_; |
|
300 |
|
301 uint32_t usedArgSlots_; |
|
302 MoveOp::Type firstArgType; |
|
303 |
|
304 bool dynamicAlignment_; |
|
305 |
|
306 bool enoughMemory_; |
|
307 // Compute space needed for the function call and set the properties of the |
|
308 // callee. It returns the space which has to be allocated for calling the |
|
309 // function. |
|
310 // |
|
311 // arg Number of arguments of the function. |
|
312 void setupABICall(uint32_t arg); |
|
313 |
|
314 protected: |
|
315 MoveResolver moveResolver_; |
|
316 |
|
317 // Extra bytes currently pushed onto the frame beyond frameDepth_. This is |
|
318 // needed to compute offsets to stack slots while temporary space has been |
|
319 // reserved for unexpected spills or C++ function calls. It is maintained |
|
320 // by functions which track stack alignment, which for clear distinction |
|
321 // use StudlyCaps (for example, Push, Pop). |
|
322 uint32_t framePushed_; |
|
323 void adjustFrame(int value) { |
|
324 setFramePushed(framePushed_ + value); |
|
325 } |
|
326 public: |
|
327 MacroAssemblerMIPSCompat() |
|
328 : inCall_(false), |
|
329 enoughMemory_(true), |
|
330 framePushed_(0) |
|
331 { } |
|
332 bool oom() const { |
|
333 return Assembler::oom(); |
|
334 } |
|
335 |
|
336 public: |
|
337 using MacroAssemblerMIPS::call; |
|
338 |
|
339 void j(Label *dest) { |
|
340 ma_b(dest); |
|
341 } |
|
342 |
|
343 void mov(Register src, Register dest) { |
|
344 as_or(dest, src, zero); |
|
345 } |
|
346 void mov(ImmWord imm, Register dest) { |
|
347 ma_li(dest, Imm32(imm.value)); |
|
348 } |
|
349 void mov(ImmPtr imm, Register dest) { |
|
350 mov(ImmWord(uintptr_t(imm.value)), dest); |
|
351 } |
|
352 void mov(Register src, Address dest) { |
|
353 MOZ_ASSUME_UNREACHABLE("NYI-IC"); |
|
354 } |
|
355 void mov(Address src, Register dest) { |
|
356 MOZ_ASSUME_UNREACHABLE("NYI-IC"); |
|
357 } |
|
358 |
|
359 void call(const Register reg) { |
|
360 as_jalr(reg); |
|
361 as_nop(); |
|
362 } |
|
363 |
|
364 void call(Label *label) { |
|
365 // for now, assume that it'll be nearby? |
|
366 ma_bal(label); |
|
367 } |
|
368 |
|
369 void call(ImmWord imm) { |
|
370 call(ImmPtr((void*)imm.value)); |
|
371 } |
|
372 void call(ImmPtr imm) { |
|
373 BufferOffset bo = m_buffer.nextOffset(); |
|
374 addPendingJump(bo, imm, Relocation::HARDCODED); |
|
375 ma_call(imm); |
|
376 } |
|
377 void call(AsmJSImmPtr imm) { |
|
378 movePtr(imm, CallReg); |
|
379 call(CallReg); |
|
380 } |
|
381 void call(JitCode *c) { |
|
382 BufferOffset bo = m_buffer.nextOffset(); |
|
383 addPendingJump(bo, ImmPtr(c->raw()), Relocation::JITCODE); |
|
384 ma_liPatchable(ScratchRegister, Imm32((uint32_t)c->raw())); |
|
385 ma_callIonHalfPush(ScratchRegister); |
|
386 } |
|
387 void branch(JitCode *c) { |
|
388 BufferOffset bo = m_buffer.nextOffset(); |
|
389 addPendingJump(bo, ImmPtr(c->raw()), Relocation::JITCODE); |
|
390 ma_liPatchable(ScratchRegister, Imm32((uint32_t)c->raw())); |
|
391 as_jr(ScratchRegister); |
|
392 as_nop(); |
|
393 } |
|
394 void branch(const Register reg) { |
|
395 as_jr(reg); |
|
396 as_nop(); |
|
397 } |
|
398 void nop() { |
|
399 as_nop(); |
|
400 } |
|
401 void ret() { |
|
402 ma_pop(ra); |
|
403 as_jr(ra); |
|
404 as_nop(); |
|
405 } |
|
406 void retn(Imm32 n) { |
|
407 // pc <- [sp]; sp += n |
|
408 ma_lw(ra, Address(StackPointer, 0)); |
|
409 ma_addu(StackPointer, StackPointer, n); |
|
410 as_jr(ra); |
|
411 as_nop(); |
|
412 } |
|
413 void push(Imm32 imm) { |
|
414 ma_li(ScratchRegister, imm); |
|
415 ma_push(ScratchRegister); |
|
416 } |
|
417 void push(ImmWord imm) { |
|
418 ma_li(ScratchRegister, Imm32(imm.value)); |
|
419 ma_push(ScratchRegister); |
|
420 } |
|
421 void push(ImmGCPtr imm) { |
|
422 ma_li(ScratchRegister, imm); |
|
423 ma_push(ScratchRegister); |
|
424 } |
|
425 void push(const Address &address) { |
|
426 ma_lw(ScratchRegister, address); |
|
427 ma_push(ScratchRegister); |
|
428 } |
|
429 void push(const Register ®) { |
|
430 ma_push(reg); |
|
431 } |
|
432 void push(const FloatRegister ®) { |
|
433 ma_push(reg); |
|
434 } |
|
435 void pop(const Register ®) { |
|
436 ma_pop(reg); |
|
437 } |
|
438 void pop(const FloatRegister ®) { |
|
439 ma_pop(reg); |
|
440 } |
|
441 |
|
442 // Emit a branch that can be toggled to a non-operation. On MIPS we use |
|
443 // "andi" instruction to toggle the branch. |
|
444 // See ToggleToJmp(), ToggleToCmp(). |
|
445 CodeOffsetLabel toggledJump(Label *label); |
|
446 |
|
447 // Emit a "jalr" or "nop" instruction. ToggleCall can be used to patch |
|
448 // this instruction. |
|
449 CodeOffsetLabel toggledCall(JitCode *target, bool enabled); |
|
450 |
|
451 static size_t ToggledCallSize() { |
|
452 // Four instructions used in: MacroAssemblerMIPSCompat::toggledCall |
|
453 return 4 * sizeof(uint32_t); |
|
454 } |
|
455 |
|
456 CodeOffsetLabel pushWithPatch(ImmWord imm) { |
|
457 CodeOffsetLabel label = movWithPatch(imm, ScratchRegister); |
|
458 ma_push(ScratchRegister); |
|
459 return label; |
|
460 } |
|
461 |
|
462 CodeOffsetLabel movWithPatch(ImmWord imm, Register dest) { |
|
463 CodeOffsetLabel label = currentOffset(); |
|
464 ma_liPatchable(dest, Imm32(imm.value)); |
|
465 return label; |
|
466 } |
|
467 CodeOffsetLabel movWithPatch(ImmPtr imm, Register dest) { |
|
468 return movWithPatch(ImmWord(uintptr_t(imm.value)), dest); |
|
469 } |
|
470 |
|
471 void jump(Label *label) { |
|
472 ma_b(label); |
|
473 } |
|
474 void jump(Register reg) { |
|
475 as_jr(reg); |
|
476 as_nop(); |
|
477 } |
|
478 void jump(const Address &address) { |
|
479 ma_lw(ScratchRegister, address); |
|
480 as_jr(ScratchRegister); |
|
481 as_nop(); |
|
482 } |
|
483 |
|
484 void neg32(Register reg) { |
|
485 ma_negu(reg, reg); |
|
486 } |
|
487 void negl(Register reg) { |
|
488 ma_negu(reg, reg); |
|
489 } |
|
490 |
|
491 // Returns the register containing the type tag. |
|
492 Register splitTagForTest(const ValueOperand &value) { |
|
493 return value.typeReg(); |
|
494 } |
|
495 |
|
496 void branchTestGCThing(Condition cond, const Address &address, Label *label); |
|
497 void branchTestGCThing(Condition cond, const BaseIndex &src, Label *label); |
|
498 |
|
499 void branchTestPrimitive(Condition cond, const ValueOperand &value, Label *label); |
|
500 void branchTestPrimitive(Condition cond, const Register &tag, Label *label); |
|
501 |
|
502 void branchTestValue(Condition cond, const ValueOperand &value, const Value &v, Label *label); |
|
503 void branchTestValue(Condition cond, const Address &valaddr, const ValueOperand &value, |
|
504 Label *label); |
|
505 |
|
506 // unboxing code |
|
507 void unboxInt32(const ValueOperand &operand, const Register &dest); |
|
508 void unboxInt32(const Address &src, const Register &dest); |
|
509 void unboxBoolean(const ValueOperand &operand, const Register &dest); |
|
510 void unboxBoolean(const Address &src, const Register &dest); |
|
511 void unboxDouble(const ValueOperand &operand, const FloatRegister &dest); |
|
512 void unboxDouble(const Address &src, const FloatRegister &dest); |
|
513 void unboxString(const ValueOperand &operand, const Register &dest); |
|
514 void unboxString(const Address &src, const Register &dest); |
|
515 void unboxObject(const ValueOperand &src, const Register &dest); |
|
516 void unboxValue(const ValueOperand &src, AnyRegister dest); |
|
517 void unboxPrivate(const ValueOperand &src, Register dest); |
|
518 |
|
519 void notBoolean(const ValueOperand &val) { |
|
520 as_xori(val.payloadReg(), val.payloadReg(), 1); |
|
521 } |
|
522 |
|
523 // boxing code |
|
524 void boxDouble(const FloatRegister &src, const ValueOperand &dest); |
|
525 void boxNonDouble(JSValueType type, const Register &src, const ValueOperand &dest); |
|
526 |
|
527 // Extended unboxing API. If the payload is already in a register, returns |
|
528 // that register. Otherwise, provides a move to the given scratch register, |
|
529 // and returns that. |
|
530 Register extractObject(const Address &address, Register scratch); |
|
531 Register extractObject(const ValueOperand &value, Register scratch) { |
|
532 return value.payloadReg(); |
|
533 } |
|
534 Register extractInt32(const ValueOperand &value, Register scratch) { |
|
535 return value.payloadReg(); |
|
536 } |
|
537 Register extractBoolean(const ValueOperand &value, Register scratch) { |
|
538 return value.payloadReg(); |
|
539 } |
|
540 Register extractTag(const Address &address, Register scratch); |
|
541 Register extractTag(const BaseIndex &address, Register scratch); |
|
542 Register extractTag(const ValueOperand &value, Register scratch) { |
|
543 return value.typeReg(); |
|
544 } |
|
545 |
|
546 void boolValueToDouble(const ValueOperand &operand, const FloatRegister &dest); |
|
547 void int32ValueToDouble(const ValueOperand &operand, const FloatRegister &dest); |
|
548 void loadInt32OrDouble(const Address &address, const FloatRegister &dest); |
|
549 void loadInt32OrDouble(Register base, Register index, |
|
550 const FloatRegister &dest, int32_t shift = defaultShift); |
|
551 void loadConstantDouble(double dp, const FloatRegister &dest); |
|
552 |
|
553 void boolValueToFloat32(const ValueOperand &operand, const FloatRegister &dest); |
|
554 void int32ValueToFloat32(const ValueOperand &operand, const FloatRegister &dest); |
|
555 void loadConstantFloat32(float f, const FloatRegister &dest); |
|
556 |
|
557 void branchTestInt32(Condition cond, const ValueOperand &value, Label *label); |
|
558 void branchTestInt32(Condition cond, const Register &tag, Label *label); |
|
559 void branchTestInt32(Condition cond, const Address &address, Label *label); |
|
560 void branchTestInt32(Condition cond, const BaseIndex &src, Label *label); |
|
561 |
|
562 void branchTestBoolean(Condition cond, const ValueOperand &value, Label *label); |
|
563 void branchTestBoolean(Condition cond, const Register &tag, Label *label); |
|
564 void branchTestBoolean(Condition cond, const BaseIndex &src, Label *label); |
|
565 |
|
566 void branch32(Condition cond, Register lhs, Register rhs, Label *label) { |
|
567 ma_b(lhs, rhs, label, cond); |
|
568 } |
|
569 void branch32(Condition cond, Register lhs, Imm32 imm, Label *label) { |
|
570 ma_b(lhs, imm, label, cond); |
|
571 } |
|
572 void branch32(Condition cond, const Operand &lhs, Register rhs, Label *label) { |
|
573 if (lhs.getTag() == Operand::REG) { |
|
574 ma_b(lhs.toReg(), rhs, label, cond); |
|
575 } else { |
|
576 branch32(cond, lhs.toAddress(), rhs, label); |
|
577 } |
|
578 } |
|
579 void branch32(Condition cond, const Operand &lhs, Imm32 rhs, Label *label) { |
|
580 if (lhs.getTag() == Operand::REG) { |
|
581 ma_b(lhs.toReg(), rhs, label, cond); |
|
582 } else { |
|
583 branch32(cond, lhs.toAddress(), rhs, label); |
|
584 } |
|
585 } |
|
586 void branch32(Condition cond, const Address &lhs, Register rhs, Label *label) { |
|
587 ma_lw(ScratchRegister, lhs); |
|
588 ma_b(ScratchRegister, rhs, label, cond); |
|
589 } |
|
590 void branch32(Condition cond, const Address &lhs, Imm32 rhs, Label *label) { |
|
591 ma_lw(SecondScratchReg, lhs); |
|
592 ma_b(SecondScratchReg, rhs, label, cond); |
|
593 } |
|
594 void branchPtr(Condition cond, const Address &lhs, Register rhs, Label *label) { |
|
595 branch32(cond, lhs, rhs, label); |
|
596 } |
|
597 |
|
598 void branchPrivatePtr(Condition cond, const Address &lhs, ImmPtr ptr, Label *label) { |
|
599 branchPtr(cond, lhs, ptr, label); |
|
600 } |
|
601 |
|
602 void branchPrivatePtr(Condition cond, const Address &lhs, Register ptr, Label *label) { |
|
603 branchPtr(cond, lhs, ptr, label); |
|
604 } |
|
605 |
|
606 void branchPrivatePtr(Condition cond, Register lhs, ImmWord ptr, Label *label) { |
|
607 branchPtr(cond, lhs, ptr, label); |
|
608 } |
|
609 |
|
610 void branchTestDouble(Condition cond, const ValueOperand &value, Label *label); |
|
611 void branchTestDouble(Condition cond, const Register &tag, Label *label); |
|
612 void branchTestDouble(Condition cond, const Address &address, Label *label); |
|
613 void branchTestDouble(Condition cond, const BaseIndex &src, Label *label); |
|
614 |
|
615 void branchTestNull(Condition cond, const ValueOperand &value, Label *label); |
|
616 void branchTestNull(Condition cond, const Register &tag, Label *label); |
|
617 void branchTestNull(Condition cond, const BaseIndex &src, Label *label); |
|
618 |
|
619 void branchTestObject(Condition cond, const ValueOperand &value, Label *label); |
|
620 void branchTestObject(Condition cond, const Register &tag, Label *label); |
|
621 void branchTestObject(Condition cond, const BaseIndex &src, Label *label); |
|
622 |
|
623 void branchTestString(Condition cond, const ValueOperand &value, Label *label); |
|
624 void branchTestString(Condition cond, const Register &tag, Label *label); |
|
625 void branchTestString(Condition cond, const BaseIndex &src, Label *label); |
|
626 |
|
627 void branchTestUndefined(Condition cond, const ValueOperand &value, Label *label); |
|
628 void branchTestUndefined(Condition cond, const Register &tag, Label *label); |
|
629 void branchTestUndefined(Condition cond, const BaseIndex &src, Label *label); |
|
630 void branchTestUndefined(Condition cond, const Address &address, Label *label); |
|
631 |
|
632 void branchTestNumber(Condition cond, const ValueOperand &value, Label *label); |
|
633 void branchTestNumber(Condition cond, const Register &tag, Label *label); |
|
634 |
|
635 void branchTestMagic(Condition cond, const ValueOperand &value, Label *label); |
|
636 void branchTestMagic(Condition cond, const Register &tag, Label *label); |
|
637 void branchTestMagic(Condition cond, const Address &address, Label *label); |
|
638 void branchTestMagic(Condition cond, const BaseIndex &src, Label *label); |
|
639 |
|
640 void branchTestMagicValue(Condition cond, const ValueOperand &val, JSWhyMagic why, |
|
641 Label *label) { |
|
642 MOZ_ASSERT(cond == Equal || cond == NotEqual); |
|
643 // Test for magic |
|
644 Label notmagic; |
|
645 branchTestMagic(cond, val, ¬magic); |
|
646 // Test magic value |
|
647 branch32(cond, val.payloadReg(), Imm32(static_cast<int32_t>(why)), label); |
|
648 bind(¬magic); |
|
649 } |
|
650 |
|
651 void branchTestInt32Truthy(bool b, const ValueOperand &value, Label *label); |
|
652 |
|
653 void branchTestStringTruthy(bool b, const ValueOperand &value, Label *label); |
|
654 |
|
655 void branchTestDoubleTruthy(bool b, const FloatRegister &value, Label *label); |
|
656 |
|
657 void branchTestBooleanTruthy(bool b, const ValueOperand &operand, Label *label); |
|
658 |
|
659 void branchTest32(Condition cond, const Register &lhs, const Register &rhs, Label *label) { |
|
660 MOZ_ASSERT(cond == Zero || cond == NonZero || cond == Signed || cond == NotSigned); |
|
661 if (lhs == rhs) { |
|
662 ma_b(lhs, rhs, label, cond); |
|
663 } else { |
|
664 as_and(ScratchRegister, lhs, rhs); |
|
665 ma_b(ScratchRegister, ScratchRegister, label, cond); |
|
666 } |
|
667 } |
|
668 void branchTest32(Condition cond, const Register &lhs, Imm32 imm, Label *label) { |
|
669 ma_li(ScratchRegister, imm); |
|
670 branchTest32(cond, lhs, ScratchRegister, label); |
|
671 } |
|
672 void branchTest32(Condition cond, const Address &address, Imm32 imm, Label *label) { |
|
673 ma_lw(SecondScratchReg, address); |
|
674 branchTest32(cond, SecondScratchReg, imm, label); |
|
675 } |
|
676 void branchTestPtr(Condition cond, const Register &lhs, const Register &rhs, Label *label) { |
|
677 branchTest32(cond, lhs, rhs, label); |
|
678 } |
|
679 void branchTestPtr(Condition cond, const Register &lhs, const Imm32 rhs, Label *label) { |
|
680 branchTest32(cond, lhs, rhs, label); |
|
681 } |
|
682 void branchTestPtr(Condition cond, const Address &lhs, Imm32 imm, Label *label) { |
|
683 branchTest32(cond, lhs, imm, label); |
|
684 } |
|
685 void branchPtr(Condition cond, Register lhs, Register rhs, Label *label) { |
|
686 ma_b(lhs, rhs, label, cond); |
|
687 } |
|
688 void branchPtr(Condition cond, Register lhs, ImmGCPtr ptr, Label *label) { |
|
689 ma_li(ScratchRegister, ptr); |
|
690 ma_b(lhs, ScratchRegister, label, cond); |
|
691 } |
|
692 void branchPtr(Condition cond, Register lhs, ImmWord imm, Label *label) { |
|
693 ma_b(lhs, Imm32(imm.value), label, cond); |
|
694 } |
|
695 void branchPtr(Condition cond, Register lhs, ImmPtr imm, Label *label) { |
|
696 branchPtr(cond, lhs, ImmWord(uintptr_t(imm.value)), label); |
|
697 } |
|
698 void branchPtr(Condition cond, Register lhs, AsmJSImmPtr imm, Label *label) { |
|
699 movePtr(imm, ScratchRegister); |
|
700 branchPtr(cond, lhs, ScratchRegister, label); |
|
701 } |
|
702 void branchPtr(Condition cond, Register lhs, Imm32 imm, Label *label) { |
|
703 ma_b(lhs, imm, label, cond); |
|
704 } |
|
705 void decBranchPtr(Condition cond, const Register &lhs, Imm32 imm, Label *label) { |
|
706 subPtr(imm, lhs); |
|
707 branch32(cond, lhs, Imm32(0), label); |
|
708 } |
|
709 |
|
710 protected: |
|
711 uint32_t getType(const Value &val); |
|
712 void moveData(const Value &val, Register data); |
|
713 public: |
|
714 void moveValue(const Value &val, Register type, Register data); |
|
715 |
|
716 CodeOffsetJump jumpWithPatch(RepatchLabel *label); |
|
717 |
|
718 template <typename T> |
|
719 CodeOffsetJump branchPtrWithPatch(Condition cond, Register reg, T ptr, RepatchLabel *label) { |
|
720 movePtr(ptr, ScratchRegister); |
|
721 Label skipJump; |
|
722 ma_b(reg, ScratchRegister, &skipJump, InvertCondition(cond), ShortJump); |
|
723 CodeOffsetJump off = jumpWithPatch(label); |
|
724 bind(&skipJump); |
|
725 return off; |
|
726 } |
|
727 |
|
728 template <typename T> |
|
729 CodeOffsetJump branchPtrWithPatch(Condition cond, Address addr, T ptr, RepatchLabel *label) { |
|
730 loadPtr(addr, SecondScratchReg); |
|
731 movePtr(ptr, ScratchRegister); |
|
732 Label skipJump; |
|
733 ma_b(SecondScratchReg, ScratchRegister, &skipJump, InvertCondition(cond), ShortJump); |
|
734 CodeOffsetJump off = jumpWithPatch(label); |
|
735 bind(&skipJump); |
|
736 return off; |
|
737 } |
|
738 void branchPtr(Condition cond, Address addr, ImmGCPtr ptr, Label *label) { |
|
739 ma_lw(SecondScratchReg, addr); |
|
740 ma_li(ScratchRegister, ptr); |
|
741 ma_b(SecondScratchReg, ScratchRegister, label, cond); |
|
742 } |
|
743 void branchPtr(Condition cond, Address addr, ImmWord ptr, Label *label) { |
|
744 ma_lw(SecondScratchReg, addr); |
|
745 ma_b(SecondScratchReg, Imm32(ptr.value), label, cond); |
|
746 } |
|
747 void branchPtr(Condition cond, Address addr, ImmPtr ptr, Label *label) { |
|
748 branchPtr(cond, addr, ImmWord(uintptr_t(ptr.value)), label); |
|
749 } |
|
750 void branchPtr(Condition cond, const AbsoluteAddress &addr, const Register &ptr, Label *label) { |
|
751 loadPtr(addr, ScratchRegister); |
|
752 ma_b(ScratchRegister, ptr, label, cond); |
|
753 } |
|
754 void branchPtr(Condition cond, const AsmJSAbsoluteAddress &addr, const Register &ptr, |
|
755 Label *label) { |
|
756 loadPtr(addr, ScratchRegister); |
|
757 ma_b(ScratchRegister, ptr, label, cond); |
|
758 } |
|
759 void branch32(Condition cond, const AbsoluteAddress &lhs, Imm32 rhs, Label *label) { |
|
760 loadPtr(lhs, SecondScratchReg); // ma_b might use scratch |
|
761 ma_b(SecondScratchReg, rhs, label, cond); |
|
762 } |
|
763 void branch32(Condition cond, const AbsoluteAddress &lhs, const Register &rhs, Label *label) { |
|
764 loadPtr(lhs, ScratchRegister); |
|
765 ma_b(ScratchRegister, rhs, label, cond); |
|
766 } |
|
767 |
|
768 void loadUnboxedValue(Address address, MIRType type, AnyRegister dest) { |
|
769 if (dest.isFloat()) |
|
770 loadInt32OrDouble(address, dest.fpu()); |
|
771 else |
|
772 ma_lw(dest.gpr(), address); |
|
773 } |
|
774 |
|
775 void loadUnboxedValue(BaseIndex address, MIRType type, AnyRegister dest) { |
|
776 if (dest.isFloat()) |
|
777 loadInt32OrDouble(address.base, address.index, dest.fpu(), address.scale); |
|
778 else |
|
779 load32(address, dest.gpr()); |
|
780 } |
|
781 |
|
782 void moveValue(const Value &val, const ValueOperand &dest); |
|
783 |
|
784 void moveValue(const ValueOperand &src, const ValueOperand &dest) { |
|
785 MOZ_ASSERT(src.typeReg() != dest.payloadReg()); |
|
786 MOZ_ASSERT(src.payloadReg() != dest.typeReg()); |
|
787 if (src.typeReg() != dest.typeReg()) |
|
788 ma_move(dest.typeReg(), src.typeReg()); |
|
789 if (src.payloadReg() != dest.payloadReg()) |
|
790 ma_move(dest.payloadReg(), src.payloadReg()); |
|
791 } |
|
792 |
|
793 void storeValue(ValueOperand val, Operand dst); |
|
794 void storeValue(ValueOperand val, const BaseIndex &dest); |
|
795 void storeValue(JSValueType type, Register reg, BaseIndex dest); |
|
796 void storeValue(ValueOperand val, const Address &dest); |
|
797 void storeValue(JSValueType type, Register reg, Address dest); |
|
798 void storeValue(const Value &val, Address dest); |
|
799 void storeValue(const Value &val, BaseIndex dest); |
|
800 |
|
801 void loadValue(Address src, ValueOperand val); |
|
802 void loadValue(Operand dest, ValueOperand val) { |
|
803 loadValue(dest.toAddress(), val); |
|
804 } |
|
805 void loadValue(const BaseIndex &addr, ValueOperand val); |
|
806 void tagValue(JSValueType type, Register payload, ValueOperand dest); |
|
807 |
|
808 void pushValue(ValueOperand val); |
|
809 void popValue(ValueOperand val); |
|
810 void pushValue(const Value &val) { |
|
811 jsval_layout jv = JSVAL_TO_IMPL(val); |
|
812 push(Imm32(jv.s.tag)); |
|
813 if (val.isMarkable()) |
|
814 push(ImmGCPtr(reinterpret_cast<gc::Cell *>(val.toGCThing()))); |
|
815 else |
|
816 push(Imm32(jv.s.payload.i32)); |
|
817 } |
|
818 void pushValue(JSValueType type, Register reg) { |
|
819 push(ImmTag(JSVAL_TYPE_TO_TAG(type))); |
|
820 ma_push(reg); |
|
821 } |
|
822 void pushValue(const Address &addr); |
|
823 void Push(const ValueOperand &val) { |
|
824 pushValue(val); |
|
825 framePushed_ += sizeof(Value); |
|
826 } |
|
827 void Pop(const ValueOperand &val) { |
|
828 popValue(val); |
|
829 framePushed_ -= sizeof(Value); |
|
830 } |
|
831 void storePayload(const Value &val, Address dest); |
|
832 void storePayload(Register src, Address dest); |
|
833 void storePayload(const Value &val, Register base, Register index, int32_t shift = defaultShift); |
|
834 void storePayload(Register src, Register base, Register index, int32_t shift = defaultShift); |
|
835 void storeTypeTag(ImmTag tag, Address dest); |
|
836 void storeTypeTag(ImmTag tag, Register base, Register index, int32_t shift = defaultShift); |
|
837 |
|
838 void makeFrameDescriptor(Register frameSizeReg, FrameType type) { |
|
839 ma_sll(frameSizeReg, frameSizeReg, Imm32(FRAMESIZE_SHIFT)); |
|
840 ma_or(frameSizeReg, frameSizeReg, Imm32(type)); |
|
841 } |
|
842 |
|
843 void linkExitFrame(); |
|
844 void linkParallelExitFrame(const Register &pt); |
|
845 void handleFailureWithHandler(void *handler); |
|
846 void handleFailureWithHandlerTail(); |
|
847 |
|
848 ///////////////////////////////////////////////////////////////// |
|
849 // Common interface. |
|
850 ///////////////////////////////////////////////////////////////// |
|
851 public: |
|
852 // The following functions are exposed for use in platform-shared code. |
|
853 void Push(const Register ®) { |
|
854 ma_push(reg); |
|
855 adjustFrame(sizeof(intptr_t)); |
|
856 } |
|
857 void Push(const Imm32 imm) { |
|
858 ma_li(ScratchRegister, imm); |
|
859 ma_push(ScratchRegister); |
|
860 adjustFrame(sizeof(intptr_t)); |
|
861 } |
|
862 void Push(const ImmWord imm) { |
|
863 ma_li(ScratchRegister, Imm32(imm.value)); |
|
864 ma_push(ScratchRegister); |
|
865 adjustFrame(sizeof(intptr_t)); |
|
866 } |
|
867 void Push(const ImmPtr imm) { |
|
868 Push(ImmWord(uintptr_t(imm.value))); |
|
869 } |
|
870 void Push(const ImmGCPtr ptr) { |
|
871 ma_li(ScratchRegister, ptr); |
|
872 ma_push(ScratchRegister); |
|
873 adjustFrame(sizeof(intptr_t)); |
|
874 } |
|
875 void Push(const FloatRegister &f) { |
|
876 ma_push(f); |
|
877 adjustFrame(sizeof(double)); |
|
878 } |
|
879 |
|
880 CodeOffsetLabel PushWithPatch(const ImmWord &word) { |
|
881 framePushed_ += sizeof(word.value); |
|
882 return pushWithPatch(word); |
|
883 } |
|
884 CodeOffsetLabel PushWithPatch(const ImmPtr &imm) { |
|
885 return PushWithPatch(ImmWord(uintptr_t(imm.value))); |
|
886 } |
|
887 |
|
888 void Pop(const Register ®) { |
|
889 ma_pop(reg); |
|
890 adjustFrame(-sizeof(intptr_t)); |
|
891 } |
|
892 void implicitPop(uint32_t args) { |
|
893 MOZ_ASSERT(args % sizeof(intptr_t) == 0); |
|
894 adjustFrame(-args); |
|
895 } |
|
896 uint32_t framePushed() const { |
|
897 return framePushed_; |
|
898 } |
|
899 void setFramePushed(uint32_t framePushed) { |
|
900 framePushed_ = framePushed; |
|
901 } |
|
902 |
|
903 // Builds an exit frame on the stack, with a return address to an internal |
|
904 // non-function. Returns offset to be passed to markSafepointAt(). |
|
905 bool buildFakeExitFrame(const Register &scratch, uint32_t *offset); |
|
906 |
|
907 void callWithExitFrame(JitCode *target); |
|
908 void callWithExitFrame(JitCode *target, Register dynStack); |
|
909 |
|
910 // Makes an Ion call using the only two methods that it is sane for |
|
911 // indep code to make a call |
|
912 void callIon(const Register &callee); |
|
913 |
|
914 void reserveStack(uint32_t amount); |
|
915 void freeStack(uint32_t amount); |
|
916 void freeStack(Register amount); |
|
917 |
|
918 void add32(Register src, Register dest); |
|
919 void add32(Imm32 imm, Register dest); |
|
920 void add32(Imm32 imm, const Address &dest); |
|
921 void sub32(Imm32 imm, Register dest); |
|
922 void sub32(Register src, Register dest); |
|
923 |
|
924 void and32(Imm32 imm, Register dest); |
|
925 void and32(Imm32 imm, const Address &dest); |
|
926 void or32(Imm32 imm, const Address &dest); |
|
927 void xor32(Imm32 imm, Register dest); |
|
928 void xorPtr(Imm32 imm, Register dest); |
|
929 void xorPtr(Register src, Register dest); |
|
930 void orPtr(Imm32 imm, Register dest); |
|
931 void orPtr(Register src, Register dest); |
|
932 void andPtr(Imm32 imm, Register dest); |
|
933 void andPtr(Register src, Register dest); |
|
934 void addPtr(Register src, Register dest); |
|
935 void subPtr(Register src, Register dest); |
|
936 void addPtr(const Address &src, Register dest); |
|
937 void not32(Register reg); |
|
938 |
|
939 void move32(const Imm32 &imm, const Register &dest); |
|
940 void move32(const Register &src, const Register &dest); |
|
941 |
|
942 void movePtr(const Register &src, const Register &dest); |
|
943 void movePtr(const ImmWord &imm, const Register &dest); |
|
944 void movePtr(const ImmPtr &imm, const Register &dest); |
|
945 void movePtr(const AsmJSImmPtr &imm, const Register &dest); |
|
946 void movePtr(const ImmGCPtr &imm, const Register &dest); |
|
947 |
|
948 void load8SignExtend(const Address &address, const Register &dest); |
|
949 void load8SignExtend(const BaseIndex &src, const Register &dest); |
|
950 |
|
951 void load8ZeroExtend(const Address &address, const Register &dest); |
|
952 void load8ZeroExtend(const BaseIndex &src, const Register &dest); |
|
953 |
|
954 void load16SignExtend(const Address &address, const Register &dest); |
|
955 void load16SignExtend(const BaseIndex &src, const Register &dest); |
|
956 |
|
957 void load16ZeroExtend(const Address &address, const Register &dest); |
|
958 void load16ZeroExtend(const BaseIndex &src, const Register &dest); |
|
959 |
|
960 void load32(const Address &address, const Register &dest); |
|
961 void load32(const BaseIndex &address, const Register &dest); |
|
962 void load32(const AbsoluteAddress &address, const Register &dest); |
|
963 |
|
964 void loadPtr(const Address &address, const Register &dest); |
|
965 void loadPtr(const BaseIndex &src, const Register &dest); |
|
966 void loadPtr(const AbsoluteAddress &address, const Register &dest); |
|
967 void loadPtr(const AsmJSAbsoluteAddress &address, const Register &dest); |
|
968 |
|
969 void loadPrivate(const Address &address, const Register &dest); |
|
970 |
|
971 void loadDouble(const Address &addr, const FloatRegister &dest); |
|
972 void loadDouble(const BaseIndex &src, const FloatRegister &dest); |
|
973 |
|
974 // Load a float value into a register, then expand it to a double. |
|
975 void loadFloatAsDouble(const Address &addr, const FloatRegister &dest); |
|
976 void loadFloatAsDouble(const BaseIndex &src, const FloatRegister &dest); |
|
977 |
|
978 void loadFloat32(const Address &addr, const FloatRegister &dest); |
|
979 void loadFloat32(const BaseIndex &src, const FloatRegister &dest); |
|
980 |
|
981 void store8(const Register &src, const Address &address); |
|
982 void store8(const Imm32 &imm, const Address &address); |
|
983 void store8(const Register &src, const BaseIndex &address); |
|
984 void store8(const Imm32 &imm, const BaseIndex &address); |
|
985 |
|
986 void store16(const Register &src, const Address &address); |
|
987 void store16(const Imm32 &imm, const Address &address); |
|
988 void store16(const Register &src, const BaseIndex &address); |
|
989 void store16(const Imm32 &imm, const BaseIndex &address); |
|
990 |
|
991 void store32(const Register &src, const AbsoluteAddress &address); |
|
992 void store32(const Register &src, const Address &address); |
|
993 void store32(const Register &src, const BaseIndex &address); |
|
994 void store32(const Imm32 &src, const Address &address); |
|
995 void store32(const Imm32 &src, const BaseIndex &address); |
|
996 |
|
997 void storePtr(ImmWord imm, const Address &address); |
|
998 void storePtr(ImmPtr imm, const Address &address); |
|
999 void storePtr(ImmGCPtr imm, const Address &address); |
|
1000 void storePtr(Register src, const Address &address); |
|
1001 void storePtr(const Register &src, const AbsoluteAddress &dest); |
|
1002 void storeDouble(FloatRegister src, Address addr) { |
|
1003 ma_sd(src, addr); |
|
1004 } |
|
1005 void storeDouble(FloatRegister src, BaseIndex addr) { |
|
1006 MOZ_ASSERT(addr.offset == 0); |
|
1007 ma_sd(src, addr); |
|
1008 } |
|
1009 void moveDouble(FloatRegister src, FloatRegister dest) { |
|
1010 as_movd(dest, src); |
|
1011 } |
|
1012 |
|
1013 void storeFloat32(FloatRegister src, Address addr) { |
|
1014 ma_ss(src, addr); |
|
1015 } |
|
1016 void storeFloat32(FloatRegister src, BaseIndex addr) { |
|
1017 MOZ_ASSERT(addr.offset == 0); |
|
1018 ma_ss(src, addr); |
|
1019 } |
|
1020 |
|
1021 void zeroDouble(FloatRegister reg) { |
|
1022 moveToDoubleLo(zero, reg); |
|
1023 moveToDoubleHi(zero, reg); |
|
1024 } |
|
1025 |
|
1026 void clampIntToUint8(Register reg) { |
|
1027 // look at (reg >> 8) if it is 0, then src shouldn't be clamped |
|
1028 // if it is <0, then we want to clamp to 0, |
|
1029 // otherwise, we wish to clamp to 255 |
|
1030 Label done; |
|
1031 ma_move(ScratchRegister, reg); |
|
1032 as_sra(ScratchRegister, ScratchRegister, 8); |
|
1033 ma_b(ScratchRegister, ScratchRegister, &done, Assembler::Zero, ShortJump); |
|
1034 { |
|
1035 Label negative; |
|
1036 ma_b(ScratchRegister, ScratchRegister, &negative, Assembler::Signed, ShortJump); |
|
1037 { |
|
1038 ma_li(reg, Imm32(255)); |
|
1039 ma_b(&done, ShortJump); |
|
1040 } |
|
1041 bind(&negative); |
|
1042 { |
|
1043 ma_move(reg, zero); |
|
1044 } |
|
1045 } |
|
1046 bind(&done); |
|
1047 } |
|
1048 |
|
1049 void subPtr(Imm32 imm, const Register dest); |
|
1050 void addPtr(Imm32 imm, const Register dest); |
|
1051 void addPtr(Imm32 imm, const Address &dest); |
|
1052 void addPtr(ImmWord imm, const Register dest) { |
|
1053 addPtr(Imm32(imm.value), dest); |
|
1054 } |
|
1055 void addPtr(ImmPtr imm, const Register dest) { |
|
1056 addPtr(ImmWord(uintptr_t(imm.value)), dest); |
|
1057 } |
|
1058 |
|
1059 void breakpoint(); |
|
1060 |
|
1061 void branchDouble(DoubleCondition cond, const FloatRegister &lhs, const FloatRegister &rhs, |
|
1062 Label *label); |
|
1063 |
|
1064 void branchFloat(DoubleCondition cond, const FloatRegister &lhs, const FloatRegister &rhs, |
|
1065 Label *label); |
|
1066 |
|
1067 void checkStackAlignment(); |
|
1068 |
|
1069 void alignPointerUp(Register src, Register dest, uint32_t alignment); |
|
1070 |
|
1071 void rshiftPtr(Imm32 imm, Register dest) { |
|
1072 ma_srl(dest, dest, imm); |
|
1073 } |
|
1074 void lshiftPtr(Imm32 imm, Register dest) { |
|
1075 ma_sll(dest, dest, imm); |
|
1076 } |
|
1077 |
|
1078 // If source is a double, load it into dest. If source is int32, |
|
1079 // convert it to double. Else, branch to failure. |
|
1080 void ensureDouble(const ValueOperand &source, FloatRegister dest, Label *failure); |
|
1081 |
|
1082 // Setup a call to C/C++ code, given the number of general arguments it |
|
1083 // takes. Note that this only supports cdecl. |
|
1084 // |
|
1085 // In order for alignment to work correctly, the MacroAssembler must have a |
|
1086 // consistent view of the stack displacement. It is okay to call "push" |
|
1087 // manually, however, if the stack alignment were to change, the macro |
|
1088 // assembler should be notified before starting a call. |
|
1089 void setupAlignedABICall(uint32_t args); |
|
1090 |
|
1091 // Sets up an ABI call for when the alignment is not known. This may need a |
|
1092 // scratch register. |
|
1093 void setupUnalignedABICall(uint32_t args, const Register &scratch); |
|
1094 |
|
1095 // Arguments must be assigned in a left-to-right order. This process may |
|
1096 // temporarily use more stack, in which case sp-relative addresses will be |
|
1097 // automatically adjusted. It is extremely important that sp-relative |
|
1098 // addresses are computed *after* setupABICall(). Furthermore, no |
|
1099 // operations should be emitted while setting arguments. |
|
1100 void passABIArg(const MoveOperand &from, MoveOp::Type type); |
|
1101 void passABIArg(const Register ®); |
|
1102 void passABIArg(const FloatRegister ®, MoveOp::Type type); |
|
1103 void passABIArg(const ValueOperand ®s); |
|
1104 |
|
1105 protected: |
|
1106 bool buildOOLFakeExitFrame(void *fakeReturnAddr); |
|
1107 |
|
1108 private: |
|
1109 void callWithABIPre(uint32_t *stackAdjust); |
|
1110 void callWithABIPost(uint32_t stackAdjust, MoveOp::Type result); |
|
1111 |
|
1112 public: |
|
1113 // Emits a call to a C/C++ function, resolving all argument moves. |
|
1114 void callWithABI(void *fun, MoveOp::Type result = MoveOp::GENERAL); |
|
1115 void callWithABI(AsmJSImmPtr imm, MoveOp::Type result = MoveOp::GENERAL); |
|
1116 void callWithABI(const Address &fun, MoveOp::Type result = MoveOp::GENERAL); |
|
1117 |
|
1118 CodeOffsetLabel labelForPatch() { |
|
1119 return CodeOffsetLabel(nextOffset().getOffset()); |
|
1120 } |
|
1121 |
|
1122 void memIntToValue(Address Source, Address Dest) { |
|
1123 MOZ_ASSUME_UNREACHABLE("NYI"); |
|
1124 } |
|
1125 |
|
1126 void lea(Operand addr, Register dest) { |
|
1127 MOZ_ASSUME_UNREACHABLE("NYI"); |
|
1128 } |
|
1129 |
|
1130 void abiret() { |
|
1131 MOZ_ASSUME_UNREACHABLE("NYI"); |
|
1132 } |
|
1133 |
|
1134 void ma_storeImm(Imm32 imm, const Address &addr) { |
|
1135 ma_sw(imm, addr); |
|
1136 } |
|
1137 |
|
1138 BufferOffset ma_BoundsCheck(Register bounded) { |
|
1139 BufferOffset bo = m_buffer.nextOffset(); |
|
1140 ma_liPatchable(bounded, Imm32(0)); |
|
1141 return bo; |
|
1142 } |
|
1143 |
|
1144 void moveFloat32(FloatRegister src, FloatRegister dest) { |
|
1145 as_movs(dest, src); |
|
1146 } |
|
1147 |
|
1148 void branchPtrInNurseryRange(Register ptr, Register temp, Label *label); |
|
1149 }; |
|
1150 |
|
1151 typedef MacroAssemblerMIPSCompat MacroAssemblerSpecific; |
|
1152 |
|
1153 } // namespace jit |
|
1154 } // namespace js |
|
1155 |
|
1156 #endif /* jit_mips_MacroAssembler_mips_h */ |