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, &notInt32);
1020         convertInt32ToDouble(src.payloadReg(), dest.fpu());
1021         jump(&end);
1022         bind(&notInt32);
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, &notInt32);
1037     convertInt32ToDouble(ToPayload(src), dest);
1038     jump(&end);
1039     bind(&notInt32);
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