2 * Copyright (C) 2008, 2014-2016 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 #ifndef MacroAssemblerX86Common_h
27 #define MacroAssemblerX86Common_h
31 #include "X86Assembler.h"
32 #include "AbstractMacroAssembler.h"
33 #include <wtf/Optional.h>
37 class MacroAssemblerX86Common : public AbstractMacroAssembler<X86Assembler, MacroAssemblerX86Common> {
40 // Use this directly only if you're not generating code with it.
41 static const X86Registers::RegisterID s_scratchRegister = X86Registers::r11;
43 // Use this when generating code so that we get enforcement of the disallowing of scratch register
45 X86Registers::RegisterID scratchRegister()
47 RELEASE_ASSERT(m_allowScratchRegister);
48 return s_scratchRegister;
53 static const int DoubleConditionBitInvert = 0x10;
54 static const int DoubleConditionBitSpecial = 0x20;
55 static const int DoubleConditionBits = DoubleConditionBitInvert | DoubleConditionBitSpecial;
58 typedef X86Assembler::XMMRegisterID XMMRegisterID;
60 static bool isCompactPtrAlignedAddressOffset(ptrdiff_t value)
62 return value >= -128 && value <= 127;
65 enum RelationalCondition {
66 Equal = X86Assembler::ConditionE,
67 NotEqual = X86Assembler::ConditionNE,
68 Above = X86Assembler::ConditionA,
69 AboveOrEqual = X86Assembler::ConditionAE,
70 Below = X86Assembler::ConditionB,
71 BelowOrEqual = X86Assembler::ConditionBE,
72 GreaterThan = X86Assembler::ConditionG,
73 GreaterThanOrEqual = X86Assembler::ConditionGE,
74 LessThan = X86Assembler::ConditionL,
75 LessThanOrEqual = X86Assembler::ConditionLE
78 enum ResultCondition {
79 Overflow = X86Assembler::ConditionO,
80 Signed = X86Assembler::ConditionS,
81 PositiveOrZero = X86Assembler::ConditionNS,
82 Zero = X86Assembler::ConditionE,
83 NonZero = X86Assembler::ConditionNE
86 // FIXME: it would be neat to rename this to FloatingPointCondition in every assembler.
87 enum DoubleCondition {
88 // These conditions will only evaluate to true if the comparison is ordered - i.e. neither operand is NaN.
89 DoubleEqual = X86Assembler::ConditionE | DoubleConditionBitSpecial,
90 DoubleNotEqual = X86Assembler::ConditionNE,
91 DoubleGreaterThan = X86Assembler::ConditionA,
92 DoubleGreaterThanOrEqual = X86Assembler::ConditionAE,
93 DoubleLessThan = X86Assembler::ConditionA | DoubleConditionBitInvert,
94 DoubleLessThanOrEqual = X86Assembler::ConditionAE | DoubleConditionBitInvert,
95 // If either operand is NaN, these conditions always evaluate to true.
96 DoubleEqualOrUnordered = X86Assembler::ConditionE,
97 DoubleNotEqualOrUnordered = X86Assembler::ConditionNE | DoubleConditionBitSpecial,
98 DoubleGreaterThanOrUnordered = X86Assembler::ConditionB | DoubleConditionBitInvert,
99 DoubleGreaterThanOrEqualOrUnordered = X86Assembler::ConditionBE | DoubleConditionBitInvert,
100 DoubleLessThanOrUnordered = X86Assembler::ConditionB,
101 DoubleLessThanOrEqualOrUnordered = X86Assembler::ConditionBE,
104 !((X86Assembler::ConditionE | X86Assembler::ConditionNE | X86Assembler::ConditionA | X86Assembler::ConditionAE | X86Assembler::ConditionB | X86Assembler::ConditionBE) & DoubleConditionBits),
105 DoubleConditionBits_should_not_interfere_with_X86Assembler_Condition_codes);
107 static const RegisterID stackPointerRegister = X86Registers::esp;
108 static const RegisterID framePointerRegister = X86Registers::ebp;
110 static bool canBlind() { return true; }
111 static bool shouldBlindForSpecificArch(uint32_t value) { return value >= 0x00ffffff; }
112 static bool shouldBlindForSpecificArch(uint64_t value) { return value >= 0x00ffffff; }
114 // Integer arithmetic operations:
116 // Operations are typically two operand - operation(source, srcDst)
117 // For many operations the source may be an TrustedImm32, the srcDst operand
118 // may often be a memory location (explictly described using an Address
121 void add32(RegisterID src, RegisterID dest)
123 m_assembler.addl_rr(src, dest);
126 void add32(TrustedImm32 imm, Address address)
128 m_assembler.addl_im(imm.m_value, address.offset, address.base);
131 void add32(TrustedImm32 imm, BaseIndex address)
133 m_assembler.addl_im(imm.m_value, address.offset, address.base, address.index, address.scale);
136 void add8(TrustedImm32 imm, Address address)
138 TrustedImm32 imm8(static_cast<int8_t>(imm.m_value));
139 m_assembler.addb_im(imm8.m_value, address.offset, address.base);
142 void add8(TrustedImm32 imm, BaseIndex address)
144 TrustedImm32 imm8(static_cast<int8_t>(imm.m_value));
145 m_assembler.addb_im(imm8.m_value, address.offset, address.base, address.index, address.scale);
148 void add16(TrustedImm32 imm, Address address)
150 m_assembler.addw_im(imm.m_value, address.offset, address.base);
153 void add16(TrustedImm32 imm, BaseIndex address)
155 m_assembler.addw_im(imm.m_value, address.offset, address.base, address.index, address.scale);
158 void add32(TrustedImm32 imm, RegisterID dest)
160 if (imm.m_value == 1)
161 m_assembler.inc_r(dest);
163 m_assembler.addl_ir(imm.m_value, dest);
166 void add32(Address src, RegisterID dest)
168 m_assembler.addl_mr(src.offset, src.base, dest);
171 void add32(RegisterID src, Address dest)
173 m_assembler.addl_rm(src, dest.offset, dest.base);
176 void add32(RegisterID src, BaseIndex dest)
178 m_assembler.addl_rm(src, dest.offset, dest.base, dest.index, dest.scale);
181 void add8(RegisterID src, Address dest)
183 m_assembler.addb_rm(src, dest.offset, dest.base);
186 void add8(RegisterID src, BaseIndex dest)
188 m_assembler.addb_rm(src, dest.offset, dest.base, dest.index, dest.scale);
191 void add16(RegisterID src, Address dest)
193 m_assembler.addw_rm(src, dest.offset, dest.base);
196 void add16(RegisterID src, BaseIndex dest)
198 m_assembler.addw_rm(src, dest.offset, dest.base, dest.index, dest.scale);
201 void add32(TrustedImm32 imm, RegisterID src, RegisterID dest)
204 zeroExtend32ToPtr(src, dest);
213 m_assembler.leal_mr(imm.m_value, src, dest);
216 void add32(RegisterID a, RegisterID b, RegisterID dest)
218 x86Lea32(BaseIndex(a, b, TimesOne), dest);
221 void x86Lea32(BaseIndex index, RegisterID dest)
223 if (!index.scale && !index.offset) {
224 if (index.base == dest) {
225 add32(index.index, dest);
228 if (index.index == dest) {
229 add32(index.base, dest);
233 m_assembler.leal_mr(index.offset, index.base, index.index, index.scale, dest);
236 void and32(RegisterID src, RegisterID dest)
238 m_assembler.andl_rr(src, dest);
241 void and32(TrustedImm32 imm, RegisterID dest)
243 m_assembler.andl_ir(imm.m_value, dest);
246 void and32(RegisterID src, Address dest)
248 m_assembler.andl_rm(src, dest.offset, dest.base);
251 void and32(Address src, RegisterID dest)
253 m_assembler.andl_mr(src.offset, src.base, dest);
256 void and32(TrustedImm32 imm, Address address)
258 m_assembler.andl_im(imm.m_value, address.offset, address.base);
261 void and32(RegisterID op1, RegisterID op2, RegisterID dest)
264 zeroExtend32ToPtr(op1, dest);
265 else if (op1 == dest)
268 move32IfNeeded(op2, dest);
273 void and32(Address op1, RegisterID op2, RegisterID dest)
277 else if (op1.base == dest) {
281 zeroExtend32ToPtr(op2, dest);
286 void and32(RegisterID op1, Address op2, RegisterID dest)
288 and32(op2, op1, dest);
291 void and32(TrustedImm32 imm, RegisterID src, RegisterID dest)
293 move32IfNeeded(src, dest);
297 void countLeadingZeros32(RegisterID src, RegisterID dst)
299 if (supportsLZCNT()) {
300 m_assembler.lzcnt_rr(src, dst);
303 m_assembler.bsr_rr(src, dst);
307 void countLeadingZeros32(Address src, RegisterID dst)
309 if (supportsLZCNT()) {
310 m_assembler.lzcnt_mr(src.offset, src.base, dst);
313 m_assembler.bsr_mr(src.offset, src.base, dst);
317 void lshift32(RegisterID shift_amount, RegisterID dest)
319 if (shift_amount == X86Registers::ecx)
320 m_assembler.shll_CLr(dest);
322 ASSERT(shift_amount != dest);
323 // On x86 we can only shift by ecx; if asked to shift by another register we'll
324 // need rejig the shift amount into ecx first, and restore the registers afterwards.
325 // If we dest is ecx, then shift the swapped register!
326 swap(shift_amount, X86Registers::ecx);
327 m_assembler.shll_CLr(dest == X86Registers::ecx ? shift_amount : dest);
328 swap(shift_amount, X86Registers::ecx);
332 void lshift32(RegisterID src, RegisterID shift_amount, RegisterID dest)
334 ASSERT(shift_amount != dest);
336 move32IfNeeded(src, dest);
337 lshift32(shift_amount, dest);
340 void lshift32(TrustedImm32 imm, RegisterID dest)
342 m_assembler.shll_i8r(imm.m_value, dest);
345 void lshift32(RegisterID src, TrustedImm32 imm, RegisterID dest)
347 move32IfNeeded(src, dest);
351 void mul32(RegisterID src, RegisterID dest)
353 m_assembler.imull_rr(src, dest);
356 void mul32(RegisterID src1, RegisterID src2, RegisterID dest)
359 m_assembler.imull_rr(src1, dest);
362 move32IfNeeded(src1, dest);
363 m_assembler.imull_rr(src2, dest);
366 void mul32(Address src, RegisterID dest)
368 m_assembler.imull_mr(src.offset, src.base, dest);
371 void mul32(Address op1, RegisterID op2, RegisterID dest)
375 else if (op1.base == dest) {
379 zeroExtend32ToPtr(op2, dest);
384 void mul32(RegisterID src1, Address src2, RegisterID dest)
386 mul32(src2, src1, dest);
389 void mul32(TrustedImm32 imm, RegisterID src, RegisterID dest)
391 m_assembler.imull_i32r(src, imm.m_value, dest);
394 void x86ConvertToDoubleWord32()
399 void x86ConvertToDoubleWord32(RegisterID eax, RegisterID edx)
401 ASSERT_UNUSED(eax, eax == X86Registers::eax);
402 ASSERT_UNUSED(edx, edx == X86Registers::edx);
403 x86ConvertToDoubleWord32();
406 void x86Div32(RegisterID denominator)
408 m_assembler.idivl_r(denominator);
411 void x86Div32(RegisterID eax, RegisterID edx, RegisterID denominator)
413 ASSERT_UNUSED(eax, eax == X86Registers::eax);
414 ASSERT_UNUSED(edx, edx == X86Registers::edx);
415 x86Div32(denominator);
418 void neg32(RegisterID srcDest)
420 m_assembler.negl_r(srcDest);
423 void neg32(Address srcDest)
425 m_assembler.negl_m(srcDest.offset, srcDest.base);
428 void or32(RegisterID src, RegisterID dest)
430 m_assembler.orl_rr(src, dest);
433 void or32(TrustedImm32 imm, RegisterID dest)
435 m_assembler.orl_ir(imm.m_value, dest);
438 void or32(RegisterID src, Address dest)
440 m_assembler.orl_rm(src, dest.offset, dest.base);
443 void or32(Address src, RegisterID dest)
445 m_assembler.orl_mr(src.offset, src.base, dest);
448 void or32(TrustedImm32 imm, Address address)
450 m_assembler.orl_im(imm.m_value, address.offset, address.base);
453 void or32(RegisterID op1, RegisterID op2, RegisterID dest)
456 zeroExtend32ToPtr(op1, dest);
457 else if (op1 == dest)
460 move32IfNeeded(op2, dest);
465 void or32(Address op1, RegisterID op2, RegisterID dest)
469 else if (op1.base == dest) {
473 zeroExtend32ToPtr(op2, dest);
478 void or32(RegisterID op1, Address op2, RegisterID dest)
480 or32(op2, op1, dest);
483 void or32(TrustedImm32 imm, RegisterID src, RegisterID dest)
485 move32IfNeeded(src, dest);
489 void rshift32(RegisterID shift_amount, RegisterID dest)
491 if (shift_amount == X86Registers::ecx)
492 m_assembler.sarl_CLr(dest);
494 ASSERT(shift_amount != dest);
496 // On x86 we can only shift by ecx; if asked to shift by another register we'll
497 // need rejig the shift amount into ecx first, and restore the registers afterwards.
498 // If we dest is ecx, then shift the swapped register!
499 swap(shift_amount, X86Registers::ecx);
500 m_assembler.sarl_CLr(dest == X86Registers::ecx ? shift_amount : dest);
501 swap(shift_amount, X86Registers::ecx);
505 void rshift32(RegisterID src, RegisterID shift_amount, RegisterID dest)
507 ASSERT(shift_amount != dest);
509 move32IfNeeded(src, dest);
510 rshift32(shift_amount, dest);
513 void rshift32(TrustedImm32 imm, RegisterID dest)
515 m_assembler.sarl_i8r(imm.m_value, dest);
518 void rshift32(RegisterID src, TrustedImm32 imm, RegisterID dest)
520 move32IfNeeded(src, dest);
524 void urshift32(RegisterID shift_amount, RegisterID dest)
526 if (shift_amount == X86Registers::ecx)
527 m_assembler.shrl_CLr(dest);
529 ASSERT(shift_amount != dest);
531 // On x86 we can only shift by ecx; if asked to shift by another register we'll
532 // need rejig the shift amount into ecx first, and restore the registers afterwards.
533 // If we dest is ecx, then shift the swapped register!
534 swap(shift_amount, X86Registers::ecx);
535 m_assembler.shrl_CLr(dest == X86Registers::ecx ? shift_amount : dest);
536 swap(shift_amount, X86Registers::ecx);
540 void urshift32(RegisterID src, RegisterID shift_amount, RegisterID dest)
542 ASSERT(shift_amount != dest);
544 move32IfNeeded(src, dest);
545 urshift32(shift_amount, dest);
548 void urshift32(TrustedImm32 imm, RegisterID dest)
550 m_assembler.shrl_i8r(imm.m_value, dest);
553 void urshift32(RegisterID src, TrustedImm32 imm, RegisterID dest)
555 move32IfNeeded(src, dest);
556 urshift32(imm, dest);
559 void sub32(RegisterID src, RegisterID dest)
561 m_assembler.subl_rr(src, dest);
564 void sub32(TrustedImm32 imm, RegisterID dest)
566 if (imm.m_value == 1)
567 m_assembler.dec_r(dest);
569 m_assembler.subl_ir(imm.m_value, dest);
572 void sub32(TrustedImm32 imm, Address address)
574 m_assembler.subl_im(imm.m_value, address.offset, address.base);
577 void sub32(Address src, RegisterID dest)
579 m_assembler.subl_mr(src.offset, src.base, dest);
582 void sub32(RegisterID src, Address dest)
584 m_assembler.subl_rm(src, dest.offset, dest.base);
587 void xor32(RegisterID src, RegisterID dest)
589 m_assembler.xorl_rr(src, dest);
592 void xor32(TrustedImm32 imm, Address dest)
594 if (imm.m_value == -1)
595 m_assembler.notl_m(dest.offset, dest.base);
597 m_assembler.xorl_im(imm.m_value, dest.offset, dest.base);
600 void xor32(TrustedImm32 imm, RegisterID dest)
602 if (imm.m_value == -1)
603 m_assembler.notl_r(dest);
605 m_assembler.xorl_ir(imm.m_value, dest);
608 void xor32(RegisterID src, Address dest)
610 m_assembler.xorl_rm(src, dest.offset, dest.base);
613 void xor32(Address src, RegisterID dest)
615 m_assembler.xorl_mr(src.offset, src.base, dest);
618 void xor32(RegisterID op1, RegisterID op2, RegisterID dest)
621 move(TrustedImm32(0), dest);
622 else if (op1 == dest)
625 move32IfNeeded(op2, dest);
630 void xor32(Address op1, RegisterID op2, RegisterID dest)
634 else if (op1.base == dest) {
638 zeroExtend32ToPtr(op2, dest);
643 void xor32(RegisterID op1, Address op2, RegisterID dest)
645 xor32(op2, op1, dest);
648 void xor32(TrustedImm32 imm, RegisterID src, RegisterID dest)
650 move32IfNeeded(src, dest);
654 void not32(RegisterID srcDest)
656 m_assembler.notl_r(srcDest);
659 void not32(Address dest)
661 m_assembler.notl_m(dest.offset, dest.base);
664 void sqrtDouble(FPRegisterID src, FPRegisterID dst)
666 m_assembler.sqrtsd_rr(src, dst);
669 void sqrtDouble(Address src, FPRegisterID dst)
671 m_assembler.sqrtsd_mr(src.offset, src.base, dst);
674 void sqrtFloat(FPRegisterID src, FPRegisterID dst)
676 m_assembler.sqrtss_rr(src, dst);
679 void sqrtFloat(Address src, FPRegisterID dst)
681 m_assembler.sqrtss_mr(src.offset, src.base, dst);
684 void absDouble(FPRegisterID src, FPRegisterID dst)
687 static const double negativeZeroConstant = -0.0;
688 loadDouble(TrustedImmPtr(&negativeZeroConstant), dst);
689 m_assembler.andnpd_rr(src, dst);
692 void negateDouble(FPRegisterID src, FPRegisterID dst)
695 static const double negativeZeroConstant = -0.0;
696 loadDouble(TrustedImmPtr(&negativeZeroConstant), dst);
697 m_assembler.xorpd_rr(src, dst);
700 void ceilDouble(FPRegisterID src, FPRegisterID dst)
702 m_assembler.roundsd_rr(src, dst, X86Assembler::RoundingType::TowardInfiniti);
705 void ceilDouble(Address src, FPRegisterID dst)
707 m_assembler.roundsd_mr(src.offset, src.base, dst, X86Assembler::RoundingType::TowardInfiniti);
710 void ceilFloat(FPRegisterID src, FPRegisterID dst)
712 m_assembler.roundss_rr(src, dst, X86Assembler::RoundingType::TowardInfiniti);
715 void ceilFloat(Address src, FPRegisterID dst)
717 m_assembler.roundss_mr(src.offset, src.base, dst, X86Assembler::RoundingType::TowardInfiniti);
720 void floorDouble(FPRegisterID src, FPRegisterID dst)
722 m_assembler.roundsd_rr(src, dst, X86Assembler::RoundingType::TowardNegativeInfiniti);
725 void floorDouble(Address src, FPRegisterID dst)
727 m_assembler.roundsd_mr(src.offset, src.base, dst, X86Assembler::RoundingType::TowardNegativeInfiniti);
730 void floorFloat(FPRegisterID src, FPRegisterID dst)
732 m_assembler.roundss_rr(src, dst, X86Assembler::RoundingType::TowardNegativeInfiniti);
735 void floorFloat(Address src, FPRegisterID dst)
737 m_assembler.roundss_mr(src.offset, src.base, dst, X86Assembler::RoundingType::TowardNegativeInfiniti);
740 void roundTowardZeroDouble(FPRegisterID src, FPRegisterID dst)
742 m_assembler.roundsd_rr(src, dst, X86Assembler::RoundingType::TowardZero);
745 void roundTowardZeroDouble(Address src, FPRegisterID dst)
747 m_assembler.roundsd_mr(src.offset, src.base, dst, X86Assembler::RoundingType::TowardZero);
750 void roundTowardZeroFloat(FPRegisterID src, FPRegisterID dst)
752 m_assembler.roundss_rr(src, dst, X86Assembler::RoundingType::TowardZero);
755 void roundTowardZeroFloat(Address src, FPRegisterID dst)
757 m_assembler.roundss_mr(src.offset, src.base, dst, X86Assembler::RoundingType::TowardZero);
760 // Memory access operations:
762 // Loads are of the form load(address, destination) and stores of the form
763 // store(source, address). The source for a store may be an TrustedImm32. Address
764 // operand objects to loads and store will be implicitly constructed if a
765 // register is passed.
767 void load32(ImplicitAddress address, RegisterID dest)
769 m_assembler.movl_mr(address.offset, address.base, dest);
772 void load32(BaseIndex address, RegisterID dest)
774 m_assembler.movl_mr(address.offset, address.base, address.index, address.scale, dest);
777 void load32WithUnalignedHalfWords(BaseIndex address, RegisterID dest)
779 load32(address, dest);
782 void load16Unaligned(BaseIndex address, RegisterID dest)
784 load16(address, dest);
787 DataLabel32 load32WithAddressOffsetPatch(Address address, RegisterID dest)
790 m_assembler.movl_mr_disp32(address.offset, address.base, dest);
791 return DataLabel32(this);
794 DataLabelCompact load32WithCompactAddressOffsetPatch(Address address, RegisterID dest)
797 m_assembler.movl_mr_disp8(address.offset, address.base, dest);
798 return DataLabelCompact(this);
801 static void repatchCompact(CodeLocationDataLabelCompact dataLabelCompact, int32_t value)
803 ASSERT(isCompactPtrAlignedAddressOffset(value));
804 AssemblerType_T::repatchCompact(dataLabelCompact.dataLocation(), value);
807 DataLabelCompact loadCompactWithAddressOffsetPatch(Address address, RegisterID dest)
810 m_assembler.movl_mr_disp8(address.offset, address.base, dest);
811 return DataLabelCompact(this);
814 void load8(BaseIndex address, RegisterID dest)
816 m_assembler.movzbl_mr(address.offset, address.base, address.index, address.scale, dest);
819 void load8(ImplicitAddress address, RegisterID dest)
821 m_assembler.movzbl_mr(address.offset, address.base, dest);
824 void load8SignedExtendTo32(BaseIndex address, RegisterID dest)
826 m_assembler.movsbl_mr(address.offset, address.base, address.index, address.scale, dest);
829 void load8SignedExtendTo32(ImplicitAddress address, RegisterID dest)
831 m_assembler.movsbl_mr(address.offset, address.base, dest);
834 void zeroExtend8To32(RegisterID src, RegisterID dest)
836 m_assembler.movzbl_rr(src, dest);
839 void signExtend8To32(RegisterID src, RegisterID dest)
841 m_assembler.movsbl_rr(src, dest);
844 void load16(BaseIndex address, RegisterID dest)
846 m_assembler.movzwl_mr(address.offset, address.base, address.index, address.scale, dest);
849 void load16(Address address, RegisterID dest)
851 m_assembler.movzwl_mr(address.offset, address.base, dest);
854 void load16SignedExtendTo32(BaseIndex address, RegisterID dest)
856 m_assembler.movswl_mr(address.offset, address.base, address.index, address.scale, dest);
859 void load16SignedExtendTo32(Address address, RegisterID dest)
861 m_assembler.movswl_mr(address.offset, address.base, dest);
864 void zeroExtend16To32(RegisterID src, RegisterID dest)
866 m_assembler.movzwl_rr(src, dest);
869 void signExtend16To32(RegisterID src, RegisterID dest)
871 m_assembler.movswl_rr(src, dest);
874 DataLabel32 store32WithAddressOffsetPatch(RegisterID src, Address address)
877 m_assembler.movl_rm_disp32(src, address.offset, address.base);
878 return DataLabel32(this);
881 void store32(RegisterID src, ImplicitAddress address)
883 m_assembler.movl_rm(src, address.offset, address.base);
886 void store32(RegisterID src, BaseIndex address)
888 m_assembler.movl_rm(src, address.offset, address.base, address.index, address.scale);
891 void store32(TrustedImm32 imm, ImplicitAddress address)
893 m_assembler.movl_i32m(imm.m_value, address.offset, address.base);
896 void store32(TrustedImm32 imm, BaseIndex address)
898 m_assembler.movl_i32m(imm.m_value, address.offset, address.base, address.index, address.scale);
901 void storeZero32(ImplicitAddress address)
903 store32(TrustedImm32(0), address);
906 void storeZero32(BaseIndex address)
908 store32(TrustedImm32(0), address);
911 void store8(TrustedImm32 imm, Address address)
913 TrustedImm32 imm8(static_cast<int8_t>(imm.m_value));
914 m_assembler.movb_i8m(imm8.m_value, address.offset, address.base);
917 void store8(TrustedImm32 imm, BaseIndex address)
919 TrustedImm32 imm8(static_cast<int8_t>(imm.m_value));
920 m_assembler.movb_i8m(imm8.m_value, address.offset, address.base, address.index, address.scale);
923 static ALWAYS_INLINE RegisterID getUnusedRegister(BaseIndex address)
925 if (address.base != X86Registers::eax && address.index != X86Registers::eax)
926 return X86Registers::eax;
928 if (address.base != X86Registers::ebx && address.index != X86Registers::ebx)
929 return X86Registers::ebx;
931 ASSERT(address.base != X86Registers::ecx && address.index != X86Registers::ecx);
932 return X86Registers::ecx;
935 static ALWAYS_INLINE RegisterID getUnusedRegister(Address address)
937 if (address.base != X86Registers::eax)
938 return X86Registers::eax;
940 ASSERT(address.base != X86Registers::edx);
941 return X86Registers::edx;
944 void store8(RegisterID src, BaseIndex address)
947 // On 32-bit x86 we can only store from the first 4 registers;
948 // esp..edi are mapped to the 'h' registers!
950 // Pick a temporary register.
951 RegisterID temp = getUnusedRegister(address);
953 // Swap to the temporary register to perform the store.
955 m_assembler.movb_rm(temp, address.offset, address.base, address.index, address.scale);
960 m_assembler.movb_rm(src, address.offset, address.base, address.index, address.scale);
963 void store8(RegisterID src, Address address)
966 // On 32-bit x86 we can only store from the first 4 registers;
967 // esp..edi are mapped to the 'h' registers!
969 // Pick a temporary register.
970 RegisterID temp = getUnusedRegister(address);
972 // Swap to the temporary register to perform the store.
974 m_assembler.movb_rm(temp, address.offset, address.base);
979 m_assembler.movb_rm(src, address.offset, address.base);
982 void store16(RegisterID src, BaseIndex address)
985 // On 32-bit x86 we can only store from the first 4 registers;
986 // esp..edi are mapped to the 'h' registers!
988 // Pick a temporary register.
989 RegisterID temp = getUnusedRegister(address);
991 // Swap to the temporary register to perform the store.
993 m_assembler.movw_rm(temp, address.offset, address.base, address.index, address.scale);
998 m_assembler.movw_rm(src, address.offset, address.base, address.index, address.scale);
1001 void store16(RegisterID src, Address address)
1004 // On 32-bit x86 we can only store from the first 4 registers;
1005 // esp..edi are mapped to the 'h' registers!
1007 // Pick a temporary register.
1008 RegisterID temp = getUnusedRegister(address);
1010 // Swap to the temporary register to perform the store.
1012 m_assembler.movw_rm(temp, address.offset, address.base);
1017 m_assembler.movw_rm(src, address.offset, address.base);
1021 // Floating-point operation:
1023 // Presently only supports SSE, not x87 floating point.
1025 void moveDouble(FPRegisterID src, FPRegisterID dest)
1027 ASSERT(isSSE2Present());
1029 m_assembler.movaps_rr(src, dest);
1032 void loadDouble(TrustedImmPtr address, FPRegisterID dest)
1035 ASSERT(isSSE2Present());
1036 m_assembler.movsd_mr(address.m_value, dest);
1038 move(address, scratchRegister());
1039 loadDouble(scratchRegister(), dest);
1043 void loadDouble(ImplicitAddress address, FPRegisterID dest)
1045 ASSERT(isSSE2Present());
1046 m_assembler.movsd_mr(address.offset, address.base, dest);
1049 void loadDouble(BaseIndex address, FPRegisterID dest)
1051 ASSERT(isSSE2Present());
1052 m_assembler.movsd_mr(address.offset, address.base, address.index, address.scale, dest);
1055 void loadFloat(ImplicitAddress address, FPRegisterID dest)
1057 ASSERT(isSSE2Present());
1058 m_assembler.movss_mr(address.offset, address.base, dest);
1061 void loadFloat(BaseIndex address, FPRegisterID dest)
1063 ASSERT(isSSE2Present());
1064 m_assembler.movss_mr(address.offset, address.base, address.index, address.scale, dest);
1067 void storeDouble(FPRegisterID src, ImplicitAddress address)
1069 ASSERT(isSSE2Present());
1070 m_assembler.movsd_rm(src, address.offset, address.base);
1073 void storeDouble(FPRegisterID src, BaseIndex address)
1075 ASSERT(isSSE2Present());
1076 m_assembler.movsd_rm(src, address.offset, address.base, address.index, address.scale);
1079 void storeFloat(FPRegisterID src, ImplicitAddress address)
1081 ASSERT(isSSE2Present());
1082 m_assembler.movss_rm(src, address.offset, address.base);
1085 void storeFloat(FPRegisterID src, BaseIndex address)
1087 ASSERT(isSSE2Present());
1088 m_assembler.movss_rm(src, address.offset, address.base, address.index, address.scale);
1091 void convertDoubleToFloat(FPRegisterID src, FPRegisterID dst)
1093 ASSERT(isSSE2Present());
1094 m_assembler.cvtsd2ss_rr(src, dst);
1097 void convertDoubleToFloat(Address address, FPRegisterID dst)
1099 ASSERT(isSSE2Present());
1100 m_assembler.cvtsd2ss_mr(address.offset, address.base, dst);
1103 void convertFloatToDouble(FPRegisterID src, FPRegisterID dst)
1105 ASSERT(isSSE2Present());
1106 m_assembler.cvtss2sd_rr(src, dst);
1109 void convertFloatToDouble(Address address, FPRegisterID dst)
1111 ASSERT(isSSE2Present());
1112 m_assembler.cvtss2sd_mr(address.offset, address.base, dst);
1115 void addDouble(FPRegisterID src, FPRegisterID dest)
1117 addDouble(src, dest, dest);
1120 void addDouble(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest)
1123 m_assembler.vaddsd_rr(op1, op2, dest);
1125 ASSERT(isSSE2Present());
1127 m_assembler.addsd_rr(op2, dest);
1129 moveDouble(op2, dest);
1130 m_assembler.addsd_rr(op1, dest);
1135 void addDouble(Address src, FPRegisterID dest)
1137 addDouble(src, dest, dest);
1140 void addDouble(Address op1, FPRegisterID op2, FPRegisterID dest)
1143 m_assembler.vaddsd_mr(op1.offset, op1.base, op2, dest);
1145 ASSERT(isSSE2Present());
1147 m_assembler.addsd_mr(op1.offset, op1.base, dest);
1151 loadDouble(op1, dest);
1152 addDouble(op2, dest);
1156 void addDouble(FPRegisterID op1, Address op2, FPRegisterID dest)
1158 addDouble(op2, op1, dest);
1161 void addDouble(BaseIndex op1, FPRegisterID op2, FPRegisterID dest)
1164 m_assembler.vaddsd_mr(op1.offset, op1.base, op1.index, op1.scale, op2, dest);
1166 ASSERT(isSSE2Present());
1168 m_assembler.addsd_mr(op1.offset, op1.base, op1.index, op1.scale, dest);
1171 loadDouble(op1, dest);
1172 addDouble(op2, dest);
1176 void addFloat(FPRegisterID src, FPRegisterID dest)
1178 addFloat(src, dest, dest);
1181 void addFloat(Address src, FPRegisterID dest)
1183 addFloat(src, dest, dest);
1186 void addFloat(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest)
1189 m_assembler.vaddss_rr(op1, op2, dest);
1191 ASSERT(isSSE2Present());
1193 m_assembler.addss_rr(op2, dest);
1195 moveDouble(op2, dest);
1196 m_assembler.addss_rr(op1, dest);
1201 void addFloat(Address op1, FPRegisterID op2, FPRegisterID dest)
1204 m_assembler.vaddss_mr(op1.offset, op1.base, op2, dest);
1206 ASSERT(isSSE2Present());
1208 m_assembler.addss_mr(op1.offset, op1.base, dest);
1212 loadFloat(op1, dest);
1213 addFloat(op2, dest);
1217 void addFloat(FPRegisterID op1, Address op2, FPRegisterID dest)
1219 addFloat(op2, op1, dest);
1222 void addFloat(BaseIndex op1, FPRegisterID op2, FPRegisterID dest)
1225 m_assembler.vaddss_mr(op1.offset, op1.base, op1.index, op1.scale, op2, dest);
1227 ASSERT(isSSE2Present());
1229 m_assembler.addss_mr(op1.offset, op1.base, op1.index, op1.scale, dest);
1232 loadFloat(op1, dest);
1233 addFloat(op2, dest);
1237 void divDouble(FPRegisterID src, FPRegisterID dest)
1239 ASSERT(isSSE2Present());
1240 m_assembler.divsd_rr(src, dest);
1243 void divDouble(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest)
1245 // B := A / B is invalid.
1246 ASSERT(op1 == dest || op2 != dest);
1248 moveDouble(op1, dest);
1249 divDouble(op2, dest);
1252 void divDouble(Address src, FPRegisterID dest)
1254 ASSERT(isSSE2Present());
1255 m_assembler.divsd_mr(src.offset, src.base, dest);
1258 void divFloat(FPRegisterID src, FPRegisterID dest)
1260 ASSERT(isSSE2Present());
1261 m_assembler.divss_rr(src, dest);
1264 void divFloat(Address src, FPRegisterID dest)
1266 ASSERT(isSSE2Present());
1267 m_assembler.divss_mr(src.offset, src.base, dest);
1270 void subDouble(FPRegisterID src, FPRegisterID dest)
1272 subDouble(dest, src, dest);
1275 void subDouble(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest)
1278 m_assembler.vsubsd_rr(op1, op2, dest);
1280 ASSERT(isSSE2Present());
1282 // B := A - B is invalid.
1283 ASSERT(op1 == dest || op2 != dest);
1284 moveDouble(op1, dest);
1285 m_assembler.subsd_rr(op2, dest);
1289 void subDouble(FPRegisterID op1, Address op2, FPRegisterID dest)
1292 m_assembler.vsubsd_mr(op1, op2.offset, op2.base, dest);
1294 moveDouble(op1, dest);
1295 m_assembler.subsd_mr(op2.offset, op2.base, dest);
1299 void subDouble(FPRegisterID op1, BaseIndex op2, FPRegisterID dest)
1302 m_assembler.vsubsd_mr(op1, op2.offset, op2.base, op2.index, op2.scale, dest);
1304 moveDouble(op1, dest);
1305 m_assembler.subsd_mr(op2.offset, op2.base, op2.index, op2.scale, dest);
1309 void subDouble(Address src, FPRegisterID dest)
1311 subDouble(dest, src, dest);
1314 void subFloat(FPRegisterID src, FPRegisterID dest)
1316 subFloat(dest, src, dest);
1319 void subFloat(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest)
1322 m_assembler.vsubss_rr(op1, op2, dest);
1324 ASSERT(isSSE2Present());
1325 // B := A - B is invalid.
1326 ASSERT(op1 == dest || op2 != dest);
1327 moveDouble(op1, dest);
1328 m_assembler.subss_rr(op2, dest);
1332 void subFloat(FPRegisterID op1, Address op2, FPRegisterID dest)
1335 m_assembler.vsubss_mr(op1, op2.offset, op2.base, dest);
1337 moveDouble(op1, dest);
1338 m_assembler.subss_mr(op2.offset, op2.base, dest);
1342 void subFloat(FPRegisterID op1, BaseIndex op2, FPRegisterID dest)
1345 m_assembler.vsubss_mr(op1, op2.offset, op2.base, op2.index, op2.scale, dest);
1347 moveDouble(op1, dest);
1348 m_assembler.subss_mr(op2.offset, op2.base, op2.index, op2.scale, dest);
1352 void subFloat(Address src, FPRegisterID dest)
1354 subFloat(dest, src, dest);
1357 void mulDouble(FPRegisterID src, FPRegisterID dest)
1359 mulDouble(src, dest, dest);
1362 void mulDouble(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest)
1365 m_assembler.vmulsd_rr(op1, op2, dest);
1367 ASSERT(isSSE2Present());
1369 m_assembler.mulsd_rr(op2, dest);
1371 moveDouble(op2, dest);
1372 m_assembler.mulsd_rr(op1, dest);
1377 void mulDouble(Address src, FPRegisterID dest)
1379 mulDouble(src, dest, dest);
1382 void mulDouble(Address op1, FPRegisterID op2, FPRegisterID dest)
1385 m_assembler.vmulsd_mr(op1.offset, op1.base, op2, dest);
1387 ASSERT(isSSE2Present());
1389 m_assembler.mulsd_mr(op1.offset, op1.base, dest);
1392 loadDouble(op1, dest);
1393 mulDouble(op2, dest);
1397 void mulDouble(FPRegisterID op1, Address op2, FPRegisterID dest)
1399 return mulDouble(op2, op1, dest);
1402 void mulDouble(BaseIndex op1, FPRegisterID op2, FPRegisterID dest)
1405 m_assembler.vmulsd_mr(op1.offset, op1.base, op1.index, op1.scale, op2, dest);
1407 ASSERT(isSSE2Present());
1409 m_assembler.mulsd_mr(op1.offset, op1.base, op1.index, op1.scale, dest);
1412 loadDouble(op1, dest);
1413 mulDouble(op2, dest);
1417 void mulFloat(FPRegisterID src, FPRegisterID dest)
1419 mulFloat(src, dest, dest);
1422 void mulFloat(Address src, FPRegisterID dest)
1424 mulFloat(src, dest, dest);
1427 void mulFloat(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest)
1430 m_assembler.vmulss_rr(op1, op2, dest);
1432 ASSERT(isSSE2Present());
1434 m_assembler.mulss_rr(op2, dest);
1436 moveDouble(op2, dest);
1437 m_assembler.mulss_rr(op1, dest);
1442 void mulFloat(Address op1, FPRegisterID op2, FPRegisterID dest)
1445 m_assembler.vmulss_mr(op1.offset, op1.base, op2, dest);
1447 ASSERT(isSSE2Present());
1449 m_assembler.mulss_mr(op1.offset, op1.base, dest);
1452 loadFloat(op1, dest);
1453 mulFloat(op2, dest);
1457 void mulFloat(FPRegisterID op1, Address op2, FPRegisterID dest)
1459 mulFloat(op2, op1, dest);
1462 void mulFloat(BaseIndex op1, FPRegisterID op2, FPRegisterID dest)
1465 m_assembler.vmulss_mr(op1.offset, op1.base, op1.index, op1.scale, op2, dest);
1467 ASSERT(isSSE2Present());
1469 m_assembler.mulss_mr(op1.offset, op1.base, op1.index, op1.scale, dest);
1472 loadFloat(op1, dest);
1473 mulFloat(op2, dest);
1477 void andDouble(FPRegisterID src, FPRegisterID dst)
1479 // ANDPS is defined on 128bits and is shorter than ANDPD.
1480 m_assembler.andps_rr(src, dst);
1483 void andDouble(FPRegisterID src1, FPRegisterID src2, FPRegisterID dst)
1486 andDouble(src2, dst);
1488 moveDouble(src2, dst);
1489 andDouble(src1, dst);
1493 void andFloat(FPRegisterID src, FPRegisterID dst)
1495 m_assembler.andps_rr(src, dst);
1498 void andFloat(FPRegisterID src1, FPRegisterID src2, FPRegisterID dst)
1501 andFloat(src2, dst);
1503 moveDouble(src2, dst);
1504 andFloat(src1, dst);
1508 void xorDouble(FPRegisterID src, FPRegisterID dst)
1510 m_assembler.xorps_rr(src, dst);
1513 void xorDouble(FPRegisterID src1, FPRegisterID src2, FPRegisterID dst)
1516 xorDouble(src2, dst);
1518 moveDouble(src2, dst);
1519 xorDouble(src1, dst);
1523 void xorFloat(FPRegisterID src, FPRegisterID dst)
1525 m_assembler.xorps_rr(src, dst);
1528 void xorFloat(FPRegisterID src1, FPRegisterID src2, FPRegisterID dst)
1531 xorFloat(src2, dst);
1533 moveDouble(src2, dst);
1534 xorFloat(src1, dst);
1538 void convertInt32ToDouble(RegisterID src, FPRegisterID dest)
1540 ASSERT(isSSE2Present());
1541 m_assembler.cvtsi2sd_rr(src, dest);
1544 void convertInt32ToDouble(Address src, FPRegisterID dest)
1546 ASSERT(isSSE2Present());
1547 m_assembler.cvtsi2sd_mr(src.offset, src.base, dest);
1550 void convertInt32ToFloat(RegisterID src, FPRegisterID dest)
1552 ASSERT(isSSE2Present());
1553 m_assembler.cvtsi2ss_rr(src, dest);
1556 void convertInt32ToFloat(Address src, FPRegisterID dest)
1558 ASSERT(isSSE2Present());
1559 m_assembler.cvtsi2ss_mr(src.offset, src.base, dest);
1562 Jump branchDouble(DoubleCondition cond, FPRegisterID left, FPRegisterID right)
1564 ASSERT(isSSE2Present());
1566 if (cond & DoubleConditionBitInvert)
1567 m_assembler.ucomisd_rr(left, right);
1569 m_assembler.ucomisd_rr(right, left);
1570 return jumpAfterFloatingPointCompare(cond, left, right);
1573 Jump branchFloat(DoubleCondition cond, FPRegisterID left, FPRegisterID right)
1575 ASSERT(isSSE2Present());
1577 if (cond & DoubleConditionBitInvert)
1578 m_assembler.ucomiss_rr(left, right);
1580 m_assembler.ucomiss_rr(right, left);
1581 return jumpAfterFloatingPointCompare(cond, left, right);
1584 // Truncates 'src' to an integer, and places the resulting 'dest'.
1585 // If the result is not representable as a 32 bit value, branch.
1586 // May also branch for some values that are representable in 32 bits
1587 // (specifically, in this case, INT_MIN).
1588 enum BranchTruncateType { BranchIfTruncateFailed, BranchIfTruncateSuccessful };
1589 Jump branchTruncateDoubleToInt32(FPRegisterID src, RegisterID dest, BranchTruncateType branchType = BranchIfTruncateFailed)
1591 ASSERT(isSSE2Present());
1592 m_assembler.cvttsd2si_rr(src, dest);
1593 return branch32(branchType ? NotEqual : Equal, dest, TrustedImm32(0x80000000));
1596 void truncateDoubleToInt32(FPRegisterID src, RegisterID dest)
1598 ASSERT(isSSE2Present());
1599 m_assembler.cvttsd2si_rr(src, dest);
1603 void truncateDoubleToUint32(FPRegisterID src, RegisterID dest)
1605 ASSERT(isSSE2Present());
1606 m_assembler.cvttsd2siq_rr(src, dest);
1610 // Convert 'src' to an integer, and places the resulting 'dest'.
1611 // If the result is not representable as a 32 bit value, branch.
1612 // May also branch for some values that are representable in 32 bits
1613 // (specifically, in this case, 0).
1614 void branchConvertDoubleToInt32(FPRegisterID src, RegisterID dest, JumpList& failureCases, FPRegisterID fpTemp, bool negZeroCheck = true)
1616 ASSERT(isSSE2Present());
1617 m_assembler.cvttsd2si_rr(src, dest);
1619 // If the result is zero, it might have been -0.0, and the double comparison won't catch this!
1622 Jump valueIsNonZero = branchTest32(NonZero, dest);
1623 m_assembler.movmskpd_rr(src, scratchRegister());
1624 failureCases.append(branchTest32(NonZero, scratchRegister(), TrustedImm32(1)));
1625 valueIsNonZero.link(this);
1629 failureCases.append(branchTest32(Zero, dest));
1632 // Convert the integer result back to float & compare to the original value - if not equal or unordered (NaN) then jump.
1633 convertInt32ToDouble(dest, fpTemp);
1634 m_assembler.ucomisd_rr(fpTemp, src);
1635 failureCases.append(m_assembler.jp());
1636 failureCases.append(m_assembler.jne());
1639 void moveZeroToDouble(FPRegisterID reg)
1641 m_assembler.xorps_rr(reg, reg);
1644 Jump branchDoubleNonZero(FPRegisterID reg, FPRegisterID scratch)
1646 ASSERT(isSSE2Present());
1647 m_assembler.xorpd_rr(scratch, scratch);
1648 return branchDouble(DoubleNotEqual, reg, scratch);
1651 Jump branchDoubleZeroOrNaN(FPRegisterID reg, FPRegisterID scratch)
1653 ASSERT(isSSE2Present());
1654 m_assembler.xorpd_rr(scratch, scratch);
1655 return branchDouble(DoubleEqualOrUnordered, reg, scratch);
1658 void lshiftPacked(TrustedImm32 imm, XMMRegisterID reg)
1660 ASSERT(isSSE2Present());
1661 m_assembler.psllq_i8r(imm.m_value, reg);
1664 void rshiftPacked(TrustedImm32 imm, XMMRegisterID reg)
1666 ASSERT(isSSE2Present());
1667 m_assembler.psrlq_i8r(imm.m_value, reg);
1670 void orPacked(XMMRegisterID src, XMMRegisterID dst)
1672 ASSERT(isSSE2Present());
1673 m_assembler.por_rr(src, dst);
1676 void move32ToFloat(RegisterID src, XMMRegisterID dst)
1678 ASSERT(isSSE2Present());
1679 m_assembler.movd_rr(src, dst);
1682 void moveFloatTo32(XMMRegisterID src, RegisterID dst)
1684 ASSERT(isSSE2Present());
1685 m_assembler.movd_rr(src, dst);
1688 // Stack manipulation operations:
1690 // The ABI is assumed to provide a stack abstraction to memory,
1691 // containing machine word sized units of data. Push and pop
1692 // operations add and remove a single register sized unit of data
1693 // to or from the stack. Peek and poke operations read or write
1694 // values on the stack, without moving the current stack position.
1696 void pop(RegisterID dest)
1698 m_assembler.pop_r(dest);
1701 void push(RegisterID src)
1703 m_assembler.push_r(src);
1706 void push(Address address)
1708 m_assembler.push_m(address.offset, address.base);
1711 void push(TrustedImm32 imm)
1713 m_assembler.push_i32(imm.m_value);
1717 // Register move operations:
1719 // Move values in registers.
1721 void move(TrustedImm32 imm, RegisterID dest)
1723 // Note: on 64-bit the TrustedImm32 value is zero extended into the register, it
1724 // may be useful to have a separate version that sign extends the value?
1726 m_assembler.xorl_rr(dest, dest);
1728 m_assembler.movl_i32r(imm.m_value, dest);
1732 void move(RegisterID src, RegisterID dest)
1734 // Note: on 64-bit this is is a full register move; perhaps it would be
1735 // useful to have separate move32 & movePtr, with move32 zero extending?
1737 m_assembler.movq_rr(src, dest);
1740 void move(TrustedImmPtr imm, RegisterID dest)
1743 m_assembler.xorq_rr(dest, dest);
1745 m_assembler.movq_i64r(imm.asIntptr(), dest);
1748 void move(TrustedImm64 imm, RegisterID dest)
1751 m_assembler.xorq_rr(dest, dest);
1753 m_assembler.movq_i64r(imm.m_value, dest);
1756 void moveConditionallyDouble(DoubleCondition cond, FPRegisterID left, FPRegisterID right, RegisterID src, RegisterID dest)
1758 ASSERT(isSSE2Present());
1760 if (cond & DoubleConditionBitInvert)
1761 m_assembler.ucomisd_rr(left, right);
1763 m_assembler.ucomisd_rr(right, left);
1764 moveConditionallyAfterFloatingPointCompare(cond, left, right, src, dest);
1767 void moveConditionallyDouble(DoubleCondition cond, FPRegisterID left, FPRegisterID right, RegisterID thenCase, RegisterID elseCase, RegisterID dest)
1769 ASSERT(isSSE2Present());
1771 if (thenCase != dest && elseCase != dest) {
1772 move(elseCase, dest);
1777 if (elseCase == dest)
1780 cond = invert(cond);
1784 if (cond & DoubleConditionBitInvert)
1785 m_assembler.ucomisd_rr(left, right);
1787 m_assembler.ucomisd_rr(right, left);
1788 moveConditionallyAfterFloatingPointCompare(cond, left, right, src, dest);
1791 void moveConditionallyFloat(DoubleCondition cond, FPRegisterID left, FPRegisterID right, RegisterID src, RegisterID dest)
1793 ASSERT(isSSE2Present());
1795 if (cond & DoubleConditionBitInvert)
1796 m_assembler.ucomiss_rr(left, right);
1798 m_assembler.ucomiss_rr(right, left);
1799 moveConditionallyAfterFloatingPointCompare(cond, left, right, src, dest);
1802 void moveConditionallyFloat(DoubleCondition cond, FPRegisterID left, FPRegisterID right, RegisterID thenCase, RegisterID elseCase, RegisterID dest)
1804 ASSERT(isSSE2Present());
1806 if (thenCase != dest && elseCase != dest) {
1807 move(elseCase, dest);
1812 if (elseCase == dest)
1815 cond = invert(cond);
1819 if (cond & DoubleConditionBitInvert)
1820 m_assembler.ucomiss_rr(left, right);
1822 m_assembler.ucomiss_rr(right, left);
1823 moveConditionallyAfterFloatingPointCompare(cond, left, right, src, dest);
1826 void swap(RegisterID reg1, RegisterID reg2)
1829 m_assembler.xchgq_rr(reg1, reg2);
1832 void signExtend32ToPtr(TrustedImm32 imm, RegisterID dest)
1835 m_assembler.xorq_rr(dest, dest);
1837 m_assembler.mov_i32r(imm.m_value, dest);
1840 void signExtend32ToPtr(RegisterID src, RegisterID dest)
1842 m_assembler.movsxd_rr(src, dest);
1845 void zeroExtend32ToPtr(RegisterID src, RegisterID dest)
1847 m_assembler.movl_rr(src, dest);
1850 void zeroExtend32ToPtr(TrustedImm32 src, RegisterID dest)
1852 m_assembler.movl_i32r(src.m_value, dest);
1855 void move(RegisterID src, RegisterID dest)
1858 m_assembler.movl_rr(src, dest);
1861 void move(TrustedImmPtr imm, RegisterID dest)
1864 m_assembler.xorl_rr(dest, dest);
1866 m_assembler.movl_i32r(imm.asIntptr(), dest);
1869 void moveConditionallyDouble(DoubleCondition cond, FPRegisterID left, FPRegisterID right, RegisterID src, RegisterID dest)
1871 ASSERT(isSSE2Present());
1873 if (cond & DoubleConditionBitInvert)
1874 m_assembler.ucomisd_rr(left, right);
1876 m_assembler.ucomisd_rr(right, left);
1878 if (cond == DoubleEqual) {
1879 if (left == right) {
1880 m_assembler.cmovnpl_rr(src, dest);
1884 Jump isUnordered(m_assembler.jp());
1885 m_assembler.cmovel_rr(src, dest);
1886 isUnordered.link(this);
1890 if (cond == DoubleNotEqualOrUnordered) {
1891 if (left == right) {
1892 m_assembler.cmovpl_rr(src, dest);
1896 m_assembler.cmovpl_rr(src, dest);
1897 m_assembler.cmovnel_rr(src, dest);
1901 ASSERT(!(cond & DoubleConditionBitSpecial));
1902 m_assembler.cmovl_rr(static_cast<X86Assembler::Condition>(cond & ~DoubleConditionBits), src, dest);
1905 void swap(RegisterID reg1, RegisterID reg2)
1908 m_assembler.xchgl_rr(reg1, reg2);
1911 void signExtend32ToPtr(RegisterID src, RegisterID dest)
1916 void zeroExtend32ToPtr(RegisterID src, RegisterID dest)
1922 void swap32(RegisterID src, RegisterID dest)
1924 m_assembler.xchgl_rr(src, dest);
1927 void swap32(RegisterID src, Address dest)
1929 m_assembler.xchgl_rm(src, dest.offset, dest.base);
1932 void moveConditionally32(RelationalCondition cond, RegisterID left, RegisterID right, RegisterID src, RegisterID dest)
1934 m_assembler.cmpl_rr(right, left);
1935 cmov(x86Condition(cond), src, dest);
1938 void moveConditionally32(RelationalCondition cond, RegisterID left, RegisterID right, RegisterID thenCase, RegisterID elseCase, RegisterID dest)
1940 m_assembler.cmpl_rr(right, left);
1942 if (thenCase != dest && elseCase != dest) {
1943 move(elseCase, dest);
1947 if (elseCase == dest)
1948 cmov(x86Condition(cond), thenCase, dest);
1950 cmov(x86Condition(invert(cond)), elseCase, dest);
1953 void moveConditionally32(RelationalCondition cond, RegisterID left, TrustedImm32 right, RegisterID thenCase, RegisterID elseCase, RegisterID dest)
1955 if (!right.m_value) {
1956 if (auto resultCondition = commuteCompareToZeroIntoTest(cond)) {
1957 moveConditionallyTest32(*resultCondition, left, left, thenCase, elseCase, dest);
1962 m_assembler.cmpl_ir(right.m_value, left);
1964 if (thenCase != dest && elseCase != dest) {
1965 move(elseCase, dest);
1969 if (elseCase == dest)
1970 cmov(x86Condition(cond), thenCase, dest);
1972 cmov(x86Condition(invert(cond)), elseCase, dest);
1975 void moveConditionallyTest32(ResultCondition cond, RegisterID testReg, RegisterID mask, RegisterID src, RegisterID dest)
1977 m_assembler.testl_rr(testReg, mask);
1978 cmov(x86Condition(cond), src, dest);
1981 void moveConditionallyTest32(ResultCondition cond, RegisterID left, RegisterID right, RegisterID thenCase, RegisterID elseCase, RegisterID dest)
1983 ASSERT(isInvertible(cond));
1984 ASSERT_WITH_MESSAGE(cond != Overflow, "TEST does not set the Overflow Flag.");
1986 m_assembler.testl_rr(right, left);
1988 if (thenCase != dest && elseCase != dest) {
1989 move(elseCase, dest);
1993 if (elseCase == dest)
1994 cmov(x86Condition(cond), thenCase, dest);
1996 cmov(x86Condition(invert(cond)), elseCase, dest);
1999 void moveConditionallyTest32(ResultCondition cond, RegisterID testReg, TrustedImm32 mask, RegisterID src, RegisterID dest)
2001 test32(testReg, mask);
2002 cmov(x86Condition(cond), src, dest);
2005 void moveConditionallyTest32(ResultCondition cond, RegisterID testReg, TrustedImm32 mask, RegisterID thenCase, RegisterID elseCase, RegisterID dest)
2007 ASSERT(isInvertible(cond));
2008 ASSERT_WITH_MESSAGE(cond != Overflow, "TEST does not set the Overflow Flag.");
2010 test32(testReg, mask);
2012 if (thenCase != dest && elseCase != dest) {
2013 move(elseCase, dest);
2017 if (elseCase == dest)
2018 cmov(x86Condition(cond), thenCase, dest);
2020 cmov(x86Condition(invert(cond)), elseCase, dest);
2023 template<typename LeftType, typename RightType>
2024 void moveDoubleConditionally32(RelationalCondition cond, LeftType left, RightType right, FPRegisterID thenCase, FPRegisterID elseCase, FPRegisterID dest)
2026 static_assert(!std::is_same<LeftType, FPRegisterID>::value && !std::is_same<RightType, FPRegisterID>::value, "One of the tested argument could be aliased on dest. Use moveDoubleConditionallyDouble().");
2028 if (thenCase != dest && elseCase != dest) {
2029 moveDouble(elseCase, dest);
2033 if (elseCase == dest) {
2034 Jump falseCase = branch32(invert(cond), left, right);
2035 moveDouble(thenCase, dest);
2036 falseCase.link(this);
2038 Jump trueCase = branch32(cond, left, right);
2039 moveDouble(elseCase, dest);
2040 trueCase.link(this);
2044 template<typename TestType, typename MaskType>
2045 void moveDoubleConditionallyTest32(ResultCondition cond, TestType test, MaskType mask, FPRegisterID thenCase, FPRegisterID elseCase, FPRegisterID dest)
2047 static_assert(!std::is_same<TestType, FPRegisterID>::value && !std::is_same<MaskType, FPRegisterID>::value, "One of the tested argument could be aliased on dest. Use moveDoubleConditionallyDouble().");
2049 if (elseCase == dest && isInvertible(cond)) {
2050 Jump falseCase = branchTest32(invert(cond), test, mask);
2051 moveDouble(thenCase, dest);
2052 falseCase.link(this);
2053 } else if (thenCase == dest) {
2054 Jump trueCase = branchTest32(cond, test, mask);
2055 moveDouble(elseCase, dest);
2056 trueCase.link(this);
2059 Jump trueCase = branchTest32(cond, test, mask);
2060 moveDouble(elseCase, dest);
2061 Jump falseCase = jump();
2062 trueCase.link(this);
2063 moveDouble(thenCase, dest);
2064 falseCase.link(this);
2067 void moveDoubleConditionallyDouble(DoubleCondition cond, FPRegisterID left, FPRegisterID right, FPRegisterID thenCase, FPRegisterID elseCase, FPRegisterID dest)
2069 if (elseCase == dest) {
2070 Jump falseCase = branchDouble(invert(cond), left, right);
2071 moveDouble(thenCase, dest);
2072 falseCase.link(this);
2073 } else if (thenCase == dest) {
2074 Jump trueCase = branchDouble(cond, left, right);
2075 moveDouble(elseCase, dest);
2076 trueCase.link(this);
2078 Jump trueCase = branchDouble(cond, left, right);
2079 moveDouble(elseCase, dest);
2080 Jump falseCase = jump();
2081 trueCase.link(this);
2082 moveDouble(thenCase, dest);
2083 falseCase.link(this);
2087 void moveDoubleConditionallyFloat(DoubleCondition cond, FPRegisterID left, FPRegisterID right, FPRegisterID thenCase, FPRegisterID elseCase, FPRegisterID dest)
2089 if (elseCase == dest) {
2090 Jump falseCase = branchFloat(invert(cond), left, right);
2091 moveDouble(thenCase, dest);
2092 falseCase.link(this);
2093 } else if (thenCase == dest) {
2094 Jump trueCase = branchFloat(cond, left, right);
2095 moveDouble(elseCase, dest);
2096 trueCase.link(this);
2098 Jump trueCase = branchFloat(cond, left, right);
2099 moveDouble(elseCase, dest);
2100 Jump falseCase = jump();
2101 trueCase.link(this);
2102 moveDouble(thenCase, dest);
2103 falseCase.link(this);
2107 // Forwards / external control flow operations:
2109 // This set of jump and conditional branch operations return a Jump
2110 // object which may linked at a later point, allow forwards jump,
2111 // or jumps that will require external linkage (after the code has been
2114 // For branches, signed <, >, <= and >= are denoted as l, g, le, and ge
2115 // respecitvely, for unsigned comparisons the names b, a, be, and ae are
2116 // used (representing the names 'below' and 'above').
2118 // Operands to the comparision are provided in the expected order, e.g.
2119 // jle32(reg1, TrustedImm32(5)) will branch if the value held in reg1, when
2120 // treated as a signed 32bit value, is less than or equal to 5.
2122 // jz and jnz test whether the first operand is equal to zero, and take
2123 // an optional second operand of a mask under which to perform the test.
2126 Jump branch8(RelationalCondition cond, Address left, TrustedImm32 right)
2128 TrustedImm32 right8(static_cast<int8_t>(right.m_value));
2129 m_assembler.cmpb_im(right8.m_value, left.offset, left.base);
2130 return Jump(m_assembler.jCC(x86Condition(cond)));
2133 Jump branch32(RelationalCondition cond, RegisterID left, RegisterID right)
2135 m_assembler.cmpl_rr(right, left);
2136 return Jump(m_assembler.jCC(x86Condition(cond)));
2139 Jump branch32(RelationalCondition cond, RegisterID left, TrustedImm32 right)
2141 if (!right.m_value) {
2142 if (auto resultCondition = commuteCompareToZeroIntoTest(cond))
2143 return branchTest32(*resultCondition, left, left);
2146 m_assembler.cmpl_ir(right.m_value, left);
2147 return Jump(m_assembler.jCC(x86Condition(cond)));
2150 Jump branch32(RelationalCondition cond, RegisterID left, Address right)
2152 m_assembler.cmpl_mr(right.offset, right.base, left);
2153 return Jump(m_assembler.jCC(x86Condition(cond)));
2156 Jump branch32(RelationalCondition cond, Address left, RegisterID right)
2158 m_assembler.cmpl_rm(right, left.offset, left.base);
2159 return Jump(m_assembler.jCC(x86Condition(cond)));
2162 Jump branch32(RelationalCondition cond, Address left, TrustedImm32 right)
2164 m_assembler.cmpl_im(right.m_value, left.offset, left.base);
2165 return Jump(m_assembler.jCC(x86Condition(cond)));
2168 Jump branch32(RelationalCondition cond, BaseIndex left, TrustedImm32 right)
2170 m_assembler.cmpl_im(right.m_value, left.offset, left.base, left.index, left.scale);
2171 return Jump(m_assembler.jCC(x86Condition(cond)));
2174 Jump branch32WithUnalignedHalfWords(RelationalCondition cond, BaseIndex left, TrustedImm32 right)
2176 return branch32(cond, left, right);
2179 Jump branchTest32(ResultCondition cond, RegisterID reg, RegisterID mask)
2181 m_assembler.testl_rr(reg, mask);
2182 return Jump(m_assembler.jCC(x86Condition(cond)));
2185 void test32(RegisterID reg, TrustedImm32 mask = TrustedImm32(-1))
2187 if (mask.m_value == -1)
2188 m_assembler.testl_rr(reg, reg);
2189 else if (!(mask.m_value & ~0xff) && reg < X86Registers::esp) { // Using esp and greater as a byte register yields the upper half of the 16 bit registers ax, cx, dx and bx, e.g. esp, register 4, is actually ah.
2190 if (mask.m_value == 0xff)
2191 m_assembler.testb_rr(reg, reg);
2193 m_assembler.testb_i8r(mask.m_value, reg);
2195 m_assembler.testl_i32r(mask.m_value, reg);
2198 Jump branch(ResultCondition cond)
2200 return Jump(m_assembler.jCC(x86Condition(cond)));
2203 Jump branchTest32(ResultCondition cond, RegisterID reg, TrustedImm32 mask = TrustedImm32(-1))
2206 return branch(cond);
2209 Jump branchTest32(ResultCondition cond, Address address, TrustedImm32 mask = TrustedImm32(-1))
2211 generateTest32(address, mask);
2212 return Jump(m_assembler.jCC(x86Condition(cond)));
2215 Jump branchTest32(ResultCondition cond, BaseIndex address, TrustedImm32 mask = TrustedImm32(-1))
2217 if (mask.m_value == -1)
2218 m_assembler.cmpl_im(0, address.offset, address.base, address.index, address.scale);
2220 m_assembler.testl_i32m(mask.m_value, address.offset, address.base, address.index, address.scale);
2221 return Jump(m_assembler.jCC(x86Condition(cond)));
2224 Jump branchTest8(ResultCondition cond, Address address, TrustedImm32 mask = TrustedImm32(-1))
2226 TrustedImm32 mask8(static_cast<int8_t>(mask.m_value));
2227 if (mask8.m_value == -1)
2228 m_assembler.cmpb_im(0, address.offset, address.base);
2230 m_assembler.testb_im(mask8.m_value, address.offset, address.base);
2231 return Jump(m_assembler.jCC(x86Condition(cond)));
2234 Jump branchTest8(ResultCondition cond, BaseIndex address, TrustedImm32 mask = TrustedImm32(-1))
2236 TrustedImm32 mask8(static_cast<int8_t>(mask.m_value));
2237 if (mask8.m_value == -1)
2238 m_assembler.cmpb_im(0, address.offset, address.base, address.index, address.scale);
2240 m_assembler.testb_im(mask8.m_value, address.offset, address.base, address.index, address.scale);
2241 return Jump(m_assembler.jCC(x86Condition(cond)));
2244 Jump branch8(RelationalCondition cond, BaseIndex left, TrustedImm32 right)
2246 TrustedImm32 right8(static_cast<int8_t>(right.m_value));
2247 m_assembler.cmpb_im(right8.m_value, left.offset, left.base, left.index, left.scale);
2248 return Jump(m_assembler.jCC(x86Condition(cond)));
2253 return Jump(m_assembler.jmp());
2256 void jump(RegisterID target)
2258 m_assembler.jmp_r(target);
2261 // Address is a memory location containing the address to jump to
2262 void jump(Address address)
2264 m_assembler.jmp_m(address.offset, address.base);
2267 // Address is a memory location containing the address to jump to
2268 void jump(BaseIndex address)
2270 m_assembler.jmp_m(address.offset, address.base, address.index, address.scale);
2274 // Arithmetic control flow operations:
2276 // This set of conditional branch operations branch based
2277 // on the result of an arithmetic operation. The operation
2278 // is performed as normal, storing the result.
2280 // * jz operations branch if the result is zero.
2281 // * jo operations branch if the (signed) arithmetic
2282 // operation caused an overflow to occur.
2284 Jump branchAdd32(ResultCondition cond, RegisterID src, RegisterID dest)
2287 return Jump(m_assembler.jCC(x86Condition(cond)));
2290 Jump branchAdd32(ResultCondition cond, TrustedImm32 imm, RegisterID dest)
2293 return Jump(m_assembler.jCC(x86Condition(cond)));
2296 Jump branchAdd32(ResultCondition cond, TrustedImm32 src, Address dest)
2299 return Jump(m_assembler.jCC(x86Condition(cond)));
2302 Jump branchAdd32(ResultCondition cond, RegisterID src, Address dest)
2305 return Jump(m_assembler.jCC(x86Condition(cond)));
2308 Jump branchAdd32(ResultCondition cond, Address src, RegisterID dest)
2311 return Jump(m_assembler.jCC(x86Condition(cond)));
2314 Jump branchAdd32(ResultCondition cond, RegisterID src1, RegisterID src2, RegisterID dest)
2317 return branchAdd32(cond, src2, dest);
2318 move32IfNeeded(src2, dest);
2319 return branchAdd32(cond, src1, dest);
2322 Jump branchAdd32(ResultCondition cond, Address op1, RegisterID op2, RegisterID dest)
2325 return branchAdd32(cond, op1, dest);
2326 if (op1.base == dest) {
2328 return branchAdd32(cond, op2, dest);
2330 zeroExtend32ToPtr(op2, dest);
2331 return branchAdd32(cond, op1, dest);
2334 Jump branchAdd32(ResultCondition cond, RegisterID src1, Address src2, RegisterID dest)
2336 return branchAdd32(cond, src2, src1, dest);
2339 Jump branchAdd32(ResultCondition cond, RegisterID src, TrustedImm32 imm, RegisterID dest)
2341 move32IfNeeded(src, dest);
2342 return branchAdd32(cond, imm, dest);
2345 Jump branchMul32(ResultCondition cond, RegisterID src, RegisterID dest)
2348 if (cond != Overflow)
2349 m_assembler.testl_rr(dest, dest);
2350 return Jump(m_assembler.jCC(x86Condition(cond)));
2353 Jump branchMul32(ResultCondition cond, Address src, RegisterID dest)
2356 if (cond != Overflow)
2357 m_assembler.testl_rr(dest, dest);
2358 return Jump(m_assembler.jCC(x86Condition(cond)));
2361 Jump branchMul32(ResultCondition cond, RegisterID src, TrustedImm32 imm, RegisterID dest)
2363 mul32(imm, src, dest);
2364 if (cond != Overflow)
2365 m_assembler.testl_rr(dest, dest);
2366 return Jump(m_assembler.jCC(x86Condition(cond)));
2369 Jump branchMul32(ResultCondition cond, RegisterID src1, RegisterID src2, RegisterID dest)
2372 return branchMul32(cond, src2, dest);
2373 move32IfNeeded(src2, dest);
2374 return branchMul32(cond, src1, dest);
2377 Jump branchSub32(ResultCondition cond, RegisterID src, RegisterID dest)
2380 return Jump(m_assembler.jCC(x86Condition(cond)));
2383 Jump branchSub32(ResultCondition cond, TrustedImm32 imm, RegisterID dest)
2386 return Jump(m_assembler.jCC(x86Condition(cond)));
2389 Jump branchSub32(ResultCondition cond, TrustedImm32 imm, Address dest)
2392 return Jump(m_assembler.jCC(x86Condition(cond)));
2395 Jump branchSub32(ResultCondition cond, RegisterID src, Address dest)
2398 return Jump(m_assembler.jCC(x86Condition(cond)));
2401 Jump branchSub32(ResultCondition cond, Address src, RegisterID dest)
2404 return Jump(m_assembler.jCC(x86Condition(cond)));
2407 Jump branchSub32(ResultCondition cond, RegisterID src1, RegisterID src2, RegisterID dest)
2409 // B := A - B is invalid.
2410 ASSERT(src1 == dest || src2 != dest);
2412 move32IfNeeded(src1, dest);
2413 return branchSub32(cond, src2, dest);
2416 Jump branchSub32(ResultCondition cond, RegisterID src1, TrustedImm32 src2, RegisterID dest)
2418 move32IfNeeded(src1, dest);
2419 return branchSub32(cond, src2, dest);
2422 Jump branchNeg32(ResultCondition cond, RegisterID srcDest)
2425 return Jump(m_assembler.jCC(x86Condition(cond)));
2428 Jump branchOr32(ResultCondition cond, RegisterID src, RegisterID dest)
2431 return Jump(m_assembler.jCC(x86Condition(cond)));
2435 // Miscellaneous operations:
2444 return Call(m_assembler.jmp(), Call::LinkableNearTail);
2449 return Call(m_assembler.call(), Call::LinkableNear);
2452 Call call(RegisterID target)
2454 return Call(m_assembler.call(target), Call::None);
2457 void call(Address address)
2459 m_assembler.call_m(address.offset, address.base);
2467 void compare8(RelationalCondition cond, Address left, TrustedImm32 right, RegisterID dest)
2469 TrustedImm32 right8(static_cast<int8_t>(right.m_value));
2470 m_assembler.cmpb_im(right8.m_value, left.offset, left.base);
2471 set32(x86Condition(cond), dest);
2474 void compare32(RelationalCondition cond, RegisterID left, RegisterID right, RegisterID dest)
2476 m_assembler.cmpl_rr(right, left);
2477 set32(x86Condition(cond), dest);
2480 void compare32(RelationalCondition cond, RegisterID left, TrustedImm32 right, RegisterID dest)
2482 if (!right.m_value) {
2483 if (auto resultCondition = commuteCompareToZeroIntoTest(cond)) {
2484 test32(*resultCondition, left, left, dest);
2489 m_assembler.cmpl_ir(right.m_value, left);
2490 set32(x86Condition(cond), dest);
2494 // The mask should be optional... perhaps the argument order should be
2495 // dest-src, operations always have a dest? ... possibly not true, considering
2496 // asm ops like test, or pseudo ops like pop().
2498 void test8(ResultCondition cond, Address address, TrustedImm32 mask, RegisterID dest)
2500 TrustedImm32 mask8(static_cast<int8_t>(mask.m_value));
2501 if (mask8.m_value == -1)
2502 m_assembler.cmpb_im(0, address.offset, address.base);
2504 m_assembler.testb_im(mask8.m_value, address.offset, address.base);
2505 set32(x86Condition(cond), dest);
2508 void test32(ResultCondition cond, Address address, TrustedImm32 mask, RegisterID dest)
2510 generateTest32(address, mask);
2511 set32(x86Condition(cond), dest);
2514 void test32(ResultCondition cond, RegisterID reg, RegisterID mask, RegisterID dest)
2516 m_assembler.testl_rr(reg, mask);
2517 set32(x86Condition(cond), dest);
2520 void test32(ResultCondition cond, RegisterID reg, TrustedImm32 mask, RegisterID dest)
2523 set32(x86Condition(cond), dest);
2526 void setCarry(RegisterID dest)
2528 set32(X86Assembler::ConditionC, dest);
2531 // Invert a relational condition, e.g. == becomes !=, < becomes >=, etc.
2532 static RelationalCondition invert(RelationalCondition cond)
2534 return static_cast<RelationalCondition>(cond ^ 1);
2537 static DoubleCondition invert(DoubleCondition cond)
2541 return DoubleNotEqualOrUnordered;
2542 case DoubleNotEqual:
2543 return DoubleEqualOrUnordered;
2544 case DoubleGreaterThan:
2545 return DoubleLessThanOrEqualOrUnordered;
2546 case DoubleGreaterThanOrEqual:
2547 return DoubleLessThanOrUnordered;
2548 case DoubleLessThan:
2549 return DoubleGreaterThanOrEqualOrUnordered;
2550 case DoubleLessThanOrEqual:
2551 return DoubleGreaterThanOrUnordered;
2552 case DoubleEqualOrUnordered:
2553 return DoubleNotEqual;
2554 case DoubleNotEqualOrUnordered:
2556 case DoubleGreaterThanOrUnordered:
2557 return DoubleLessThanOrEqual;
2558 case DoubleGreaterThanOrEqualOrUnordered:
2559 return DoubleLessThan;
2560 case DoubleLessThanOrUnordered:
2561 return DoubleGreaterThanOrEqual;
2562 case DoubleLessThanOrEqualOrUnordered:
2563 return DoubleGreaterThan;
2565 RELEASE_ASSERT_NOT_REACHED();
2566 return DoubleEqual; // make compiler happy
2569 static bool isInvertible(ResultCondition cond)
2575 case PositiveOrZero:
2582 static ResultCondition invert(ResultCondition cond)
2590 return PositiveOrZero;
2591 case PositiveOrZero:
2594 RELEASE_ASSERT_NOT_REACHED();
2595 return Zero; // Make compiler happy for release builds.
2599 static Optional<ResultCondition> commuteCompareToZeroIntoTest(RelationalCondition cond)
2608 case GreaterThanOrEqual:
2609 return PositiveOrZero;
2623 m_assembler.mfence();
2626 static void replaceWithJump(CodeLocationLabel instructionStart, CodeLocationLabel destination)
2628 X86Assembler::replaceWithJump(instructionStart.executableAddress(), destination.executableAddress());
2631 static ptrdiff_t maxJumpReplacementSize()
2633 return X86Assembler::maxJumpReplacementSize();
2636 static bool supportsFloatingPointRounding()
2638 if (s_sse4_1CheckState == CPUIDCheckState::NotChecked)
2639 updateEax1EcxFlags();
2640 return s_sse4_1CheckState == CPUIDCheckState::Set;
2643 static bool supportsAVX()
2645 // AVX still causes mysterious regressions and those regressions can be massive.
2649 static void updateEax1EcxFlags()
2654 __cpuid(cpuInfo, 0x1);
2656 #elif COMPILER(GCC_OR_CLANG)
2664 : "%eax", "%ebx", "%ecx", "%edx"
2675 : "%eax", "%ecx", "%edx"
2678 #endif // COMPILER(GCC_OR_CLANG)
2679 s_sse4_1CheckState = (flags & (1 << 19)) ? CPUIDCheckState::Set : CPUIDCheckState::Clear;
2680 s_avxCheckState = (flags & (1 << 28)) ? CPUIDCheckState::Set : CPUIDCheckState::Clear;
2683 #if ENABLE(MASM_PROBE)
2684 void probe(ProbeFunction, void* arg1, void* arg2);
2685 #endif // ENABLE(MASM_PROBE)
2688 X86Assembler::Condition x86Condition(RelationalCondition cond)
2690 return static_cast<X86Assembler::Condition>(cond);
2693 X86Assembler::Condition x86Condition(ResultCondition cond)
2695 return static_cast<X86Assembler::Condition>(cond);
2698 void set32(X86Assembler::Condition cond, RegisterID dest)
2701 // On 32-bit x86 we can only set the first 4 registers;
2702 // esp..edi are mapped to the 'h' registers!
2704 m_assembler.xchgl_rr(dest, X86Registers::eax);
2705 m_assembler.setCC_r(cond, X86Registers::eax);
2706 m_assembler.movzbl_rr(X86Registers::eax, X86Registers::eax);
2707 m_assembler.xchgl_rr(dest, X86Registers::eax);
2711 m_assembler.setCC_r(cond, dest);
2712 m_assembler.movzbl_rr(dest, dest);
2715 void cmov(X86Assembler::Condition cond, RegisterID src, RegisterID dest)
2718 m_assembler.cmovq_rr(cond, src, dest);
2720 m_assembler.cmovl_rr(cond, src, dest);
2724 static bool supportsLZCNT()
2726 if (s_lzcntCheckState == CPUIDCheckState::NotChecked) {
2730 __cpuid(cpuInfo, 0x80000001);
2732 #elif COMPILER(GCC_OR_CLANG)
2735 "movl $0x80000001, %%eax;"
2740 : "%eax", "%ebx", "%ecx", "%edx"
2744 "movl $0x80000001, %%eax;"
2751 : "%eax", "%ecx", "%edx"
2754 #endif // COMPILER(GCC_OR_CLANG)
2755 s_lzcntCheckState = (flags & 0x20) ? CPUIDCheckState::Set : CPUIDCheckState::Clear;
2757 return s_lzcntCheckState == CPUIDCheckState::Set;
2761 // Only MacroAssemblerX86 should be using the following method; SSE2 is always available on
2762 // x86_64, and clients & subclasses of MacroAssembler should be using 'supportsFloatingPoint()'.
2763 friend class MacroAssemblerX86;
2765 ALWAYS_INLINE void generateTest32(Address address, TrustedImm32 mask = TrustedImm32(-1))
2767 if (mask.m_value == -1)
2768 m_assembler.cmpl_im(0, address.offset, address.base);
2769 else if (!(mask.m_value & ~0xff))
2770 m_assembler.testb_im(mask.m_value, address.offset, address.base);
2771 else if (!(mask.m_value & ~0xff00))
2772 m_assembler.testb_im(mask.m_value >> 8, address.offset + 1, address.base);
2773 else if (!(mask.m_value & ~0xff0000))
2774 m_assembler.testb_im(mask.m_value >> 16, address.offset + 2, address.base);
2775 else if (!(mask.m_value & ~0xff000000))
2776 m_assembler.testb_im(mask.m_value >> 24, address.offset + 3, address.base);
2778 m_assembler.testl_i32m(mask.m_value, address.offset, address.base);
2781 // If lzcnt is not available, use this after BSR
2782 // to count the leading zeros.
2783 void clz32AfterBsr(RegisterID dst)
2785 Jump srcIsNonZero = m_assembler.jCC(x86Condition(NonZero));
2786 move(TrustedImm32(32), dst);
2788 Jump skipNonZeroCase = jump();
2789 srcIsNonZero.link(this);
2790 xor32(TrustedImm32(0x1f), dst);
2791 skipNonZeroCase.link(this);
2794 Jump jumpAfterFloatingPointCompare(DoubleCondition cond, FPRegisterID left, FPRegisterID right)
2796 if (cond == DoubleEqual) {
2798 return Jump(m_assembler.jnp());
2799 Jump isUnordered(m_assembler.jp());
2800 Jump result = Jump(m_assembler.je());
2801 isUnordered.link(this);
2804 if (cond == DoubleNotEqualOrUnordered) {
2806 return Jump(m_assembler.jp());
2807 Jump isUnordered(m_assembler.jp());
2808 Jump isEqual(m_assembler.je());
2809 isUnordered.link(this);
2810 Jump result = jump();
2815 ASSERT(!(cond & DoubleConditionBitSpecial));
2816 return Jump(m_assembler.jCC(static_cast<X86Assembler::Condition>(cond & ~DoubleConditionBits)));
2819 // The 32bit Move does not need the REX byte for low registers, making it shorter.
2820 // Use this if the top bits are irrelevant because they will be reset by the next instruction.
2821 void move32IfNeeded(RegisterID src, RegisterID dest)
2825 m_assembler.movl_rr(src, dest);
2829 void moveConditionallyAfterFloatingPointCompare(DoubleCondition cond, FPRegisterID left, FPRegisterID right, RegisterID src, RegisterID dest)
2831 if (cond == DoubleEqual) {
2832 if (left == right) {
2833 m_assembler.cmovnpq_rr(src, dest);
2837 Jump isUnordered(m_assembler.jp());
2838 m_assembler.cmoveq_rr(src, dest);
2839 isUnordered.link(this);
2843 if (cond == DoubleNotEqualOrUnordered) {
2844 if (left == right) {
2845 m_assembler.cmovpq_rr(src, dest);
2849 m_assembler.cmovpq_rr(src, dest);
2850 m_assembler.cmovneq_rr(src, dest);
2854 ASSERT(!(cond & DoubleConditionBitSpecial));
2855 cmov(static_cast<X86Assembler::Condition>(cond & ~DoubleConditionBits), src, dest);
2862 // All X86 Macs are guaranteed to support at least SSE2,
2863 static bool isSSE2Present()
2868 #else // OS(MAC_OS_X)
2870 enum SSE2CheckState {
2876 static bool isSSE2Present()
2878 if (s_sse2CheckState == NotCheckedSSE2) {
2879 // Default the flags value to zero; if the compiler is
2880 // not MSVC or GCC we will read this as SSE2 not present.
2884 mov eax, 1 // cpuid function 1 gives us the standard feature set
2888 #elif COMPILER(GCC_OR_CLANG)
2897 : "%eax", "%ecx", "%edx"
2900 static const int SSE2FeatureBit = 1 << 26;
2901 s_sse2CheckState = (flags & SSE2FeatureBit) ? HasSSE2 : NoSSE2;
2904 ASSERT(s_sse2CheckState != NotCheckedSSE2);
2906 return s_sse2CheckState == HasSSE2;
2909 static SSE2CheckState s_sse2CheckState;
2911 #endif // OS(MAC_OS_X)
2912 #elif !defined(NDEBUG) // CPU(X86)
2914 // On x86-64 we should never be checking for SSE2 in a non-debug build,
2915 // but non debug add this method to keep the asserts above happy.
2916 static bool isSSE2Present()
2923 enum class CPUIDCheckState {
2928 JS_EXPORT_PRIVATE static CPUIDCheckState s_sse4_1CheckState;
2929 JS_EXPORT_PRIVATE static CPUIDCheckState s_avxCheckState;
2930 static CPUIDCheckState s_lzcntCheckState;
2935 #endif // ENABLE(ASSEMBLER)
2937 #endif // MacroAssemblerX86Common_h