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_x86_MacroAssembler_x86_inl_h
8 #define jit_x86_MacroAssembler_x86_inl_h
9
10 #include "jit/x86/MacroAssembler-x86.h"
11
12 #include "jit/x86-shared/MacroAssembler-x86-shared-inl.h"
13
14 namespace js {
15 namespace jit {
16
17 //{{{ check_macroassembler_style
18
19 void
move64(Imm64 imm,Register64 dest)20 MacroAssembler::move64(Imm64 imm, Register64 dest)
21 {
22 movl(Imm32(imm.value & 0xFFFFFFFFL), dest.low);
23 movl(Imm32((imm.value >> 32) & 0xFFFFFFFFL), dest.high);
24 }
25
26 void
move64(Register64 src,Register64 dest)27 MacroAssembler::move64(Register64 src, Register64 dest)
28 {
29 movl(src.low, dest.low);
30 movl(src.high, dest.high);
31 }
32
33 // ===============================================================
34 // Logical functions
35
36 void
andPtr(Register src,Register dest)37 MacroAssembler::andPtr(Register src, Register dest)
38 {
39 andl(src, dest);
40 }
41
42 void
andPtr(Imm32 imm,Register dest)43 MacroAssembler::andPtr(Imm32 imm, Register dest)
44 {
45 andl(imm, dest);
46 }
47
48 void
and64(Imm64 imm,Register64 dest)49 MacroAssembler::and64(Imm64 imm, Register64 dest)
50 {
51 if (imm.low().value != int32_t(0xFFFFFFFF))
52 andl(imm.low(), dest.low);
53 if (imm.hi().value != int32_t(0xFFFFFFFF))
54 andl(imm.hi(), dest.high);
55 }
56
57 void
or64(Imm64 imm,Register64 dest)58 MacroAssembler::or64(Imm64 imm, Register64 dest)
59 {
60 if (imm.low().value != 0)
61 orl(imm.low(), dest.low);
62 if (imm.hi().value != 0)
63 orl(imm.hi(), dest.high);
64 }
65
66 void
xor64(Imm64 imm,Register64 dest)67 MacroAssembler::xor64(Imm64 imm, Register64 dest)
68 {
69 if (imm.low().value != 0)
70 xorl(imm.low(), dest.low);
71 if (imm.hi().value != 0)
72 xorl(imm.hi(), dest.high);
73 }
74
75 void
orPtr(Register src,Register dest)76 MacroAssembler::orPtr(Register src, Register dest)
77 {
78 orl(src, dest);
79 }
80
81 void
orPtr(Imm32 imm,Register dest)82 MacroAssembler::orPtr(Imm32 imm, Register dest)
83 {
84 orl(imm, dest);
85 }
86
87 void
and64(Register64 src,Register64 dest)88 MacroAssembler::and64(Register64 src, Register64 dest)
89 {
90 andl(src.low, dest.low);
91 andl(src.high, dest.high);
92 }
93
94 void
or64(Register64 src,Register64 dest)95 MacroAssembler::or64(Register64 src, Register64 dest)
96 {
97 orl(src.low, dest.low);
98 orl(src.high, dest.high);
99 }
100
101 void
xor64(Register64 src,Register64 dest)102 MacroAssembler::xor64(Register64 src, Register64 dest)
103 {
104 xorl(src.low, dest.low);
105 xorl(src.high, dest.high);
106 }
107
108 void
xorPtr(Register src,Register dest)109 MacroAssembler::xorPtr(Register src, Register dest)
110 {
111 xorl(src, dest);
112 }
113
114 void
xorPtr(Imm32 imm,Register dest)115 MacroAssembler::xorPtr(Imm32 imm, Register dest)
116 {
117 xorl(imm, dest);
118 }
119
120 // ===============================================================
121 // Arithmetic functions
122
123 void
addPtr(Register src,Register dest)124 MacroAssembler::addPtr(Register src, Register dest)
125 {
126 addl(src, dest);
127 }
128
129 void
addPtr(Imm32 imm,Register dest)130 MacroAssembler::addPtr(Imm32 imm, Register dest)
131 {
132 addl(imm, dest);
133 }
134
135 void
addPtr(ImmWord imm,Register dest)136 MacroAssembler::addPtr(ImmWord imm, Register dest)
137 {
138 addl(Imm32(imm.value), dest);
139 }
140
141 void
addPtr(Imm32 imm,const Address & dest)142 MacroAssembler::addPtr(Imm32 imm, const Address& dest)
143 {
144 addl(imm, Operand(dest));
145 }
146
147 void
addPtr(Imm32 imm,const AbsoluteAddress & dest)148 MacroAssembler::addPtr(Imm32 imm, const AbsoluteAddress& dest)
149 {
150 addl(imm, Operand(dest));
151 }
152
153 void
addPtr(const Address & src,Register dest)154 MacroAssembler::addPtr(const Address& src, Register dest)
155 {
156 addl(Operand(src), dest);
157 }
158
159 void
add64(Register64 src,Register64 dest)160 MacroAssembler::add64(Register64 src, Register64 dest)
161 {
162 addl(src.low, dest.low);
163 adcl(src.high, dest.high);
164 }
165
166 void
add64(Imm32 imm,Register64 dest)167 MacroAssembler::add64(Imm32 imm, Register64 dest)
168 {
169 addl(imm, dest.low);
170 adcl(Imm32(0), dest.high);
171 }
172
173 void
add64(Imm64 imm,Register64 dest)174 MacroAssembler::add64(Imm64 imm, Register64 dest)
175 {
176 if (imm.low().value == 0) {
177 addl(imm.hi(), dest.high);
178 return;
179 }
180 addl(imm.low(), dest.low);
181 adcl(imm.hi(), dest.high);
182 }
183
184 void
addConstantDouble(double d,FloatRegister dest)185 MacroAssembler::addConstantDouble(double d, FloatRegister dest)
186 {
187 Double* dbl = getDouble(wasm::RawF64(d));
188 if (!dbl)
189 return;
190 masm.vaddsd_mr(nullptr, dest.encoding(), dest.encoding());
191 propagateOOM(dbl->uses.append(CodeOffset(masm.size())));
192 }
193
194 void
subPtr(Register src,Register dest)195 MacroAssembler::subPtr(Register src, Register dest)
196 {
197 subl(src, dest);
198 }
199
200 void
subPtr(Register src,const Address & dest)201 MacroAssembler::subPtr(Register src, const Address& dest)
202 {
203 subl(src, Operand(dest));
204 }
205
206 void
subPtr(Imm32 imm,Register dest)207 MacroAssembler::subPtr(Imm32 imm, Register dest)
208 {
209 subl(imm, dest);
210 }
211
212 void
subPtr(const Address & addr,Register dest)213 MacroAssembler::subPtr(const Address& addr, Register dest)
214 {
215 subl(Operand(addr), dest);
216 }
217
218 void
sub64(Register64 src,Register64 dest)219 MacroAssembler::sub64(Register64 src, Register64 dest)
220 {
221 subl(src.low, dest.low);
222 sbbl(src.high, dest.high);
223 }
224
225 void
sub64(Imm64 imm,Register64 dest)226 MacroAssembler::sub64(Imm64 imm, Register64 dest)
227 {
228 if (imm.low().value == 0) {
229 subl(imm.hi(), dest.high);
230 return;
231 }
232 subl(imm.low(), dest.low);
233 sbbl(imm.hi(), dest.high);
234 }
235
236 // Note: this function clobbers eax and edx.
237 void
mul64(Imm64 imm,const Register64 & dest)238 MacroAssembler::mul64(Imm64 imm, const Register64& dest)
239 {
240 // LOW32 = LOW(LOW(dest) * LOW(imm));
241 // HIGH32 = LOW(HIGH(dest) * LOW(imm)) [multiply imm into upper bits]
242 // + LOW(LOW(dest) * HIGH(imm)) [multiply dest into upper bits]
243 // + HIGH(LOW(dest) * LOW(imm)) [carry]
244
245 MOZ_ASSERT(dest.low != eax && dest.low != edx);
246 MOZ_ASSERT(dest.high != eax && dest.high != edx);
247
248 // HIGH(dest) = LOW(HIGH(dest) * LOW(imm));
249 movl(Imm32(imm.value & 0xFFFFFFFFL), edx);
250 imull(edx, dest.high);
251
252 // edx:eax = LOW(dest) * LOW(imm);
253 movl(Imm32(imm.value & 0xFFFFFFFFL), edx);
254 movl(dest.low, eax);
255 mull(edx);
256
257 // HIGH(dest) += edx;
258 addl(edx, dest.high);
259
260 // HIGH(dest) += LOW(LOW(dest) * HIGH(imm));
261 if (((imm.value >> 32) & 0xFFFFFFFFL) == 5)
262 leal(Operand(dest.low, dest.low, TimesFour), edx);
263 else
264 MOZ_CRASH("Unsupported imm");
265 addl(edx, dest.high);
266
267 // LOW(dest) = eax;
268 movl(eax, dest.low);
269 }
270
271 void
mul64(Imm64 imm,const Register64 & dest,const Register temp)272 MacroAssembler::mul64(Imm64 imm, const Register64& dest, const Register temp)
273 {
274 // LOW32 = LOW(LOW(dest) * LOW(src)); (1)
275 // HIGH32 = LOW(HIGH(dest) * LOW(src)) [multiply src into upper bits] (2)
276 // + LOW(LOW(dest) * HIGH(src)) [multiply dest into upper bits] (3)
277 // + HIGH(LOW(dest) * LOW(src)) [carry] (4)
278
279 MOZ_ASSERT(dest == Register64(edx, eax));
280 MOZ_ASSERT(temp != edx && temp != eax);
281
282 movl(dest.low, temp);
283
284 // Compute mul64
285 imull(imm.low(), dest.high); // (2)
286 imull(imm.hi(), temp); // (3)
287 addl(dest.high, temp);
288 movl(imm.low(), dest.high);
289 mull(dest.high/*, dest.low*/); // (4) + (1) output in edx:eax (dest_hi:dest_lo)
290 addl(temp, dest.high);
291 }
292
293 void
mul64(const Register64 & src,const Register64 & dest,const Register temp)294 MacroAssembler::mul64(const Register64& src, const Register64& dest, const Register temp)
295 {
296 // LOW32 = LOW(LOW(dest) * LOW(src)); (1)
297 // HIGH32 = LOW(HIGH(dest) * LOW(src)) [multiply src into upper bits] (2)
298 // + LOW(LOW(dest) * HIGH(src)) [multiply dest into upper bits] (3)
299 // + HIGH(LOW(dest) * LOW(src)) [carry] (4)
300
301 MOZ_ASSERT(dest == Register64(edx, eax));
302 MOZ_ASSERT(src != Register64(edx, eax) && src != Register64(eax, edx));
303
304 // Make sure the rhs.high isn't the dest.high register anymore.
305 // This saves us from doing other register moves.
306 movl(dest.low, temp);
307
308 // Compute mul64
309 imull(src.low, dest.high); // (2)
310 imull(src.high, temp); // (3)
311 addl(dest.high, temp);
312 movl(src.low, dest.high);
313 mull(dest.high/*, dest.low*/); // (4) + (1) output in edx:eax (dest_hi:dest_lo)
314 addl(temp, dest.high);
315 }
316
317 void
mulBy3(Register src,Register dest)318 MacroAssembler::mulBy3(Register src, Register dest)
319 {
320 lea(Operand(src, src, TimesTwo), dest);
321 }
322
323 void
mulDoublePtr(ImmPtr imm,Register temp,FloatRegister dest)324 MacroAssembler::mulDoublePtr(ImmPtr imm, Register temp, FloatRegister dest)
325 {
326 movl(imm, temp);
327 vmulsd(Operand(temp, 0), dest, dest);
328 }
329
330 void
inc64(AbsoluteAddress dest)331 MacroAssembler::inc64(AbsoluteAddress dest)
332 {
333 addl(Imm32(1), Operand(dest));
334 Label noOverflow;
335 j(NonZero, &noOverflow);
336 addl(Imm32(1), Operand(dest.offset(4)));
337 bind(&noOverflow);
338 }
339
340 void
neg64(Register64 reg)341 MacroAssembler::neg64(Register64 reg)
342 {
343 negl(reg.low);
344 adcl(Imm32(0), reg.high);
345 negl(reg.high);
346 }
347
348 // ===============================================================
349 // Shift functions
350
351 void
lshiftPtr(Imm32 imm,Register dest)352 MacroAssembler::lshiftPtr(Imm32 imm, Register dest)
353 {
354 MOZ_ASSERT(0 <= imm.value && imm.value < 32);
355 shll(imm, dest);
356 }
357
358 void
lshift64(Imm32 imm,Register64 dest)359 MacroAssembler::lshift64(Imm32 imm, Register64 dest)
360 {
361 MOZ_ASSERT(0 <= imm.value && imm.value < 64);
362 if (imm.value < 32) {
363 shldl(imm, dest.low, dest.high);
364 shll(imm, dest.low);
365 return;
366 }
367
368 mov(dest.low, dest.high);
369 shll(Imm32(imm.value & 0x1f), dest.high);
370 xorl(dest.low, dest.low);
371 }
372
373 void
lshift64(Register shift,Register64 srcDest)374 MacroAssembler::lshift64(Register shift, Register64 srcDest)
375 {
376 MOZ_ASSERT(shift == ecx);
377 MOZ_ASSERT(srcDest.low != ecx && srcDest.high != ecx);
378
379 Label done;
380
381 shldl_cl(srcDest.low, srcDest.high);
382 shll_cl(srcDest.low);
383
384 testl(Imm32(0x20), ecx);
385 j(Condition::Equal, &done);
386
387 // 32 - 63 bit shift
388 movl(srcDest.low, srcDest.high);
389 xorl(srcDest.low, srcDest.low);
390
391 bind(&done);
392 }
393
394 void
rshiftPtr(Imm32 imm,Register dest)395 MacroAssembler::rshiftPtr(Imm32 imm, Register dest)
396 {
397 MOZ_ASSERT(0 <= imm.value && imm.value < 32);
398 shrl(imm, dest);
399 }
400
401 void
rshift64(Imm32 imm,Register64 dest)402 MacroAssembler::rshift64(Imm32 imm, Register64 dest)
403 {
404 MOZ_ASSERT(0 <= imm.value && imm.value < 64);
405 if (imm.value < 32) {
406 shrdl(imm, dest.high, dest.low);
407 shrl(imm, dest.high);
408 return;
409 }
410
411 movl(dest.high, dest.low);
412 shrl(Imm32(imm.value & 0x1f), dest.low);
413 xorl(dest.high, dest.high);
414 }
415
416 void
rshift64(Register shift,Register64 srcDest)417 MacroAssembler::rshift64(Register shift, Register64 srcDest)
418 {
419 MOZ_ASSERT(shift == ecx);
420 MOZ_ASSERT(srcDest.low != ecx && srcDest.high != ecx);
421
422 Label done;
423
424 shrdl_cl(srcDest.high, srcDest.low);
425 shrl_cl(srcDest.high);
426
427 testl(Imm32(0x20), ecx);
428 j(Condition::Equal, &done);
429
430 // 32 - 63 bit shift
431 movl(srcDest.high, srcDest.low);
432 xorl(srcDest.high, srcDest.high);
433
434 bind(&done);
435 }
436
437 void
rshiftPtrArithmetic(Imm32 imm,Register dest)438 MacroAssembler::rshiftPtrArithmetic(Imm32 imm, Register dest)
439 {
440 MOZ_ASSERT(0 <= imm.value && imm.value < 32);
441 sarl(imm, dest);
442 }
443
444 void
rshift64Arithmetic(Imm32 imm,Register64 dest)445 MacroAssembler::rshift64Arithmetic(Imm32 imm, Register64 dest)
446 {
447 MOZ_ASSERT(0 <= imm.value && imm.value < 64);
448 if (imm.value < 32) {
449 shrdl(imm, dest.high, dest.low);
450 sarl(imm, dest.high);
451 return;
452 }
453
454 movl(dest.high, dest.low);
455 sarl(Imm32(imm.value & 0x1f), dest.low);
456 sarl(Imm32(0x1f), dest.high);
457 }
458
459 void
rshift64Arithmetic(Register shift,Register64 srcDest)460 MacroAssembler::rshift64Arithmetic(Register shift, Register64 srcDest)
461 {
462 MOZ_ASSERT(shift == ecx);
463 MOZ_ASSERT(srcDest.low != ecx && srcDest.high != ecx);
464
465 Label done;
466
467 shrdl_cl(srcDest.high, srcDest.low);
468 sarl_cl(srcDest.high);
469
470 testl(Imm32(0x20), ecx);
471 j(Condition::Equal, &done);
472
473 // 32 - 63 bit shift
474 movl(srcDest.high, srcDest.low);
475 sarl(Imm32(0x1f), srcDest.high);
476
477 bind(&done);
478 }
479
480 // ===============================================================
481 // Rotation functions
482
483 void
rotateLeft64(Register count,Register64 src,Register64 dest,Register temp)484 MacroAssembler::rotateLeft64(Register count, Register64 src, Register64 dest, Register temp)
485 {
486 MOZ_ASSERT(src == dest, "defineReuseInput");
487 MOZ_ASSERT(count == ecx, "defineFixed(ecx)");
488
489 Label done;
490
491 movl(dest.high, temp);
492 shldl_cl(dest.low, dest.high);
493 shldl_cl(temp, dest.low);
494
495 testl(Imm32(0x20), count);
496 j(Condition::Equal, &done);
497 xchgl(dest.high, dest.low);
498
499 bind(&done);
500 }
501
502 void
rotateRight64(Register count,Register64 src,Register64 dest,Register temp)503 MacroAssembler::rotateRight64(Register count, Register64 src, Register64 dest, Register temp)
504 {
505 MOZ_ASSERT(src == dest, "defineReuseInput");
506 MOZ_ASSERT(count == ecx, "defineFixed(ecx)");
507
508 Label done;
509
510 movl(dest.high, temp);
511 shrdl_cl(dest.low, dest.high);
512 shrdl_cl(temp, dest.low);
513
514 testl(Imm32(0x20), count);
515 j(Condition::Equal, &done);
516 xchgl(dest.high, dest.low);
517
518 bind(&done);
519 }
520
521 void
rotateLeft64(Imm32 count,Register64 src,Register64 dest,Register temp)522 MacroAssembler::rotateLeft64(Imm32 count, Register64 src, Register64 dest, Register temp)
523 {
524 MOZ_ASSERT(src == dest, "defineReuseInput");
525
526 int32_t amount = count.value & 0x3f;
527 if ((amount & 0x1f) != 0) {
528 movl(dest.high, temp);
529 shldl(Imm32(amount & 0x1f), dest.low, dest.high);
530 shldl(Imm32(amount & 0x1f), temp, dest.low);
531 }
532
533 if (!!(amount & 0x20))
534 xchgl(dest.high, dest.low);
535 }
536
537 void
rotateRight64(Imm32 count,Register64 src,Register64 dest,Register temp)538 MacroAssembler::rotateRight64(Imm32 count, Register64 src, Register64 dest, Register temp)
539 {
540 MOZ_ASSERT(src == dest, "defineReuseInput");
541
542 int32_t amount = count.value & 0x3f;
543 if ((amount & 0x1f) != 0) {
544 movl(dest.high, temp);
545 shrdl(Imm32(amount & 0x1f), dest.low, dest.high);
546 shrdl(Imm32(amount & 0x1f), temp, dest.low);
547 }
548
549 if (!!(amount & 0x20))
550 xchgl(dest.high, dest.low);
551 }
552
553 // ===============================================================
554 // Bit counting functions
555
556 void
clz64(Register64 src,Register dest)557 MacroAssembler::clz64(Register64 src, Register dest)
558 {
559 Label nonzero, zero;
560
561 bsrl(src.high, dest);
562 j(Assembler::Zero, &zero);
563 orl(Imm32(32), dest);
564 jump(&nonzero);
565
566 bind(&zero);
567 bsrl(src.low, dest);
568 j(Assembler::NonZero, &nonzero);
569 movl(Imm32(0x7F), dest);
570
571 bind(&nonzero);
572 xorl(Imm32(0x3F), dest);
573 }
574
575 void
ctz64(Register64 src,Register dest)576 MacroAssembler::ctz64(Register64 src, Register dest)
577 {
578 Label done, nonzero;
579
580 bsfl(src.low, dest);
581 j(Assembler::NonZero, &done);
582 bsfl(src.high, dest);
583 j(Assembler::NonZero, &nonzero);
584 movl(Imm32(64), dest);
585 jump(&done);
586
587 bind(&nonzero);
588 orl(Imm32(32), dest);
589
590 bind(&done);
591 }
592
593 void
popcnt64(Register64 src,Register64 dest,Register tmp)594 MacroAssembler::popcnt64(Register64 src, Register64 dest, Register tmp)
595 {
596 // The tmp register is only needed if there is no native POPCNT.
597
598 MOZ_ASSERT(src.low != tmp && src.high != tmp);
599 MOZ_ASSERT(dest.low != tmp && dest.high != tmp);
600
601 if (dest.low != src.high) {
602 popcnt32(src.low, dest.low, tmp);
603 popcnt32(src.high, dest.high, tmp);
604 } else {
605 MOZ_ASSERT(dest.high != src.high);
606 popcnt32(src.low, dest.high, tmp);
607 popcnt32(src.high, dest.low, tmp);
608 }
609 addl(dest.high, dest.low);
610 xorl(dest.high, dest.high);
611 }
612
613 // ===============================================================
614 // Condition functions
615
616 template <typename T1, typename T2>
617 void
cmpPtrSet(Condition cond,T1 lhs,T2 rhs,Register dest)618 MacroAssembler::cmpPtrSet(Condition cond, T1 lhs, T2 rhs, Register dest)
619 {
620 cmpPtr(lhs, rhs);
621 emitSet(cond, dest);
622 }
623
624 // ===============================================================
625 // Branch functions
626
627 void
branch32(Condition cond,const AbsoluteAddress & lhs,Register rhs,Label * label)628 MacroAssembler::branch32(Condition cond, const AbsoluteAddress& lhs, Register rhs, Label* label)
629 {
630 cmp32(Operand(lhs), rhs);
631 j(cond, label);
632 }
633
634 void
branch32(Condition cond,const AbsoluteAddress & lhs,Imm32 rhs,Label * label)635 MacroAssembler::branch32(Condition cond, const AbsoluteAddress& lhs, Imm32 rhs, Label* label)
636 {
637 cmp32(Operand(lhs), rhs);
638 j(cond, label);
639 }
640
641 void
branch32(Condition cond,wasm::SymbolicAddress lhs,Imm32 rhs,Label * label)642 MacroAssembler::branch32(Condition cond, wasm::SymbolicAddress lhs, Imm32 rhs, Label* label)
643 {
644 cmpl(rhs, lhs);
645 j(cond, label);
646 }
647
648 void
branch64(Condition cond,Register64 lhs,Imm64 val,Label * success,Label * fail)649 MacroAssembler::branch64(Condition cond, Register64 lhs, Imm64 val, Label* success, Label* fail)
650 {
651 bool fallthrough = false;
652 Label fallthroughLabel;
653
654 if (!fail) {
655 fail = &fallthroughLabel;
656 fallthrough = true;
657 }
658
659 switch(cond) {
660 case Assembler::Equal:
661 branch32(Assembler::NotEqual, lhs.low, val.low(), fail);
662 branch32(Assembler::Equal, lhs.high, val.hi(), success);
663 if (!fallthrough)
664 jump(fail);
665 break;
666 case Assembler::NotEqual:
667 branch32(Assembler::NotEqual, lhs.low, val.low(), success);
668 branch32(Assembler::NotEqual, lhs.high, val.hi(), success);
669 if (!fallthrough)
670 jump(fail);
671 break;
672 case Assembler::LessThan:
673 case Assembler::LessThanOrEqual:
674 case Assembler::GreaterThan:
675 case Assembler::GreaterThanOrEqual:
676 case Assembler::Below:
677 case Assembler::BelowOrEqual:
678 case Assembler::Above:
679 case Assembler::AboveOrEqual: {
680 Assembler::Condition cond1 = Assembler::ConditionWithoutEqual(cond);
681 Assembler::Condition cond2 =
682 Assembler::ConditionWithoutEqual(Assembler::InvertCondition(cond));
683 Assembler::Condition cond3 = Assembler::UnsignedCondition(cond);
684
685 cmp32(lhs.high, val.hi());
686 j(cond1, success);
687 j(cond2, fail);
688 cmp32(lhs.low, val.low());
689 j(cond3, success);
690 if (!fallthrough)
691 jump(fail);
692 break;
693 }
694 default:
695 MOZ_CRASH("Condition code not supported");
696 break;
697 }
698
699 if (fallthrough)
700 bind(fail);
701 }
702
703 void
branch64(Condition cond,Register64 lhs,Register64 rhs,Label * success,Label * fail)704 MacroAssembler::branch64(Condition cond, Register64 lhs, Register64 rhs, Label* success, Label* fail)
705 {
706 bool fallthrough = false;
707 Label fallthroughLabel;
708
709 if (!fail) {
710 fail = &fallthroughLabel;
711 fallthrough = true;
712 }
713
714 switch(cond) {
715 case Assembler::Equal:
716 branch32(Assembler::NotEqual, lhs.low, rhs.low, fail);
717 branch32(Assembler::Equal, lhs.high, rhs.high, success);
718 if (!fallthrough)
719 jump(fail);
720 break;
721 case Assembler::NotEqual:
722 branch32(Assembler::NotEqual, lhs.low, rhs.low, success);
723 branch32(Assembler::NotEqual, lhs.high, rhs.high, success);
724 if (!fallthrough)
725 jump(fail);
726 break;
727 case Assembler::LessThan:
728 case Assembler::LessThanOrEqual:
729 case Assembler::GreaterThan:
730 case Assembler::GreaterThanOrEqual:
731 case Assembler::Below:
732 case Assembler::BelowOrEqual:
733 case Assembler::Above:
734 case Assembler::AboveOrEqual: {
735 Assembler::Condition cond1 = Assembler::ConditionWithoutEqual(cond);
736 Assembler::Condition cond2 =
737 Assembler::ConditionWithoutEqual(Assembler::InvertCondition(cond));
738 Assembler::Condition cond3 = Assembler::UnsignedCondition(cond);
739
740 cmp32(lhs.high, rhs.high);
741 j(cond1, success);
742 j(cond2, fail);
743 cmp32(lhs.low, rhs.low);
744 j(cond3, success);
745 if (!fallthrough)
746 jump(fail);
747 break;
748 }
749 default:
750 MOZ_CRASH("Condition code not supported");
751 break;
752 }
753
754 if (fallthrough)
755 bind(fail);
756 }
757
758 void
branch64(Condition cond,const Address & lhs,Imm64 val,Label * label)759 MacroAssembler::branch64(Condition cond, const Address& lhs, Imm64 val, Label* label)
760 {
761 MOZ_ASSERT(cond == Assembler::NotEqual || cond == Assembler::Equal,
762 "other condition codes not supported");
763
764 Label done;
765
766 if (cond == Assembler::Equal)
767 branch32(Assembler::NotEqual, lhs, val.firstHalf(), &done);
768 else
769 branch32(Assembler::NotEqual, lhs, val.firstHalf(), label);
770 branch32(cond, Address(lhs.base, lhs.offset + sizeof(uint32_t)), val.secondHalf(), label);
771
772 bind(&done);
773 }
774
775 void
branch64(Condition cond,const Address & lhs,const Address & rhs,Register scratch,Label * label)776 MacroAssembler::branch64(Condition cond, const Address& lhs, const Address& rhs, Register scratch,
777 Label* label)
778 {
779 MOZ_ASSERT(cond == Assembler::NotEqual || cond == Assembler::Equal,
780 "other condition codes not supported");
781 MOZ_ASSERT(lhs.base != scratch);
782 MOZ_ASSERT(rhs.base != scratch);
783
784 Label done;
785
786 load32(rhs, scratch);
787 if (cond == Assembler::Equal)
788 branch32(Assembler::NotEqual, lhs, scratch, &done);
789 else
790 branch32(Assembler::NotEqual, lhs, scratch, label);
791
792 load32(Address(rhs.base, rhs.offset + sizeof(uint32_t)), scratch);
793 branch32(cond, Address(lhs.base, lhs.offset + sizeof(uint32_t)), scratch, label);
794
795 bind(&done);
796 }
797
798 void
branchPtr(Condition cond,const AbsoluteAddress & lhs,Register rhs,Label * label)799 MacroAssembler::branchPtr(Condition cond, const AbsoluteAddress& lhs, Register rhs, Label* label)
800 {
801 branchPtrImpl(cond, lhs, rhs, label);
802 }
803
804 void
branchPtr(Condition cond,const AbsoluteAddress & lhs,ImmWord rhs,Label * label)805 MacroAssembler::branchPtr(Condition cond, const AbsoluteAddress& lhs, ImmWord rhs, Label* label)
806 {
807 branchPtrImpl(cond, lhs, rhs, label);
808 }
809
810 void
branchPtr(Condition cond,wasm::SymbolicAddress lhs,Register rhs,Label * label)811 MacroAssembler::branchPtr(Condition cond, wasm::SymbolicAddress lhs, Register rhs, Label* label)
812 {
813 cmpl(rhs, lhs);
814 j(cond, label);
815 }
816
817 void
branchPrivatePtr(Condition cond,const Address & lhs,Register rhs,Label * label)818 MacroAssembler::branchPrivatePtr(Condition cond, const Address& lhs, Register rhs, Label* label)
819 {
820 branchPtr(cond, lhs, rhs, label);
821 }
822
823 void
branchTruncateFloat32ToPtr(FloatRegister src,Register dest,Label * fail)824 MacroAssembler::branchTruncateFloat32ToPtr(FloatRegister src, Register dest, Label* fail)
825 {
826 branchTruncateFloat32ToInt32(src, dest, fail);
827 }
828
829 void
branchTruncateFloat32MaybeModUint32(FloatRegister src,Register dest,Label * fail)830 MacroAssembler::branchTruncateFloat32MaybeModUint32(FloatRegister src, Register dest, Label* fail)
831 {
832 branchTruncateFloat32ToInt32(src, dest, fail);
833 }
834
835 void
branchTruncateFloat32ToInt32(FloatRegister src,Register dest,Label * fail)836 MacroAssembler::branchTruncateFloat32ToInt32(FloatRegister src, Register dest, Label* fail)
837 {
838 vcvttss2si(src, dest);
839
840 // vcvttss2si returns 0x80000000 on failure. Test for it by
841 // subtracting 1 and testing overflow (this permits the use of a
842 // smaller immediate field).
843 cmp32(dest, Imm32(1));
844 j(Assembler::Overflow, fail);
845 }
846
847 void
branchTruncateDoubleToPtr(FloatRegister src,Register dest,Label * fail)848 MacroAssembler::branchTruncateDoubleToPtr(FloatRegister src, Register dest, Label* fail)
849 {
850 branchTruncateDoubleToInt32(src, dest, fail);
851 }
852
853 void
branchTruncateDoubleMaybeModUint32(FloatRegister src,Register dest,Label * fail)854 MacroAssembler::branchTruncateDoubleMaybeModUint32(FloatRegister src, Register dest, Label* fail)
855 {
856 // TODO: X64 supports supports integers up till 64bits. Here we only support 32bits,
857 // before failing. Implementing this for x86 might give a x86 kraken win.
858 branchTruncateDoubleToInt32(src, dest, fail);
859 }
860
861 void
branchTruncateDoubleToInt32(FloatRegister src,Register dest,Label * fail)862 MacroAssembler::branchTruncateDoubleToInt32(FloatRegister src, Register dest, Label* fail)
863 {
864 vcvttsd2si(src, dest);
865
866 // vcvttsd2si returns 0x80000000 on failure. Test for it by
867 // subtracting 1 and testing overflow (this permits the use of a
868 // smaller immediate field).
869 cmp32(dest, Imm32(1));
870 j(Assembler::Overflow, fail);
871 }
872
873 void
branchTest32(Condition cond,const AbsoluteAddress & lhs,Imm32 rhs,Label * label)874 MacroAssembler::branchTest32(Condition cond, const AbsoluteAddress& lhs, Imm32 rhs, Label* label)
875 {
876 test32(Operand(lhs), rhs);
877 j(cond, label);
878 }
879
880 template <class L>
881 void
branchTest64(Condition cond,Register64 lhs,Register64 rhs,Register temp,L label)882 MacroAssembler::branchTest64(Condition cond, Register64 lhs, Register64 rhs, Register temp,
883 L label)
884 {
885 if (cond == Assembler::Zero) {
886 MOZ_ASSERT(lhs.low == rhs.low);
887 MOZ_ASSERT(lhs.high == rhs.high);
888 movl(lhs.low, temp);
889 orl(lhs.high, temp);
890 branchTestPtr(cond, temp, temp, label);
891 } else {
892 MOZ_CRASH("Unsupported condition");
893 }
894 }
895
896 void
branchTestBooleanTruthy(bool truthy,const ValueOperand & value,Label * label)897 MacroAssembler::branchTestBooleanTruthy(bool truthy, const ValueOperand& value, Label* label)
898 {
899 test32(value.payloadReg(), value.payloadReg());
900 j(truthy ? NonZero : Zero, label);
901 }
902
903 void
branchTestMagic(Condition cond,const Address & valaddr,JSWhyMagic why,Label * label)904 MacroAssembler::branchTestMagic(Condition cond, const Address& valaddr, JSWhyMagic why, Label* label)
905 {
906 branchTestMagic(cond, valaddr, label);
907 branch32(cond, ToPayload(valaddr), Imm32(why), label);
908 }
909
910 // ========================================================================
911 // Truncate floating point.
912
913 void
truncateFloat32ToUInt64(Address src,Address dest,Register temp,FloatRegister floatTemp)914 MacroAssembler::truncateFloat32ToUInt64(Address src, Address dest, Register temp,
915 FloatRegister floatTemp)
916 {
917 Label done;
918
919 loadFloat32(src, floatTemp);
920
921 truncateFloat32ToInt64(src, dest, temp);
922
923 // For unsigned conversion the case of [INT64, UINT64] needs to get handle seperately.
924 load32(Address(dest.base, dest.offset + INT64HIGH_OFFSET), temp);
925 branch32(Assembler::Condition::NotSigned, temp, Imm32(0), &done);
926
927 // Move the value inside INT64 range.
928 storeFloat32(floatTemp, dest);
929 loadConstantFloat32(double(int64_t(0x8000000000000000)), floatTemp);
930 vaddss(Operand(dest), floatTemp, floatTemp);
931 storeFloat32(floatTemp, dest);
932 truncateFloat32ToInt64(dest, dest, temp);
933
934 load32(Address(dest.base, dest.offset + INT64HIGH_OFFSET), temp);
935 orl(Imm32(0x80000000), temp);
936 store32(temp, Address(dest.base, dest.offset + INT64HIGH_OFFSET));
937
938 bind(&done);
939 }
940
941 void
truncateDoubleToUInt64(Address src,Address dest,Register temp,FloatRegister floatTemp)942 MacroAssembler::truncateDoubleToUInt64(Address src, Address dest, Register temp,
943 FloatRegister floatTemp)
944 {
945 Label done;
946
947 loadDouble(src, floatTemp);
948
949 truncateDoubleToInt64(src, dest, temp);
950
951 // For unsigned conversion the case of [INT64, UINT64] needs to get handle seperately.
952 load32(Address(dest.base, dest.offset + INT64HIGH_OFFSET), temp);
953 branch32(Assembler::Condition::NotSigned, temp, Imm32(0), &done);
954
955 // Move the value inside INT64 range.
956 storeDouble(floatTemp, dest);
957 loadConstantDouble(double(int64_t(0x8000000000000000)), floatTemp);
958 vaddsd(Operand(dest), floatTemp, floatTemp);
959 storeDouble(floatTemp, dest);
960 truncateDoubleToInt64(dest, dest, temp);
961
962 load32(Address(dest.base, dest.offset + INT64HIGH_OFFSET), temp);
963 orl(Imm32(0x80000000), temp);
964 store32(temp, Address(dest.base, dest.offset + INT64HIGH_OFFSET));
965
966 bind(&done);
967 }
968
969 // ========================================================================
970 // wasm support
971
972 template <class L>
973 void
wasmBoundsCheck(Condition cond,Register index,L label)974 MacroAssembler::wasmBoundsCheck(Condition cond, Register index, L label)
975 {
976 CodeOffset off = cmp32WithPatch(index, Imm32(0));
977 append(wasm::BoundsCheck(off.offset()));
978
979 j(cond, label);
980 }
981
982 void
wasmPatchBoundsCheck(uint8_t * patchAt,uint32_t limit)983 MacroAssembler::wasmPatchBoundsCheck(uint8_t* patchAt, uint32_t limit)
984 {
985 reinterpret_cast<uint32_t*>(patchAt)[-1] = limit;
986 }
987
988 //}}} check_macroassembler_style
989 // ===============================================================
990
991 // Note: this function clobbers the source register.
992 void
convertUInt32ToDouble(Register src,FloatRegister dest)993 MacroAssemblerX86::convertUInt32ToDouble(Register src, FloatRegister dest)
994 {
995 // src is [0, 2^32-1]
996 subl(Imm32(0x80000000), src);
997
998 // Now src is [-2^31, 2^31-1] - int range, but not the same value.
999 convertInt32ToDouble(src, dest);
1000
1001 // dest is now a double with the int range.
1002 // correct the double value by adding 0x80000000.
1003 asMasm().addConstantDouble(2147483648.0, dest);
1004 }
1005
1006 // Note: this function clobbers the source register.
1007 void
convertUInt32ToFloat32(Register src,FloatRegister dest)1008 MacroAssemblerX86::convertUInt32ToFloat32(Register src, FloatRegister dest)
1009 {
1010 convertUInt32ToDouble(src, dest);
1011 convertDoubleToFloat32(dest, dest);
1012 }
1013
1014 void
unboxValue(const ValueOperand & src,AnyRegister dest)1015 MacroAssemblerX86::unboxValue(const ValueOperand& src, AnyRegister dest)
1016 {
1017 if (dest.isFloat()) {
1018 Label notInt32, end;
1019 asMasm().branchTestInt32(Assembler::NotEqual, src, ¬Int32);
1020 convertInt32ToDouble(src.payloadReg(), dest.fpu());
1021 jump(&end);
1022 bind(¬Int32);
1023 unboxDouble(src, dest.fpu());
1024 bind(&end);
1025 } else {
1026 if (src.payloadReg() != dest.gpr())
1027 movl(src.payloadReg(), dest.gpr());
1028 }
1029 }
1030
1031 template <typename T>
1032 void
loadInt32OrDouble(const T & src,FloatRegister dest)1033 MacroAssemblerX86::loadInt32OrDouble(const T& src, FloatRegister dest)
1034 {
1035 Label notInt32, end;
1036 asMasm().branchTestInt32(Assembler::NotEqual, src, ¬Int32);
1037 convertInt32ToDouble(ToPayload(src), dest);
1038 jump(&end);
1039 bind(¬Int32);
1040 loadDouble(src, dest);
1041 bind(&end);
1042 }
1043
1044 template <typename T>
1045 void
loadUnboxedValue(const T & src,MIRType type,AnyRegister dest)1046 MacroAssemblerX86::loadUnboxedValue(const T& src, MIRType type, AnyRegister dest)
1047 {
1048 if (dest.isFloat())
1049 loadInt32OrDouble(src, dest.fpu());
1050 else
1051 movl(Operand(src), dest.gpr());
1052 }
1053
1054 // If source is a double, load it into dest. If source is int32,
1055 // convert it to double. Else, branch to failure.
1056 void
ensureDouble(const ValueOperand & source,FloatRegister dest,Label * failure)1057 MacroAssemblerX86::ensureDouble(const ValueOperand& source, FloatRegister dest, Label* failure)
1058 {
1059 Label isDouble, done;
1060 asMasm().branchTestDouble(Assembler::Equal, source.typeReg(), &isDouble);
1061 asMasm().branchTestInt32(Assembler::NotEqual, source.typeReg(), failure);
1062
1063 convertInt32ToDouble(source.payloadReg(), dest);
1064 jump(&done);
1065
1066 bind(&isDouble);
1067 unboxDouble(source, dest);
1068
1069 bind(&done);
1070 }
1071
1072 } // namespace jit
1073 } // namespace js
1074
1075 #endif /* jit_x86_MacroAssembler_x86_inl_h */
1076