Line data Source code
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_x64_MacroAssembler_x64_inl_h
8 : #define jit_x64_MacroAssembler_x64_inl_h
9 :
10 : #include "jit/x64/MacroAssembler-x64.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 :
20 : void
21 0 : MacroAssembler::move64(Imm64 imm, Register64 dest)
22 : {
23 0 : movq(ImmWord(imm.value), dest.reg);
24 0 : }
25 :
26 : void
27 0 : MacroAssembler::move64(Register64 src, Register64 dest)
28 : {
29 0 : movq(src.reg, dest.reg);
30 0 : }
31 :
32 : void
33 0 : MacroAssembler::andPtr(Register src, Register dest)
34 : {
35 0 : andq(src, dest);
36 0 : }
37 :
38 : void
39 1334 : MacroAssembler::andPtr(Imm32 imm, Register dest)
40 : {
41 1334 : andq(imm, dest);
42 1334 : }
43 :
44 : void
45 0 : MacroAssembler::and64(Imm64 imm, Register64 dest)
46 : {
47 0 : if (INT32_MIN <= int64_t(imm.value) && int64_t(imm.value) <= INT32_MAX) {
48 0 : andq(Imm32(imm.value), dest.reg);
49 : } else {
50 0 : ScratchRegisterScope scratch(*this);
51 0 : movq(ImmWord(uintptr_t(imm.value)), scratch);
52 0 : andq(scratch, dest.reg);
53 : }
54 0 : }
55 :
56 : void
57 0 : MacroAssembler::or64(Imm64 imm, Register64 dest)
58 : {
59 0 : if (INT32_MIN <= int64_t(imm.value) && int64_t(imm.value) <= INT32_MAX) {
60 0 : orq(Imm32(imm.value), dest.reg);
61 : } else {
62 0 : ScratchRegisterScope scratch(*this);
63 0 : movq(ImmWord(uintptr_t(imm.value)), scratch);
64 0 : orq(scratch, dest.reg);
65 : }
66 0 : }
67 :
68 : void
69 0 : MacroAssembler::xor64(Imm64 imm, Register64 dest)
70 : {
71 0 : if (INT32_MIN <= int64_t(imm.value) && int64_t(imm.value) <= INT32_MAX) {
72 0 : xorq(Imm32(imm.value), dest.reg);
73 : } else {
74 0 : ScratchRegisterScope scratch(*this);
75 0 : movq(ImmWord(uintptr_t(imm.value)), scratch);
76 0 : xorq(scratch, dest.reg);
77 : }
78 0 : }
79 :
80 : void
81 6 : MacroAssembler::orPtr(Register src, Register dest)
82 : {
83 6 : orq(src, dest);
84 6 : }
85 :
86 : void
87 2084 : MacroAssembler::orPtr(Imm32 imm, Register dest)
88 : {
89 2084 : orq(imm, dest);
90 2084 : }
91 :
92 : void
93 0 : MacroAssembler::and64(Register64 src, Register64 dest)
94 : {
95 0 : andq(src.reg, dest.reg);
96 0 : }
97 :
98 : void
99 0 : MacroAssembler::or64(Register64 src, Register64 dest)
100 : {
101 0 : orq(src.reg, dest.reg);
102 0 : }
103 :
104 : void
105 0 : MacroAssembler::xor64(Register64 src, Register64 dest)
106 : {
107 0 : xorq(src.reg, dest.reg);
108 0 : }
109 :
110 : void
111 0 : MacroAssembler::xorPtr(Register src, Register dest)
112 : {
113 0 : xorq(src, dest);
114 0 : }
115 :
116 : void
117 : MacroAssembler::xorPtr(Imm32 imm, Register dest)
118 : {
119 : xorq(imm, dest);
120 : }
121 :
122 : void
123 0 : MacroAssembler::and64(const Operand& src, Register64 dest)
124 : {
125 0 : andq(src, dest.reg);
126 0 : }
127 :
128 : void
129 0 : MacroAssembler::or64(const Operand& src, Register64 dest)
130 : {
131 0 : orq(src, dest.reg);
132 0 : }
133 :
134 : void
135 0 : MacroAssembler::xor64(const Operand& src, Register64 dest)
136 : {
137 0 : xorq(src, dest.reg);
138 0 : }
139 :
140 : // ===============================================================
141 : // Arithmetic functions
142 :
143 : void
144 186 : MacroAssembler::addPtr(Register src, Register dest)
145 : {
146 186 : addq(src, dest);
147 186 : }
148 :
149 : void
150 33970 : MacroAssembler::addPtr(Imm32 imm, Register dest)
151 : {
152 33970 : addq(imm, dest);
153 33969 : }
154 :
155 : void
156 1 : MacroAssembler::addPtr(ImmWord imm, Register dest)
157 : {
158 2 : ScratchRegisterScope scratch(*this);
159 1 : MOZ_ASSERT(dest != scratch);
160 1 : if ((intptr_t)imm.value <= INT32_MAX && (intptr_t)imm.value >= INT32_MIN) {
161 1 : addq(Imm32((int32_t)imm.value), dest);
162 : } else {
163 0 : mov(imm, scratch);
164 0 : addq(scratch, dest);
165 : }
166 1 : }
167 :
168 : void
169 7508 : MacroAssembler::addPtr(Imm32 imm, const Address& dest)
170 : {
171 7508 : addq(imm, Operand(dest));
172 7508 : }
173 :
174 : void
175 0 : MacroAssembler::addPtr(Imm32 imm, const AbsoluteAddress& dest)
176 : {
177 0 : addq(imm, Operand(dest));
178 0 : }
179 :
180 : void
181 22 : MacroAssembler::addPtr(const Address& src, Register dest)
182 : {
183 22 : addq(Operand(src), dest);
184 22 : }
185 :
186 : void
187 0 : MacroAssembler::add64(const Operand& src, Register64 dest)
188 : {
189 0 : addq(src, dest.reg);
190 0 : }
191 :
192 : void
193 0 : MacroAssembler::add64(Register64 src, Register64 dest)
194 : {
195 0 : addq(src.reg, dest.reg);
196 0 : }
197 :
198 : void
199 0 : MacroAssembler::add64(Imm32 imm, Register64 dest)
200 : {
201 0 : addq(imm, dest.reg);
202 0 : }
203 :
204 : void
205 0 : MacroAssembler::add64(Imm64 imm, Register64 dest)
206 : {
207 0 : addPtr(ImmWord(imm.value), dest.reg);
208 0 : }
209 :
210 : CodeOffset
211 0 : MacroAssembler::add32ToPtrWithPatch(Register src, Register dest)
212 : {
213 0 : if (src != dest)
214 0 : movePtr(src, dest);
215 0 : addqWithPatch(Imm32(0), dest);
216 0 : return CodeOffset(currentOffset());
217 : }
218 :
219 : void
220 0 : MacroAssembler::patchAdd32ToPtr(CodeOffset offset, Imm32 imm)
221 : {
222 0 : patchAddq(offset, imm.value);
223 0 : }
224 :
225 : void
226 48 : MacroAssembler::subPtr(Register src, Register dest)
227 : {
228 48 : subq(src, dest);
229 48 : }
230 :
231 : void
232 : MacroAssembler::subPtr(Register src, const Address& dest)
233 : {
234 : subq(src, Operand(dest));
235 : }
236 :
237 : void
238 2907 : MacroAssembler::subPtr(Imm32 imm, Register dest)
239 : {
240 2907 : subq(imm, dest);
241 2907 : }
242 :
243 : void
244 0 : MacroAssembler::subPtr(ImmWord imm, Register dest)
245 : {
246 0 : ScratchRegisterScope scratch(*this);
247 0 : MOZ_ASSERT(dest != scratch);
248 0 : if ((intptr_t)imm.value <= INT32_MAX && (intptr_t)imm.value >= INT32_MIN) {
249 0 : subq(Imm32((int32_t)imm.value), dest);
250 : } else {
251 0 : mov(imm, scratch);
252 0 : subq(scratch, dest);
253 : }
254 0 : }
255 :
256 : void
257 91 : MacroAssembler::subPtr(const Address& addr, Register dest)
258 : {
259 91 : subq(Operand(addr), dest);
260 91 : }
261 :
262 : void
263 0 : MacroAssembler::sub64(const Operand& src, Register64 dest)
264 : {
265 0 : subq(src, dest.reg);
266 0 : }
267 :
268 : void
269 0 : MacroAssembler::sub64(Register64 src, Register64 dest)
270 : {
271 0 : subq(src.reg, dest.reg);
272 0 : }
273 :
274 : void
275 0 : MacroAssembler::sub64(Imm64 imm, Register64 dest)
276 : {
277 0 : subPtr(ImmWord(imm.value), dest.reg);
278 0 : }
279 :
280 : void
281 0 : MacroAssembler::mul64(Imm64 imm, const Register64& dest, const Register temp)
282 : {
283 0 : MOZ_ASSERT(temp == InvalidReg);
284 0 : mul64(imm, dest);
285 0 : }
286 :
287 : void
288 0 : MacroAssembler::mul64(Imm64 imm, const Register64& dest)
289 : {
290 0 : movq(ImmWord(uintptr_t(imm.value)), ScratchReg);
291 0 : imulq(ScratchReg, dest.reg);
292 0 : }
293 :
294 : void
295 0 : MacroAssembler::mul64(const Register64& src, const Register64& dest, const Register temp)
296 : {
297 0 : MOZ_ASSERT(temp == InvalidReg);
298 0 : mul64(Operand(src.reg), dest);
299 0 : }
300 :
301 : void
302 0 : MacroAssembler::mul64(const Operand& src, const Register64& dest)
303 : {
304 0 : imulq(src, dest.reg);
305 0 : }
306 :
307 : void
308 0 : MacroAssembler::mul64(const Operand& src, const Register64& dest, const Register temp)
309 : {
310 0 : MOZ_ASSERT(temp == InvalidReg);
311 0 : mul64(src, dest);
312 0 : }
313 :
314 : void
315 0 : MacroAssembler::mulBy3(Register src, Register dest)
316 : {
317 0 : lea(Operand(src, src, TimesTwo), dest);
318 0 : }
319 :
320 : void
321 0 : MacroAssembler::mulDoublePtr(ImmPtr imm, Register temp, FloatRegister dest)
322 : {
323 0 : movq(imm, ScratchReg);
324 0 : vmulsd(Operand(ScratchReg, 0), dest, dest);
325 0 : }
326 :
327 : void
328 7452 : MacroAssembler::inc64(AbsoluteAddress dest)
329 : {
330 7452 : if (X86Encoding::IsAddressImmediate(dest.addr)) {
331 0 : addPtr(Imm32(1), dest);
332 : } else {
333 14904 : ScratchRegisterScope scratch(*this);
334 7452 : mov(ImmPtr(dest.addr), scratch);
335 7452 : addPtr(Imm32(1), Address(scratch, 0));
336 : }
337 7452 : }
338 :
339 : void
340 0 : MacroAssembler::neg64(Register64 reg)
341 : {
342 0 : negq(reg.reg);
343 0 : }
344 :
345 : // ===============================================================
346 : // Shift functions
347 :
348 : void
349 1668 : MacroAssembler::lshiftPtr(Imm32 imm, Register dest)
350 : {
351 1668 : MOZ_ASSERT(0 <= imm.value && imm.value < 64);
352 1668 : shlq(imm, dest);
353 1668 : }
354 :
355 : void
356 0 : MacroAssembler::lshift64(Imm32 imm, Register64 dest)
357 : {
358 0 : MOZ_ASSERT(0 <= imm.value && imm.value < 64);
359 0 : lshiftPtr(imm, dest.reg);
360 0 : }
361 :
362 : void
363 0 : MacroAssembler::lshift64(Register shift, Register64 srcDest)
364 : {
365 0 : MOZ_ASSERT(shift == rcx);
366 0 : shlq_cl(srcDest.reg);
367 0 : }
368 :
369 : void
370 15 : MacroAssembler::rshiftPtr(Imm32 imm, Register dest)
371 : {
372 15 : MOZ_ASSERT(0 <= imm.value && imm.value < 64);
373 15 : shrq(imm, dest);
374 15 : }
375 :
376 : void
377 0 : MacroAssembler::rshift64(Imm32 imm, Register64 dest)
378 : {
379 0 : rshiftPtr(imm, dest.reg);
380 0 : }
381 :
382 : void
383 0 : MacroAssembler::rshift64(Register shift, Register64 srcDest)
384 : {
385 0 : MOZ_ASSERT(shift == rcx);
386 0 : shrq_cl(srcDest.reg);
387 0 : }
388 :
389 : void
390 17 : MacroAssembler::rshiftPtrArithmetic(Imm32 imm, Register dest)
391 : {
392 17 : MOZ_ASSERT(0 <= imm.value && imm.value < 64);
393 17 : sarq(imm, dest);
394 17 : }
395 :
396 : void
397 0 : MacroAssembler::rshift64Arithmetic(Imm32 imm, Register64 dest)
398 : {
399 0 : MOZ_ASSERT(0 <= imm.value && imm.value < 64);
400 0 : rshiftPtrArithmetic(imm, dest.reg);
401 0 : }
402 :
403 : void
404 0 : MacroAssembler::rshift64Arithmetic(Register shift, Register64 srcDest)
405 : {
406 0 : MOZ_ASSERT(shift == rcx);
407 0 : sarq_cl(srcDest.reg);
408 0 : }
409 :
410 : // ===============================================================
411 : // Rotation functions
412 :
413 : void
414 0 : MacroAssembler::rotateLeft64(Register count, Register64 src, Register64 dest)
415 : {
416 0 : MOZ_ASSERT(src == dest, "defineReuseInput");
417 0 : MOZ_ASSERT(count == ecx, "defineFixed(ecx)");
418 :
419 0 : rolq_cl(dest.reg);
420 0 : }
421 :
422 : void
423 0 : MacroAssembler::rotateLeft64(Register count, Register64 src, Register64 dest, Register temp)
424 : {
425 0 : MOZ_ASSERT(temp == InvalidReg);
426 0 : rotateLeft64(count, src, dest);
427 0 : }
428 :
429 : void
430 0 : MacroAssembler::rotateRight64(Register count, Register64 src, Register64 dest)
431 : {
432 0 : MOZ_ASSERT(src == dest, "defineReuseInput");
433 0 : MOZ_ASSERT(count == ecx, "defineFixed(ecx)");
434 :
435 0 : rorq_cl(dest.reg);
436 0 : }
437 :
438 : void
439 0 : MacroAssembler::rotateRight64(Register count, Register64 src, Register64 dest, Register temp)
440 : {
441 0 : MOZ_ASSERT(temp == InvalidReg);
442 0 : rotateRight64(count, src, dest);
443 0 : }
444 :
445 : void
446 0 : MacroAssembler::rotateLeft64(Imm32 count, Register64 src, Register64 dest)
447 : {
448 0 : MOZ_ASSERT(src == dest, "defineReuseInput");
449 0 : rolq(count, dest.reg);
450 0 : }
451 :
452 : void
453 0 : MacroAssembler::rotateLeft64(Imm32 count, Register64 src, Register64 dest, Register temp)
454 : {
455 0 : MOZ_ASSERT(temp == InvalidReg);
456 0 : rotateLeft64(count, src, dest);
457 0 : }
458 :
459 : void
460 0 : MacroAssembler::rotateRight64(Imm32 count, Register64 src, Register64 dest)
461 : {
462 0 : MOZ_ASSERT(src == dest, "defineReuseInput");
463 0 : rorq(count, dest.reg);
464 0 : }
465 :
466 : void
467 0 : MacroAssembler::rotateRight64(Imm32 count, Register64 src, Register64 dest, Register temp)
468 : {
469 0 : MOZ_ASSERT(temp == InvalidReg);
470 0 : rotateRight64(count, src, dest);
471 0 : }
472 :
473 : // ===============================================================
474 : // Condition functions
475 :
476 : template <typename T1, typename T2>
477 : void
478 11 : MacroAssembler::cmpPtrSet(Condition cond, T1 lhs, T2 rhs, Register dest)
479 : {
480 11 : cmpPtr(lhs, rhs);
481 11 : emitSet(cond, dest);
482 11 : }
483 :
484 : // ===============================================================
485 : // Bit counting functions
486 :
487 : void
488 0 : MacroAssembler::clz64(Register64 src, Register dest)
489 : {
490 : // On very recent chips (Haswell and newer) there is actually an
491 : // LZCNT instruction that does all of this.
492 :
493 0 : Label nonzero;
494 0 : bsrq(src.reg, dest);
495 0 : j(Assembler::NonZero, &nonzero);
496 0 : movq(ImmWord(0x7F), dest);
497 0 : bind(&nonzero);
498 0 : xorq(Imm32(0x3F), dest);
499 0 : }
500 :
501 : void
502 0 : MacroAssembler::ctz64(Register64 src, Register dest)
503 : {
504 0 : Label nonzero;
505 0 : bsfq(src.reg, dest);
506 0 : j(Assembler::NonZero, &nonzero);
507 0 : movq(ImmWord(64), dest);
508 0 : bind(&nonzero);
509 0 : }
510 :
511 : void
512 0 : MacroAssembler::popcnt64(Register64 src64, Register64 dest64, Register tmp)
513 : {
514 0 : Register src = src64.reg;
515 0 : Register dest = dest64.reg;
516 :
517 0 : if (AssemblerX86Shared::HasPOPCNT()) {
518 0 : MOZ_ASSERT(tmp == InvalidReg);
519 0 : popcntq(src, dest);
520 0 : return;
521 : }
522 :
523 0 : if (src != dest)
524 0 : movq(src, dest);
525 :
526 0 : MOZ_ASSERT(tmp != dest);
527 :
528 0 : ScratchRegisterScope scratch(*this);
529 :
530 : // Equivalent to mozilla::CountPopulation32, adapted for 64 bits.
531 : // x -= (x >> 1) & m1;
532 0 : movq(src, tmp);
533 0 : movq(ImmWord(0x5555555555555555), scratch);
534 0 : shrq(Imm32(1), tmp);
535 0 : andq(scratch, tmp);
536 0 : subq(tmp, dest);
537 :
538 : // x = (x & m2) + ((x >> 2) & m2);
539 0 : movq(dest, tmp);
540 0 : movq(ImmWord(0x3333333333333333), scratch);
541 0 : andq(scratch, dest);
542 0 : shrq(Imm32(2), tmp);
543 0 : andq(scratch, tmp);
544 0 : addq(tmp, dest);
545 :
546 : // x = (x + (x >> 4)) & m4;
547 0 : movq(dest, tmp);
548 0 : movq(ImmWord(0x0f0f0f0f0f0f0f0f), scratch);
549 0 : shrq(Imm32(4), tmp);
550 0 : addq(tmp, dest);
551 0 : andq(scratch, dest);
552 :
553 : // (x * h01) >> 56
554 0 : movq(ImmWord(0x0101010101010101), scratch);
555 0 : imulq(scratch, dest);
556 0 : shrq(Imm32(56), dest);
557 : }
558 :
559 : // ===============================================================
560 : // Branch functions
561 :
562 : void
563 : MacroAssembler::branch32(Condition cond, const AbsoluteAddress& lhs, Register rhs, Label* label)
564 : {
565 : if (X86Encoding::IsAddressImmediate(lhs.addr)) {
566 : branch32(cond, Operand(lhs), rhs, label);
567 : } else {
568 : ScratchRegisterScope scratch(*this);
569 : mov(ImmPtr(lhs.addr), scratch);
570 : branch32(cond, Address(scratch, 0), rhs, label);
571 : }
572 : }
573 : void
574 364 : MacroAssembler::branch32(Condition cond, const AbsoluteAddress& lhs, Imm32 rhs, Label* label)
575 : {
576 364 : if (X86Encoding::IsAddressImmediate(lhs.addr)) {
577 0 : branch32(cond, Operand(lhs), rhs, label);
578 : } else {
579 728 : ScratchRegisterScope scratch(*this);
580 364 : mov(ImmPtr(lhs.addr), scratch);
581 364 : branch32(cond, Address(scratch, 0), rhs, label);
582 : }
583 364 : }
584 :
585 : void
586 : MacroAssembler::branch32(Condition cond, wasm::SymbolicAddress lhs, Imm32 rhs, Label* label)
587 : {
588 : ScratchRegisterScope scratch(*this);
589 : mov(lhs, scratch);
590 : branch32(cond, Address(scratch, 0), rhs, label);
591 : }
592 :
593 : void
594 0 : MacroAssembler::branch64(Condition cond, Register64 lhs, Imm64 val, Label* success, Label* fail)
595 : {
596 0 : MOZ_ASSERT(cond == Assembler::NotEqual || cond == Assembler::Equal ||
597 : cond == Assembler::LessThan || cond == Assembler::LessThanOrEqual ||
598 : cond == Assembler::GreaterThan || cond == Assembler::GreaterThanOrEqual ||
599 : cond == Assembler::Below || cond == Assembler::BelowOrEqual ||
600 : cond == Assembler::Above || cond == Assembler::AboveOrEqual,
601 : "other condition codes not supported");
602 :
603 0 : branchPtr(cond, lhs.reg, ImmWord(val.value), success);
604 0 : if (fail)
605 0 : jump(fail);
606 0 : }
607 :
608 : void
609 0 : MacroAssembler::branch64(Condition cond, Register64 lhs, Register64 rhs, Label* success, Label* fail)
610 : {
611 0 : MOZ_ASSERT(cond == Assembler::NotEqual || cond == Assembler::Equal ||
612 : cond == Assembler::LessThan || cond == Assembler::LessThanOrEqual ||
613 : cond == Assembler::GreaterThan || cond == Assembler::GreaterThanOrEqual ||
614 : cond == Assembler::Below || cond == Assembler::BelowOrEqual ||
615 : cond == Assembler::Above || cond == Assembler::AboveOrEqual,
616 : "other condition codes not supported");
617 :
618 0 : branchPtr(cond, lhs.reg, rhs.reg, success);
619 0 : if (fail)
620 0 : jump(fail);
621 0 : }
622 :
623 : void
624 : MacroAssembler::branch64(Condition cond, const Address& lhs, Imm64 val, Label* label)
625 : {
626 : MOZ_ASSERT(cond == Assembler::NotEqual || cond == Assembler::Equal,
627 : "other condition codes not supported");
628 :
629 : branchPtr(cond, lhs, ImmWord(val.value), label);
630 : }
631 :
632 : void
633 0 : MacroAssembler::branch64(Condition cond, const Address& lhs, const Address& rhs, Register scratch,
634 : Label* label)
635 : {
636 0 : MOZ_ASSERT(cond == Assembler::NotEqual || cond == Assembler::Equal,
637 : "other condition codes not supported");
638 0 : MOZ_ASSERT(lhs.base != scratch);
639 0 : MOZ_ASSERT(rhs.base != scratch);
640 :
641 0 : loadPtr(rhs, scratch);
642 0 : branchPtr(cond, lhs, scratch, label);
643 0 : }
644 :
645 : void
646 95 : MacroAssembler::branchPtr(Condition cond, const AbsoluteAddress& lhs, Register rhs, Label* label)
647 : {
648 190 : ScratchRegisterScope scratch(*this);
649 95 : MOZ_ASSERT(rhs != scratch);
650 95 : if (X86Encoding::IsAddressImmediate(lhs.addr)) {
651 0 : branchPtrImpl(cond, Operand(lhs), rhs, label);
652 : } else {
653 95 : mov(ImmPtr(lhs.addr), scratch);
654 95 : branchPtrImpl(cond, Operand(scratch, 0x0), rhs, label);
655 : }
656 95 : }
657 :
658 : void
659 78 : MacroAssembler::branchPtr(Condition cond, const AbsoluteAddress& lhs, ImmWord rhs, Label* label)
660 : {
661 78 : if (X86Encoding::IsAddressImmediate(lhs.addr)) {
662 0 : branchPtrImpl(cond, Operand(lhs), rhs, label);
663 : } else {
664 156 : ScratchRegisterScope scratch(*this);
665 78 : mov(ImmPtr(lhs.addr), scratch);
666 78 : branchPtrImpl(cond, Operand(scratch, 0x0), rhs, label);
667 : }
668 78 : }
669 :
670 : void
671 : MacroAssembler::branchPtr(Condition cond, wasm::SymbolicAddress lhs, Register rhs, Label* label)
672 : {
673 : ScratchRegisterScope scratch(*this);
674 : MOZ_ASSERT(rhs != scratch);
675 : mov(lhs, scratch);
676 : branchPtrImpl(cond, Operand(scratch, 0x0), rhs, label);
677 : }
678 :
679 : void
680 0 : MacroAssembler::branchPrivatePtr(Condition cond, const Address& lhs, Register rhs, Label* label)
681 : {
682 0 : ScratchRegisterScope scratch(*this);
683 0 : if (rhs != scratch)
684 0 : movePtr(rhs, scratch);
685 : // Instead of unboxing lhs, box rhs and do direct comparison with lhs.
686 0 : rshiftPtr(Imm32(1), scratch);
687 0 : branchPtr(cond, lhs, scratch, label);
688 0 : }
689 :
690 : void
691 0 : MacroAssembler::branchTruncateFloat32ToPtr(FloatRegister src, Register dest, Label* fail)
692 : {
693 0 : vcvttss2sq(src, dest);
694 :
695 : // Same trick as for Doubles
696 0 : cmpPtr(dest, Imm32(1));
697 0 : j(Assembler::Overflow, fail);
698 0 : }
699 :
700 : void
701 0 : MacroAssembler::branchTruncateFloat32MaybeModUint32(FloatRegister src, Register dest, Label* fail)
702 : {
703 0 : branchTruncateFloat32ToPtr(src, dest, fail);
704 0 : movl(dest, dest); // Zero upper 32-bits.
705 0 : }
706 :
707 : void
708 : MacroAssembler::branchTruncateFloat32ToInt32(FloatRegister src, Register dest, Label* fail)
709 : {
710 : branchTruncateFloat32ToPtr(src, dest, fail);
711 : branch32(Assembler::Above, dest, Imm32(0xffffffff), fail);
712 : }
713 :
714 : void
715 0 : MacroAssembler::branchTruncateDoubleToPtr(FloatRegister src, Register dest, Label* fail)
716 : {
717 0 : vcvttsd2sq(src, dest);
718 :
719 : // vcvttsd2sq returns 0x8000000000000000 on failure. Test for it by
720 : // subtracting 1 and testing overflow (this avoids the need to
721 : // materialize that value in a register).
722 0 : cmpPtr(dest, Imm32(1));
723 0 : j(Assembler::Overflow, fail);
724 0 : }
725 :
726 : void
727 0 : MacroAssembler::branchTruncateDoubleMaybeModUint32(FloatRegister src, Register dest, Label* fail)
728 : {
729 0 : branchTruncateDoubleToPtr(src, dest, fail);
730 0 : movl(dest, dest); // Zero upper 32-bits.
731 0 : }
732 :
733 : void
734 : MacroAssembler::branchTruncateDoubleToInt32(FloatRegister src, Register dest, Label* fail)
735 : {
736 : branchTruncateDoubleToPtr(src, dest, fail);
737 : branch32(Assembler::Above, dest, Imm32(0xffffffff), fail);
738 : }
739 :
740 : void
741 247 : MacroAssembler::branchTest32(Condition cond, const AbsoluteAddress& lhs, Imm32 rhs, Label* label)
742 : {
743 247 : if (X86Encoding::IsAddressImmediate(lhs.addr)) {
744 0 : test32(Operand(lhs), rhs);
745 : } else {
746 494 : ScratchRegisterScope scratch(*this);
747 247 : mov(ImmPtr(lhs.addr), scratch);
748 247 : test32(Operand(scratch, 0), rhs);
749 : }
750 247 : j(cond, label);
751 247 : }
752 :
753 : template <class L>
754 : void
755 0 : MacroAssembler::branchTest64(Condition cond, Register64 lhs, Register64 rhs, Register temp,
756 : L label)
757 : {
758 0 : branchTestPtr(cond, lhs.reg, rhs.reg, label);
759 0 : }
760 :
761 : void
762 2631 : MacroAssembler::branchTestBooleanTruthy(bool truthy, const ValueOperand& value, Label* label)
763 : {
764 2631 : test32(value.valueReg(), value.valueReg());
765 2631 : j(truthy ? NonZero : Zero, label);
766 2631 : }
767 :
768 : void
769 0 : MacroAssembler::branchTestMagic(Condition cond, const Address& valaddr, JSWhyMagic why, Label* label)
770 : {
771 0 : uint64_t magic = MagicValue(why).asRawBits();
772 0 : cmpPtr(valaddr, ImmWord(magic));
773 0 : j(cond, label);
774 0 : }
775 : // ========================================================================
776 : // Truncate floating point.
777 :
778 : void
779 : MacroAssembler::truncateFloat32ToUInt64(Address src, Address dest, Register temp,
780 : FloatRegister floatTemp)
781 : {
782 : Label done;
783 :
784 : loadFloat32(src, floatTemp);
785 :
786 : truncateFloat32ToInt64(src, dest, temp);
787 :
788 : // For unsigned conversion the case of [INT64, UINT64] needs to get handle seperately.
789 : loadPtr(dest, temp);
790 : branchPtr(Assembler::Condition::NotSigned, temp, Imm32(0), &done);
791 :
792 : // Move the value inside INT64 range.
793 : storeFloat32(floatTemp, dest);
794 : loadConstantFloat32(double(int64_t(0x8000000000000000)), floatTemp);
795 : vaddss(Operand(dest), floatTemp, floatTemp);
796 : storeFloat32(floatTemp, dest);
797 : truncateFloat32ToInt64(dest, dest, temp);
798 :
799 : loadPtr(dest, temp);
800 : or64(Imm64(0x8000000000000000), Register64(temp));
801 : storePtr(temp, dest);
802 :
803 : bind(&done);
804 : }
805 :
806 : void
807 : MacroAssembler::truncateDoubleToUInt64(Address src, Address dest, Register temp,
808 : FloatRegister floatTemp)
809 : {
810 : Label done;
811 :
812 : loadDouble(src, floatTemp);
813 :
814 : truncateDoubleToInt64(src, dest, temp);
815 :
816 : // For unsigned conversion the case of [INT64, UINT64] needs to get handle seperately.
817 : loadPtr(dest, temp);
818 : branchPtr(Assembler::Condition::NotSigned, temp, Imm32(0), &done);
819 :
820 : // Move the value inside INT64 range.
821 : storeDouble(floatTemp, dest);
822 : loadConstantDouble(double(int64_t(0x8000000000000000)), floatTemp);
823 : vaddsd(Operand(dest), floatTemp, floatTemp);
824 : storeDouble(floatTemp, dest);
825 : truncateDoubleToInt64(dest, dest, temp);
826 :
827 : loadPtr(dest, temp);
828 : or64(Imm64(0x8000000000000000), Register64(temp));
829 : storePtr(temp, dest);
830 :
831 : bind(&done);
832 : }
833 :
834 : //}}} check_macroassembler_style
835 : // ===============================================================
836 :
837 : void
838 31 : MacroAssemblerX64::incrementInt32Value(const Address& addr)
839 : {
840 31 : asMasm().addPtr(Imm32(1), addr);
841 31 : }
842 :
843 : void
844 6 : MacroAssemblerX64::unboxValue(const ValueOperand& src, AnyRegister dest)
845 : {
846 6 : if (dest.isFloat()) {
847 2 : Label notInt32, end;
848 1 : asMasm().branchTestInt32(Assembler::NotEqual, src, ¬Int32);
849 1 : convertInt32ToDouble(src.valueReg(), dest.fpu());
850 1 : jump(&end);
851 1 : bind(¬Int32);
852 1 : unboxDouble(src, dest.fpu());
853 1 : bind(&end);
854 : } else {
855 5 : unboxNonDouble(src, dest.gpr());
856 : }
857 6 : }
858 :
859 : template <typename T>
860 : void
861 0 : MacroAssemblerX64::loadInt32OrDouble(const T& src, FloatRegister dest)
862 : {
863 0 : Label notInt32, end;
864 0 : asMasm().branchTestInt32(Assembler::NotEqual, src, ¬Int32);
865 0 : convertInt32ToDouble(src, dest);
866 0 : jump(&end);
867 0 : bind(¬Int32);
868 0 : loadDouble(src, dest);
869 0 : bind(&end);
870 0 : }
871 :
872 : // If source is a double, load it into dest. If source is int32,
873 : // convert it to double. Else, branch to failure.
874 : void
875 24 : MacroAssemblerX64::ensureDouble(const ValueOperand& source, FloatRegister dest, Label* failure)
876 : {
877 48 : Label isDouble, done;
878 24 : Register tag = splitTagForTest(source);
879 24 : asMasm().branchTestDouble(Assembler::Equal, tag, &isDouble);
880 24 : asMasm().branchTestInt32(Assembler::NotEqual, tag, failure);
881 :
882 48 : ScratchRegisterScope scratch(asMasm());
883 24 : unboxInt32(source, scratch);
884 24 : convertInt32ToDouble(scratch, dest);
885 24 : jump(&done);
886 :
887 24 : bind(&isDouble);
888 24 : unboxDouble(source, dest);
889 :
890 24 : bind(&done);
891 24 : }
892 :
893 : } // namespace jit
894 : } // namespace js
895 :
896 : #endif /* jit_x64_MacroAssembler_x64_inl_h */
|