summaryrefslogtreecommitdiff
path: root/Source/JavaScriptCore/assembler/MacroAssemblerX86Common.h
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@lorry>2017-06-27 06:07:23 +0000
committerLorry Tar Creator <lorry-tar-importer@lorry>2017-06-27 06:07:23 +0000
commit1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch)
tree46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/JavaScriptCore/assembler/MacroAssemblerX86Common.h
parent32761a6cee1d0dee366b885b7b9c777e67885688 (diff)
downloadWebKitGtk-tarball-master.tar.gz
Diffstat (limited to 'Source/JavaScriptCore/assembler/MacroAssemblerX86Common.h')
-rw-r--r--Source/JavaScriptCore/assembler/MacroAssemblerX86Common.h1823
1 files changed, 1659 insertions, 164 deletions
diff --git a/Source/JavaScriptCore/assembler/MacroAssemblerX86Common.h b/Source/JavaScriptCore/assembler/MacroAssemblerX86Common.h
index ac09eaca4..695e640f0 100644
--- a/Source/JavaScriptCore/assembler/MacroAssemblerX86Common.h
+++ b/Source/JavaScriptCore/assembler/MacroAssemblerX86Common.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2008, 2014-2017 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -23,22 +23,35 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef MacroAssemblerX86Common_h
-#define MacroAssemblerX86Common_h
+#pragma once
#if ENABLE(ASSEMBLER)
#include "X86Assembler.h"
#include "AbstractMacroAssembler.h"
+#include <wtf/Optional.h>
+
+#if COMPILER(MSVC)
+#include <intrin.h>
+#endif
namespace JSC {
-class MacroAssemblerX86Common : public AbstractMacroAssembler<X86Assembler> {
+class MacroAssemblerX86Common : public AbstractMacroAssembler<X86Assembler, MacroAssemblerX86Common> {
public:
#if CPU(X86_64)
- static const X86Registers::RegisterID scratchRegister = X86Registers::r11;
-#endif
+ // Use this directly only if you're not generating code with it.
+ static const X86Registers::RegisterID s_scratchRegister = X86Registers::r11;
+ // Use this when generating code so that we get enforcement of the disallowing of scratch register
+ // usage.
+ X86Registers::RegisterID scratchRegister()
+ {
+ RELEASE_ASSERT(m_allowScratchRegister);
+ return s_scratchRegister;
+ }
+#endif
+
protected:
static const int DoubleConditionBitInvert = 0x10;
static const int DoubleConditionBitSpecial = 0x20;
@@ -73,6 +86,7 @@ public:
NonZero = X86Assembler::ConditionNE
};
+ // FIXME: it would be neat to rename this to FloatingPointCondition in every assembler.
enum DoubleCondition {
// These conditions will only evaluate to true if the comparison is ordered - i.e. neither operand is NaN.
DoubleEqual = X86Assembler::ConditionE | DoubleConditionBitSpecial,
@@ -117,6 +131,33 @@ public:
m_assembler.addl_im(imm.m_value, address.offset, address.base);
}
+ void add32(TrustedImm32 imm, BaseIndex address)
+ {
+ m_assembler.addl_im(imm.m_value, address.offset, address.base, address.index, address.scale);
+ }
+
+ void add8(TrustedImm32 imm, Address address)
+ {
+ TrustedImm32 imm8(static_cast<int8_t>(imm.m_value));
+ m_assembler.addb_im(imm8.m_value, address.offset, address.base);
+ }
+
+ void add8(TrustedImm32 imm, BaseIndex address)
+ {
+ TrustedImm32 imm8(static_cast<int8_t>(imm.m_value));
+ m_assembler.addb_im(imm8.m_value, address.offset, address.base, address.index, address.scale);
+ }
+
+ void add16(TrustedImm32 imm, Address address)
+ {
+ m_assembler.addw_im(imm.m_value, address.offset, address.base);
+ }
+
+ void add16(TrustedImm32 imm, BaseIndex address)
+ {
+ m_assembler.addw_im(imm.m_value, address.offset, address.base, address.index, address.scale);
+ }
+
void add32(TrustedImm32 imm, RegisterID dest)
{
if (imm.m_value == 1)
@@ -135,11 +176,66 @@ public:
m_assembler.addl_rm(src, dest.offset, dest.base);
}
+ void add32(RegisterID src, BaseIndex dest)
+ {
+ m_assembler.addl_rm(src, dest.offset, dest.base, dest.index, dest.scale);
+ }
+
+ void add8(RegisterID src, Address dest)
+ {
+ m_assembler.addb_rm(src, dest.offset, dest.base);
+ }
+
+ void add8(RegisterID src, BaseIndex dest)
+ {
+ m_assembler.addb_rm(src, dest.offset, dest.base, dest.index, dest.scale);
+ }
+
+ void add16(RegisterID src, Address dest)
+ {
+ m_assembler.addw_rm(src, dest.offset, dest.base);
+ }
+
+ void add16(RegisterID src, BaseIndex dest)
+ {
+ m_assembler.addw_rm(src, dest.offset, dest.base, dest.index, dest.scale);
+ }
+
void add32(TrustedImm32 imm, RegisterID src, RegisterID dest)
{
+ if (!imm.m_value) {
+ zeroExtend32ToPtr(src, dest);
+ return;
+ }
+
+ if (src == dest) {
+ add32(imm, dest);
+ return;
+ }
+
m_assembler.leal_mr(imm.m_value, src, dest);
}
-
+
+ void add32(RegisterID a, RegisterID b, RegisterID dest)
+ {
+ x86Lea32(BaseIndex(a, b, TimesOne), dest);
+ }
+
+ void x86Lea32(BaseIndex index, RegisterID dest)
+ {
+ if (!index.scale && !index.offset) {
+ if (index.base == dest) {
+ add32(index.index, dest);
+ return;
+ }
+ if (index.index == dest) {
+ add32(index.base, dest);
+ return;
+ }
+ }
+ m_assembler.leal_mr(index.offset, index.base, index.index, index.scale, dest);
+ }
+
void and32(RegisterID src, RegisterID dest)
{
m_assembler.andl_rr(src, dest);
@@ -172,24 +268,77 @@ public:
else if (op1 == dest)
and32(op2, dest);
else {
- move(op2, dest);
+ move32IfNeeded(op2, dest);
and32(op1, dest);
}
}
+ void and32(Address op1, RegisterID op2, RegisterID dest)
+ {
+ if (op2 == dest)
+ and32(op1, dest);
+ else if (op1.base == dest) {
+ load32(op1, dest);
+ and32(op2, dest);
+ } else {
+ zeroExtend32ToPtr(op2, dest);
+ and32(op1, dest);
+ }
+ }
+
+ void and32(RegisterID op1, Address op2, RegisterID dest)
+ {
+ and32(op2, op1, dest);
+ }
+
void and32(TrustedImm32 imm, RegisterID src, RegisterID dest)
{
- move(src, dest);
+ move32IfNeeded(src, dest);
and32(imm, dest);
}
- void lshift32(RegisterID shift_amount, RegisterID dest)
+ void countLeadingZeros32(RegisterID src, RegisterID dst)
{
- ASSERT(shift_amount != dest);
+ if (supportsLZCNT()) {
+ m_assembler.lzcnt_rr(src, dst);
+ return;
+ }
+ m_assembler.bsr_rr(src, dst);
+ clz32AfterBsr(dst);
+ }
+
+ void countLeadingZeros32(Address src, RegisterID dst)
+ {
+ if (supportsLZCNT()) {
+ m_assembler.lzcnt_mr(src.offset, src.base, dst);
+ return;
+ }
+ m_assembler.bsr_mr(src.offset, src.base, dst);
+ clz32AfterBsr(dst);
+ }
+
+ void countTrailingZeros32(RegisterID src, RegisterID dst)
+ {
+ if (supportsBMI1()) {
+ m_assembler.tzcnt_rr(src, dst);
+ return;
+ }
+ m_assembler.bsf_rr(src, dst);
+ ctzAfterBsf<32>(dst);
+ }
+ // Only used for testing purposes.
+ void illegalInstruction()
+ {
+ m_assembler.illegalInstruction();
+ }
+
+ void lshift32(RegisterID shift_amount, RegisterID dest)
+ {
if (shift_amount == X86Registers::ecx)
m_assembler.shll_CLr(dest);
else {
+ ASSERT(shift_amount != dest);
// On x86 we can only shift by ecx; if asked to shift by another register we'll
// need rejig the shift amount into ecx first, and restore the registers afterwards.
// If we dest is ecx, then shift the swapped register!
@@ -203,8 +352,7 @@ public:
{
ASSERT(shift_amount != dest);
- if (src != dest)
- move(src, dest);
+ move32IfNeeded(src, dest);
lshift32(shift_amount, dest);
}
@@ -215,8 +363,7 @@ public:
void lshift32(RegisterID src, TrustedImm32 imm, RegisterID dest)
{
- if (src != dest)
- move(src, dest);
+ move32IfNeeded(src, dest);
lshift32(imm, dest);
}
@@ -225,16 +372,80 @@ public:
m_assembler.imull_rr(src, dest);
}
+ void mul32(RegisterID src1, RegisterID src2, RegisterID dest)
+ {
+ if (src2 == dest) {
+ m_assembler.imull_rr(src1, dest);
+ return;
+ }
+ move32IfNeeded(src1, dest);
+ m_assembler.imull_rr(src2, dest);
+ }
+
void mul32(Address src, RegisterID dest)
{
m_assembler.imull_mr(src.offset, src.base, dest);
}
+
+ void mul32(Address op1, RegisterID op2, RegisterID dest)
+ {
+ if (op2 == dest)
+ mul32(op1, dest);
+ else if (op1.base == dest) {
+ load32(op1, dest);
+ mul32(op2, dest);
+ } else {
+ zeroExtend32ToPtr(op2, dest);
+ mul32(op1, dest);
+ }
+ }
+
+ void mul32(RegisterID src1, Address src2, RegisterID dest)
+ {
+ mul32(src2, src1, dest);
+ }
void mul32(TrustedImm32 imm, RegisterID src, RegisterID dest)
{
m_assembler.imull_i32r(src, imm.m_value, dest);
}
+ void x86ConvertToDoubleWord32()
+ {
+ m_assembler.cdq();
+ }
+
+ void x86ConvertToDoubleWord32(RegisterID eax, RegisterID edx)
+ {
+ ASSERT_UNUSED(eax, eax == X86Registers::eax);
+ ASSERT_UNUSED(edx, edx == X86Registers::edx);
+ x86ConvertToDoubleWord32();
+ }
+
+ void x86Div32(RegisterID denominator)
+ {
+ m_assembler.idivl_r(denominator);
+ }
+
+ void x86Div32(RegisterID eax, RegisterID edx, RegisterID denominator)
+ {
+ ASSERT_UNUSED(eax, eax == X86Registers::eax);
+ ASSERT_UNUSED(edx, edx == X86Registers::edx);
+ x86Div32(denominator);
+ }
+
+ void x86UDiv32(RegisterID denominator)
+ {
+ m_assembler.divl_r(denominator);
+ }
+
+ void x86UDiv32(RegisterID eax, RegisterID edx, RegisterID denominator)
+ {
+ ASSERT_UNUSED(eax, eax == X86Registers::eax);
+ ASSERT_UNUSED(edx, edx == X86Registers::edx);
+ x86UDiv32(denominator);
+ }
+
void neg32(RegisterID srcDest)
{
m_assembler.negl_r(srcDest);
@@ -277,24 +488,42 @@ public:
else if (op1 == dest)
or32(op2, dest);
else {
- move(op2, dest);
+ move32IfNeeded(op2, dest);
or32(op1, dest);
}
}
+ void or32(Address op1, RegisterID op2, RegisterID dest)
+ {
+ if (op2 == dest)
+ or32(op1, dest);
+ else if (op1.base == dest) {
+ load32(op1, dest);
+ or32(op2, dest);
+ } else {
+ zeroExtend32ToPtr(op2, dest);
+ or32(op1, dest);
+ }
+ }
+
+ void or32(RegisterID op1, Address op2, RegisterID dest)
+ {
+ or32(op2, op1, dest);
+ }
+
void or32(TrustedImm32 imm, RegisterID src, RegisterID dest)
{
- move(src, dest);
+ move32IfNeeded(src, dest);
or32(imm, dest);
}
void rshift32(RegisterID shift_amount, RegisterID dest)
{
- ASSERT(shift_amount != dest);
-
if (shift_amount == X86Registers::ecx)
m_assembler.sarl_CLr(dest);
else {
+ ASSERT(shift_amount != dest);
+
// On x86 we can only shift by ecx; if asked to shift by another register we'll
// need rejig the shift amount into ecx first, and restore the registers afterwards.
// If we dest is ecx, then shift the swapped register!
@@ -308,8 +537,7 @@ public:
{
ASSERT(shift_amount != dest);
- if (src != dest)
- move(src, dest);
+ move32IfNeeded(src, dest);
rshift32(shift_amount, dest);
}
@@ -320,18 +548,17 @@ public:
void rshift32(RegisterID src, TrustedImm32 imm, RegisterID dest)
{
- if (src != dest)
- move(src, dest);
+ move32IfNeeded(src, dest);
rshift32(imm, dest);
}
void urshift32(RegisterID shift_amount, RegisterID dest)
{
- ASSERT(shift_amount != dest);
-
if (shift_amount == X86Registers::ecx)
m_assembler.shrl_CLr(dest);
else {
+ ASSERT(shift_amount != dest);
+
// On x86 we can only shift by ecx; if asked to shift by another register we'll
// need rejig the shift amount into ecx first, and restore the registers afterwards.
// If we dest is ecx, then shift the swapped register!
@@ -345,8 +572,7 @@ public:
{
ASSERT(shift_amount != dest);
- if (src != dest)
- move(src, dest);
+ move32IfNeeded(src, dest);
urshift32(shift_amount, dest);
}
@@ -357,16 +583,64 @@ public:
void urshift32(RegisterID src, TrustedImm32 imm, RegisterID dest)
{
- if (src != dest)
- move(src, dest);
+ move32IfNeeded(src, dest);
urshift32(imm, dest);
}
-
+
+ void rotateRight32(TrustedImm32 imm, RegisterID dest)
+ {
+ m_assembler.rorl_i8r(imm.m_value, dest);
+ }
+
+ void rotateRight32(RegisterID src, RegisterID dest)
+ {
+ if (src == X86Registers::ecx)
+ m_assembler.rorl_CLr(dest);
+ else {
+ ASSERT(src != dest);
+
+ // Can only rotate by ecx, so we do some swapping if we see anything else.
+ swap(src, X86Registers::ecx);
+ m_assembler.rorl_CLr(dest == X86Registers::ecx ? src : dest);
+ swap(src, X86Registers::ecx);
+ }
+ }
+
+ void rotateLeft32(TrustedImm32 imm, RegisterID dest)
+ {
+ m_assembler.roll_i8r(imm.m_value, dest);
+ }
+
+ void rotateLeft32(RegisterID src, RegisterID dest)
+ {
+ if (src == X86Registers::ecx)
+ m_assembler.roll_CLr(dest);
+ else {
+ ASSERT(src != dest);
+
+ // Can only rotate by ecx, so we do some swapping if we see anything else.
+ swap(src, X86Registers::ecx);
+ m_assembler.roll_CLr(dest == X86Registers::ecx ? src : dest);
+ swap(src, X86Registers::ecx);
+ }
+ }
+
void sub32(RegisterID src, RegisterID dest)
{
m_assembler.subl_rr(src, dest);
}
-
+
+ void sub32(RegisterID left, RegisterID right, RegisterID dest)
+ {
+ if (dest == right) {
+ neg32(dest);
+ add32(left, dest);
+ return;
+ }
+ move(left, dest);
+ sub32(right, dest);
+ }
+
void sub32(TrustedImm32 imm, RegisterID dest)
{
if (imm.m_value == 1)
@@ -406,9 +680,9 @@ public:
void xor32(TrustedImm32 imm, RegisterID dest)
{
if (imm.m_value == -1)
- m_assembler.notl_r(dest);
+ m_assembler.notl_r(dest);
else
- m_assembler.xorl_ir(imm.m_value, dest);
+ m_assembler.xorl_ir(imm.m_value, dest);
}
void xor32(RegisterID src, Address dest)
@@ -428,27 +702,70 @@ public:
else if (op1 == dest)
xor32(op2, dest);
else {
- move(op2, dest);
+ move32IfNeeded(op2, dest);
+ xor32(op1, dest);
+ }
+ }
+
+ void xor32(Address op1, RegisterID op2, RegisterID dest)
+ {
+ if (op2 == dest)
+ xor32(op1, dest);
+ else if (op1.base == dest) {
+ load32(op1, dest);
+ xor32(op2, dest);
+ } else {
+ zeroExtend32ToPtr(op2, dest);
xor32(op1, dest);
}
}
+ void xor32(RegisterID op1, Address op2, RegisterID dest)
+ {
+ xor32(op2, op1, dest);
+ }
+
void xor32(TrustedImm32 imm, RegisterID src, RegisterID dest)
{
- move(src, dest);
+ move32IfNeeded(src, dest);
xor32(imm, dest);
}
+ void not32(RegisterID srcDest)
+ {
+ m_assembler.notl_r(srcDest);
+ }
+
+ void not32(Address dest)
+ {
+ m_assembler.notl_m(dest.offset, dest.base);
+ }
+
void sqrtDouble(FPRegisterID src, FPRegisterID dst)
{
m_assembler.sqrtsd_rr(src, dst);
}
+ void sqrtDouble(Address src, FPRegisterID dst)
+ {
+ m_assembler.sqrtsd_mr(src.offset, src.base, dst);
+ }
+
+ void sqrtFloat(FPRegisterID src, FPRegisterID dst)
+ {
+ m_assembler.sqrtss_rr(src, dst);
+ }
+
+ void sqrtFloat(Address src, FPRegisterID dst)
+ {
+ m_assembler.sqrtss_mr(src.offset, src.base, dst);
+ }
+
void absDouble(FPRegisterID src, FPRegisterID dst)
{
ASSERT(src != dst);
static const double negativeZeroConstant = -0.0;
- loadDouble(&negativeZeroConstant, dst);
+ loadDouble(TrustedImmPtr(&negativeZeroConstant), dst);
m_assembler.andnpd_rr(src, dst);
}
@@ -456,10 +773,79 @@ public:
{
ASSERT(src != dst);
static const double negativeZeroConstant = -0.0;
- loadDouble(&negativeZeroConstant, dst);
+ loadDouble(TrustedImmPtr(&negativeZeroConstant), dst);
m_assembler.xorpd_rr(src, dst);
}
+ void ceilDouble(FPRegisterID src, FPRegisterID dst)
+ {
+ m_assembler.roundsd_rr(src, dst, X86Assembler::RoundingType::TowardInfiniti);
+ }
+
+ void ceilDouble(Address src, FPRegisterID dst)
+ {
+ m_assembler.roundsd_mr(src.offset, src.base, dst, X86Assembler::RoundingType::TowardInfiniti);
+ }
+
+ void ceilFloat(FPRegisterID src, FPRegisterID dst)
+ {
+ m_assembler.roundss_rr(src, dst, X86Assembler::RoundingType::TowardInfiniti);
+ }
+
+ void ceilFloat(Address src, FPRegisterID dst)
+ {
+ m_assembler.roundss_mr(src.offset, src.base, dst, X86Assembler::RoundingType::TowardInfiniti);
+ }
+
+ void floorDouble(FPRegisterID src, FPRegisterID dst)
+ {
+ m_assembler.roundsd_rr(src, dst, X86Assembler::RoundingType::TowardNegativeInfiniti);
+ }
+
+ void floorDouble(Address src, FPRegisterID dst)
+ {
+ m_assembler.roundsd_mr(src.offset, src.base, dst, X86Assembler::RoundingType::TowardNegativeInfiniti);
+ }
+
+ void floorFloat(FPRegisterID src, FPRegisterID dst)
+ {
+ m_assembler.roundss_rr(src, dst, X86Assembler::RoundingType::TowardNegativeInfiniti);
+ }
+
+ void floorFloat(Address src, FPRegisterID dst)
+ {
+ m_assembler.roundss_mr(src.offset, src.base, dst, X86Assembler::RoundingType::TowardNegativeInfiniti);
+ }
+
+ void roundTowardNearestIntDouble(FPRegisterID src, FPRegisterID dst)
+ {
+ m_assembler.roundsd_rr(src, dst, X86Assembler::RoundingType::ToNearestWithTiesToEven);
+ }
+
+ void roundTowardNearestIntFloat(FPRegisterID src, FPRegisterID dst)
+ {
+ m_assembler.roundss_rr(src, dst, X86Assembler::RoundingType::ToNearestWithTiesToEven);
+ }
+
+ void roundTowardZeroDouble(FPRegisterID src, FPRegisterID dst)
+ {
+ m_assembler.roundsd_rr(src, dst, X86Assembler::RoundingType::TowardZero);
+ }
+
+ void roundTowardZeroDouble(Address src, FPRegisterID dst)
+ {
+ m_assembler.roundsd_mr(src.offset, src.base, dst, X86Assembler::RoundingType::TowardZero);
+ }
+
+ void roundTowardZeroFloat(FPRegisterID src, FPRegisterID dst)
+ {
+ m_assembler.roundss_rr(src, dst, X86Assembler::RoundingType::TowardZero);
+ }
+
+ void roundTowardZeroFloat(Address src, FPRegisterID dst)
+ {
+ m_assembler.roundss_mr(src.offset, src.base, dst, X86Assembler::RoundingType::TowardZero);
+ }
// Memory access operations:
//
@@ -525,15 +911,25 @@ public:
m_assembler.movzbl_mr(address.offset, address.base, dest);
}
- void load8Signed(BaseIndex address, RegisterID dest)
+ void load8SignedExtendTo32(BaseIndex address, RegisterID dest)
{
m_assembler.movsbl_mr(address.offset, address.base, address.index, address.scale, dest);
}
- void load8Signed(ImplicitAddress address, RegisterID dest)
+ void load8SignedExtendTo32(ImplicitAddress address, RegisterID dest)
{
m_assembler.movsbl_mr(address.offset, address.base, dest);
}
+
+ void zeroExtend8To32(RegisterID src, RegisterID dest)
+ {
+ m_assembler.movzbl_rr(src, dest);
+ }
+
+ void signExtend8To32(RegisterID src, RegisterID dest)
+ {
+ m_assembler.movsbl_rr(src, dest);
+ }
void load16(BaseIndex address, RegisterID dest)
{
@@ -545,16 +941,26 @@ public:
m_assembler.movzwl_mr(address.offset, address.base, dest);
}
- void load16Signed(BaseIndex address, RegisterID dest)
+ void load16SignedExtendTo32(BaseIndex address, RegisterID dest)
{
m_assembler.movswl_mr(address.offset, address.base, address.index, address.scale, dest);
}
- void load16Signed(Address address, RegisterID dest)
+ void load16SignedExtendTo32(Address address, RegisterID dest)
{
m_assembler.movswl_mr(address.offset, address.base, dest);
}
+ void zeroExtend16To32(RegisterID src, RegisterID dest)
+ {
+ m_assembler.movzwl_rr(src, dest);
+ }
+
+ void signExtend16To32(RegisterID src, RegisterID dest)
+ {
+ m_assembler.movswl_rr(src, dest);
+ }
+
DataLabel32 store32WithAddressOffsetPatch(RegisterID src, Address address)
{
padBeforePatch();
@@ -582,16 +988,26 @@ public:
m_assembler.movl_i32m(imm.m_value, address.offset, address.base, address.index, address.scale);
}
+ void storeZero32(ImplicitAddress address)
+ {
+ store32(TrustedImm32(0), address);
+ }
+
+ void storeZero32(BaseIndex address)
+ {
+ store32(TrustedImm32(0), address);
+ }
+
void store8(TrustedImm32 imm, Address address)
{
- ASSERT(-128 <= imm.m_value && imm.m_value < 128);
- m_assembler.movb_i8m(imm.m_value, address.offset, address.base);
+ TrustedImm32 imm8(static_cast<int8_t>(imm.m_value));
+ m_assembler.movb_i8m(imm8.m_value, address.offset, address.base);
}
void store8(TrustedImm32 imm, BaseIndex address)
{
- ASSERT(-128 <= imm.m_value && imm.m_value < 128);
- m_assembler.movb_i8m(imm.m_value, address.offset, address.base, address.index, address.scale);
+ TrustedImm32 imm8(static_cast<int8_t>(imm.m_value));
+ m_assembler.movb_i8m(imm8.m_value, address.offset, address.base, address.index, address.scale);
}
static ALWAYS_INLINE RegisterID getUnusedRegister(BaseIndex address)
@@ -672,6 +1088,25 @@ public:
m_assembler.movw_rm(src, address.offset, address.base, address.index, address.scale);
}
+ void store16(RegisterID src, Address address)
+ {
+#if CPU(X86)
+ // On 32-bit x86 we can only store from the first 4 registers;
+ // esp..edi are mapped to the 'h' registers!
+ if (src >= 4) {
+ // Pick a temporary register.
+ RegisterID temp = getUnusedRegister(address);
+
+ // Swap to the temporary register to perform the store.
+ swap(src, temp);
+ m_assembler.movw_rm(temp, address.offset, address.base);
+ swap(src, temp);
+ return;
+ }
+#endif
+ m_assembler.movw_rm(src, address.offset, address.base);
+ }
+
// Floating-point operation:
//
@@ -681,17 +1116,17 @@ public:
{
ASSERT(isSSE2Present());
if (src != dest)
- m_assembler.movsd_rr(src, dest);
+ m_assembler.movaps_rr(src, dest);
}
- void loadDouble(const void* address, FPRegisterID dest)
+ void loadDouble(TrustedImmPtr address, FPRegisterID dest)
{
#if CPU(X86)
ASSERT(isSSE2Present());
- m_assembler.movsd_mr(address, dest);
+ m_assembler.movsd_mr(address.m_value, dest);
#else
- move(TrustedImmPtr(address), scratchRegister);
- loadDouble(scratchRegister, dest);
+ move(address, scratchRegister());
+ loadDouble(scratchRegister(), dest);
#endif
}
@@ -700,12 +1135,19 @@ public:
ASSERT(isSSE2Present());
m_assembler.movsd_mr(address.offset, address.base, dest);
}
-
+
void loadDouble(BaseIndex address, FPRegisterID dest)
{
ASSERT(isSSE2Present());
m_assembler.movsd_mr(address.offset, address.base, address.index, address.scale, dest);
}
+
+ void loadFloat(ImplicitAddress address, FPRegisterID dest)
+ {
+ ASSERT(isSSE2Present());
+ m_assembler.movss_mr(address.offset, address.base, dest);
+ }
+
void loadFloat(BaseIndex address, FPRegisterID dest)
{
ASSERT(isSSE2Present());
@@ -723,7 +1165,13 @@ public:
ASSERT(isSSE2Present());
m_assembler.movsd_rm(src, address.offset, address.base, address.index, address.scale);
}
-
+
+ void storeFloat(FPRegisterID src, ImplicitAddress address)
+ {
+ ASSERT(isSSE2Present());
+ m_assembler.movss_rm(src, address.offset, address.base);
+ }
+
void storeFloat(FPRegisterID src, BaseIndex address)
{
ASSERT(isSSE2Present());
@@ -736,33 +1184,144 @@ public:
m_assembler.cvtsd2ss_rr(src, dst);
}
+ void convertDoubleToFloat(Address address, FPRegisterID dst)
+ {
+ ASSERT(isSSE2Present());
+ m_assembler.cvtsd2ss_mr(address.offset, address.base, dst);
+ }
+
void convertFloatToDouble(FPRegisterID src, FPRegisterID dst)
{
ASSERT(isSSE2Present());
m_assembler.cvtss2sd_rr(src, dst);
}
- void addDouble(FPRegisterID src, FPRegisterID dest)
+ void convertFloatToDouble(Address address, FPRegisterID dst)
{
ASSERT(isSSE2Present());
- m_assembler.addsd_rr(src, dest);
+ m_assembler.cvtss2sd_mr(address.offset, address.base, dst);
+ }
+
+ void addDouble(FPRegisterID src, FPRegisterID dest)
+ {
+ addDouble(src, dest, dest);
}
void addDouble(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest)
{
- ASSERT(isSSE2Present());
- if (op1 == dest)
- addDouble(op2, dest);
+ if (supportsAVX())
+ m_assembler.vaddsd_rr(op1, op2, dest);
else {
- moveDouble(op2, dest);
- addDouble(op1, dest);
+ ASSERT(isSSE2Present());
+ if (op1 == dest)
+ m_assembler.addsd_rr(op2, dest);
+ else {
+ moveDouble(op2, dest);
+ m_assembler.addsd_rr(op1, dest);
+ }
}
}
void addDouble(Address src, FPRegisterID dest)
{
- ASSERT(isSSE2Present());
- m_assembler.addsd_mr(src.offset, src.base, dest);
+ addDouble(src, dest, dest);
+ }
+
+ void addDouble(Address op1, FPRegisterID op2, FPRegisterID dest)
+ {
+ if (supportsAVX())
+ m_assembler.vaddsd_mr(op1.offset, op1.base, op2, dest);
+ else {
+ ASSERT(isSSE2Present());
+ if (op2 == dest) {
+ m_assembler.addsd_mr(op1.offset, op1.base, dest);
+ return;
+ }
+
+ loadDouble(op1, dest);
+ addDouble(op2, dest);
+ }
+ }
+
+ void addDouble(FPRegisterID op1, Address op2, FPRegisterID dest)
+ {
+ addDouble(op2, op1, dest);
+ }
+
+ void addDouble(BaseIndex op1, FPRegisterID op2, FPRegisterID dest)
+ {
+ if (supportsAVX())
+ m_assembler.vaddsd_mr(op1.offset, op1.base, op1.index, op1.scale, op2, dest);
+ else {
+ ASSERT(isSSE2Present());
+ if (op2 == dest) {
+ m_assembler.addsd_mr(op1.offset, op1.base, op1.index, op1.scale, dest);
+ return;
+ }
+ loadDouble(op1, dest);
+ addDouble(op2, dest);
+ }
+ }
+
+ void addFloat(FPRegisterID src, FPRegisterID dest)
+ {
+ addFloat(src, dest, dest);
+ }
+
+ void addFloat(Address src, FPRegisterID dest)
+ {
+ addFloat(src, dest, dest);
+ }
+
+ void addFloat(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest)
+ {
+ if (supportsAVX())
+ m_assembler.vaddss_rr(op1, op2, dest);
+ else {
+ ASSERT(isSSE2Present());
+ if (op1 == dest)
+ m_assembler.addss_rr(op2, dest);
+ else {
+ moveDouble(op2, dest);
+ m_assembler.addss_rr(op1, dest);
+ }
+ }
+ }
+
+ void addFloat(Address op1, FPRegisterID op2, FPRegisterID dest)
+ {
+ if (supportsAVX())
+ m_assembler.vaddss_mr(op1.offset, op1.base, op2, dest);
+ else {
+ ASSERT(isSSE2Present());
+ if (op2 == dest) {
+ m_assembler.addss_mr(op1.offset, op1.base, dest);
+ return;
+ }
+
+ loadFloat(op1, dest);
+ addFloat(op2, dest);
+ }
+ }
+
+ void addFloat(FPRegisterID op1, Address op2, FPRegisterID dest)
+ {
+ addFloat(op2, op1, dest);
+ }
+
+ void addFloat(BaseIndex op1, FPRegisterID op2, FPRegisterID dest)
+ {
+ if (supportsAVX())
+ m_assembler.vaddss_mr(op1.offset, op1.base, op1.index, op1.scale, op2, dest);
+ else {
+ ASSERT(isSSE2Present());
+ if (op2 == dest) {
+ m_assembler.addss_mr(op1.offset, op1.base, op1.index, op1.scale, dest);
+ return;
+ }
+ loadFloat(op1, dest);
+ addFloat(op2, dest);
+ }
}
void divDouble(FPRegisterID src, FPRegisterID dest)
@@ -786,48 +1345,314 @@ public:
m_assembler.divsd_mr(src.offset, src.base, dest);
}
- void subDouble(FPRegisterID src, FPRegisterID dest)
+ void divFloat(FPRegisterID src, FPRegisterID dest)
{
ASSERT(isSSE2Present());
- m_assembler.subsd_rr(src, dest);
+ m_assembler.divss_rr(src, dest);
+ }
+
+ void divFloat(Address src, FPRegisterID dest)
+ {
+ ASSERT(isSSE2Present());
+ m_assembler.divss_mr(src.offset, src.base, dest);
+ }
+
+ void subDouble(FPRegisterID src, FPRegisterID dest)
+ {
+ subDouble(dest, src, dest);
}
void subDouble(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest)
{
- // B := A - B is invalid.
- ASSERT(op1 == dest || op2 != dest);
+ if (supportsAVX())
+ m_assembler.vsubsd_rr(op1, op2, dest);
+ else {
+ ASSERT(isSSE2Present());
- moveDouble(op1, dest);
- subDouble(op2, dest);
+ // B := A - B is invalid.
+ ASSERT(op1 == dest || op2 != dest);
+ moveDouble(op1, dest);
+ m_assembler.subsd_rr(op2, dest);
+ }
+ }
+
+ void subDouble(FPRegisterID op1, Address op2, FPRegisterID dest)
+ {
+ if (supportsAVX())
+ m_assembler.vsubsd_mr(op1, op2.offset, op2.base, dest);
+ else {
+ moveDouble(op1, dest);
+ m_assembler.subsd_mr(op2.offset, op2.base, dest);
+ }
+ }
+
+ void subDouble(FPRegisterID op1, BaseIndex op2, FPRegisterID dest)
+ {
+ if (supportsAVX())
+ m_assembler.vsubsd_mr(op1, op2.offset, op2.base, op2.index, op2.scale, dest);
+ else {
+ moveDouble(op1, dest);
+ m_assembler.subsd_mr(op2.offset, op2.base, op2.index, op2.scale, dest);
+ }
}
void subDouble(Address src, FPRegisterID dest)
{
- ASSERT(isSSE2Present());
- m_assembler.subsd_mr(src.offset, src.base, dest);
+ subDouble(dest, src, dest);
+ }
+
+ void subFloat(FPRegisterID src, FPRegisterID dest)
+ {
+ subFloat(dest, src, dest);
+ }
+
+ void subFloat(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest)
+ {
+ if (supportsAVX())
+ m_assembler.vsubss_rr(op1, op2, dest);
+ else {
+ ASSERT(isSSE2Present());
+ // B := A - B is invalid.
+ ASSERT(op1 == dest || op2 != dest);
+ moveDouble(op1, dest);
+ m_assembler.subss_rr(op2, dest);
+ }
+ }
+
+ void subFloat(FPRegisterID op1, Address op2, FPRegisterID dest)
+ {
+ if (supportsAVX())
+ m_assembler.vsubss_mr(op1, op2.offset, op2.base, dest);
+ else {
+ moveDouble(op1, dest);
+ m_assembler.subss_mr(op2.offset, op2.base, dest);
+ }
+ }
+
+ void subFloat(FPRegisterID op1, BaseIndex op2, FPRegisterID dest)
+ {
+ if (supportsAVX())
+ m_assembler.vsubss_mr(op1, op2.offset, op2.base, op2.index, op2.scale, dest);
+ else {
+ moveDouble(op1, dest);
+ m_assembler.subss_mr(op2.offset, op2.base, op2.index, op2.scale, dest);
+ }
+ }
+
+ void subFloat(Address src, FPRegisterID dest)
+ {
+ subFloat(dest, src, dest);
}
void mulDouble(FPRegisterID src, FPRegisterID dest)
{
- ASSERT(isSSE2Present());
- m_assembler.mulsd_rr(src, dest);
+ mulDouble(src, dest, dest);
}
void mulDouble(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest)
{
- ASSERT(isSSE2Present());
- if (op1 == dest)
- mulDouble(op2, dest);
+ if (supportsAVX())
+ m_assembler.vmulsd_rr(op1, op2, dest);
else {
- moveDouble(op2, dest);
- mulDouble(op1, dest);
+ ASSERT(isSSE2Present());
+ if (op1 == dest)
+ m_assembler.mulsd_rr(op2, dest);
+ else {
+ moveDouble(op2, dest);
+ m_assembler.mulsd_rr(op1, dest);
+ }
}
}
void mulDouble(Address src, FPRegisterID dest)
{
- ASSERT(isSSE2Present());
- m_assembler.mulsd_mr(src.offset, src.base, dest);
+ mulDouble(src, dest, dest);
+ }
+
+ void mulDouble(Address op1, FPRegisterID op2, FPRegisterID dest)
+ {
+ if (supportsAVX())
+ m_assembler.vmulsd_mr(op1.offset, op1.base, op2, dest);
+ else {
+ ASSERT(isSSE2Present());
+ if (op2 == dest) {
+ m_assembler.mulsd_mr(op1.offset, op1.base, dest);
+ return;
+ }
+ loadDouble(op1, dest);
+ mulDouble(op2, dest);
+ }
+ }
+
+ void mulDouble(FPRegisterID op1, Address op2, FPRegisterID dest)
+ {
+ return mulDouble(op2, op1, dest);
+ }
+
+ void mulDouble(BaseIndex op1, FPRegisterID op2, FPRegisterID dest)
+ {
+ if (supportsAVX())
+ m_assembler.vmulsd_mr(op1.offset, op1.base, op1.index, op1.scale, op2, dest);
+ else {
+ ASSERT(isSSE2Present());
+ if (op2 == dest) {
+ m_assembler.mulsd_mr(op1.offset, op1.base, op1.index, op1.scale, dest);
+ return;
+ }
+ loadDouble(op1, dest);
+ mulDouble(op2, dest);
+ }
+ }
+
+ void mulFloat(FPRegisterID src, FPRegisterID dest)
+ {
+ mulFloat(src, dest, dest);
+ }
+
+ void mulFloat(Address src, FPRegisterID dest)
+ {
+ mulFloat(src, dest, dest);
+ }
+
+ void mulFloat(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest)
+ {
+ if (supportsAVX())
+ m_assembler.vmulss_rr(op1, op2, dest);
+ else {
+ ASSERT(isSSE2Present());
+ if (op1 == dest)
+ m_assembler.mulss_rr(op2, dest);
+ else {
+ moveDouble(op2, dest);
+ m_assembler.mulss_rr(op1, dest);
+ }
+ }
+ }
+
+ void mulFloat(Address op1, FPRegisterID op2, FPRegisterID dest)
+ {
+ if (supportsAVX())
+ m_assembler.vmulss_mr(op1.offset, op1.base, op2, dest);
+ else {
+ ASSERT(isSSE2Present());
+ if (op2 == dest) {
+ m_assembler.mulss_mr(op1.offset, op1.base, dest);
+ return;
+ }
+ loadFloat(op1, dest);
+ mulFloat(op2, dest);
+ }
+ }
+
+ void mulFloat(FPRegisterID op1, Address op2, FPRegisterID dest)
+ {
+ mulFloat(op2, op1, dest);
+ }
+
+ void mulFloat(BaseIndex op1, FPRegisterID op2, FPRegisterID dest)
+ {
+ if (supportsAVX())
+ m_assembler.vmulss_mr(op1.offset, op1.base, op1.index, op1.scale, op2, dest);
+ else {
+ ASSERT(isSSE2Present());
+ if (op2 == dest) {
+ m_assembler.mulss_mr(op1.offset, op1.base, op1.index, op1.scale, dest);
+ return;
+ }
+ loadFloat(op1, dest);
+ mulFloat(op2, dest);
+ }
+ }
+
+ void andDouble(FPRegisterID src, FPRegisterID dst)
+ {
+ // ANDPS is defined on 128bits and is shorter than ANDPD.
+ m_assembler.andps_rr(src, dst);
+ }
+
+ void andDouble(FPRegisterID src1, FPRegisterID src2, FPRegisterID dst)
+ {
+ if (src1 == dst)
+ andDouble(src2, dst);
+ else {
+ moveDouble(src2, dst);
+ andDouble(src1, dst);
+ }
+ }
+
+ void andFloat(FPRegisterID src, FPRegisterID dst)
+ {
+ m_assembler.andps_rr(src, dst);
+ }
+
+ void andFloat(FPRegisterID src1, FPRegisterID src2, FPRegisterID dst)
+ {
+ if (src1 == dst)
+ andFloat(src2, dst);
+ else {
+ moveDouble(src2, dst);
+ andFloat(src1, dst);
+ }
+ }
+
+ void orDouble(FPRegisterID src, FPRegisterID dst)
+ {
+ m_assembler.orps_rr(src, dst);
+ }
+
+ void orDouble(FPRegisterID src1, FPRegisterID src2, FPRegisterID dst)
+ {
+ if (src1 == dst)
+ orDouble(src2, dst);
+ else {
+ moveDouble(src2, dst);
+ orDouble(src1, dst);
+ }
+ }
+
+ void orFloat(FPRegisterID src, FPRegisterID dst)
+ {
+ m_assembler.orps_rr(src, dst);
+ }
+
+ void orFloat(FPRegisterID src1, FPRegisterID src2, FPRegisterID dst)
+ {
+ if (src1 == dst)
+ orFloat(src2, dst);
+ else {
+ moveDouble(src2, dst);
+ orFloat(src1, dst);
+ }
+ }
+
+ void xorDouble(FPRegisterID src, FPRegisterID dst)
+ {
+ m_assembler.xorps_rr(src, dst);
+ }
+
+ void xorDouble(FPRegisterID src1, FPRegisterID src2, FPRegisterID dst)
+ {
+ if (src1 == dst)
+ xorDouble(src2, dst);
+ else {
+ moveDouble(src2, dst);
+ xorDouble(src1, dst);
+ }
+ }
+
+ void xorFloat(FPRegisterID src, FPRegisterID dst)
+ {
+ m_assembler.xorps_rr(src, dst);
+ }
+
+ void xorFloat(FPRegisterID src1, FPRegisterID src2, FPRegisterID dst)
+ {
+ if (src1 == dst)
+ xorFloat(src2, dst);
+ else {
+ moveDouble(src2, dst);
+ xorFloat(src1, dst);
+ }
}
void convertInt32ToDouble(RegisterID src, FPRegisterID dest)
@@ -842,6 +1667,18 @@ public:
m_assembler.cvtsi2sd_mr(src.offset, src.base, dest);
}
+ void convertInt32ToFloat(RegisterID src, FPRegisterID dest)
+ {
+ ASSERT(isSSE2Present());
+ m_assembler.cvtsi2ss_rr(src, dest);
+ }
+
+ void convertInt32ToFloat(Address src, FPRegisterID dest)
+ {
+ ASSERT(isSSE2Present());
+ m_assembler.cvtsi2ss_mr(src.offset, src.base, dest);
+ }
+
Jump branchDouble(DoubleCondition cond, FPRegisterID left, FPRegisterID right)
{
ASSERT(isSSE2Present());
@@ -850,27 +1687,18 @@ public:
m_assembler.ucomisd_rr(left, right);
else
m_assembler.ucomisd_rr(right, left);
+ return jumpAfterFloatingPointCompare(cond, left, right);
+ }
- if (cond == DoubleEqual) {
- if (left == right)
- return Jump(m_assembler.jnp());
- Jump isUnordered(m_assembler.jp());
- Jump result = Jump(m_assembler.je());
- isUnordered.link(this);
- return result;
- } else if (cond == DoubleNotEqualOrUnordered) {
- if (left == right)
- return Jump(m_assembler.jp());
- Jump isUnordered(m_assembler.jp());
- Jump isEqual(m_assembler.je());
- isUnordered.link(this);
- Jump result = jump();
- isEqual.link(this);
- return result;
- }
+ Jump branchFloat(DoubleCondition cond, FPRegisterID left, FPRegisterID right)
+ {
+ ASSERT(isSSE2Present());
- ASSERT(!(cond & DoubleConditionBitSpecial));
- return Jump(m_assembler.jCC(static_cast<X86Assembler::Condition>(cond & ~DoubleConditionBits)));
+ if (cond & DoubleConditionBitInvert)
+ m_assembler.ucomiss_rr(left, right);
+ else
+ m_assembler.ucomiss_rr(right, left);
+ return jumpAfterFloatingPointCompare(cond, left, right);
}
// Truncates 'src' to an integer, and places the resulting 'dest'.
@@ -890,15 +1718,13 @@ public:
ASSERT(isSSE2Present());
m_assembler.cvttsd2si_rr(src, dest);
}
-
-#if CPU(X86_64)
- void truncateDoubleToUint32(FPRegisterID src, RegisterID dest)
+
+ void truncateFloatToInt32(FPRegisterID src, RegisterID dest)
{
ASSERT(isSSE2Present());
- m_assembler.cvttsd2siq_rr(src, dest);
+ m_assembler.cvttss2si_rr(src, dest);
}
-#endif
-
+
// Convert 'src' to an integer, and places the resulting 'dest'.
// If the result is not representable as a 32 bit value, branch.
// May also branch for some values that are representable in 32 bits
@@ -909,8 +1735,17 @@ public:
m_assembler.cvttsd2si_rr(src, dest);
// If the result is zero, it might have been -0.0, and the double comparison won't catch this!
+#if CPU(X86_64)
+ if (negZeroCheck) {
+ Jump valueIsNonZero = branchTest32(NonZero, dest);
+ m_assembler.movmskpd_rr(src, scratchRegister());
+ failureCases.append(branchTest32(NonZero, scratchRegister(), TrustedImm32(1)));
+ valueIsNonZero.link(this);
+ }
+#else
if (negZeroCheck)
failureCases.append(branchTest32(Zero, dest));
+#endif
// Convert the integer result back to float & compare to the original value - if not equal or unordered (NaN) then jump.
convertInt32ToDouble(dest, fpTemp);
@@ -919,6 +1754,11 @@ public:
failureCases.append(m_assembler.jne());
}
+ void moveZeroToDouble(FPRegisterID reg)
+ {
+ m_assembler.xorps_rr(reg, reg);
+ }
+
Jump branchDoubleNonZero(FPRegisterID reg, FPRegisterID scratch)
{
ASSERT(isSSE2Present());
@@ -951,13 +1791,13 @@ public:
m_assembler.por_rr(src, dst);
}
- void moveInt32ToPacked(RegisterID src, XMMRegisterID dst)
+ void move32ToFloat(RegisterID src, XMMRegisterID dst)
{
ASSERT(isSSE2Present());
m_assembler.movd_rr(src, dst);
}
- void movePackedToInt32(XMMRegisterID src, RegisterID dst)
+ void moveFloatTo32(XMMRegisterID src, RegisterID dst)
{
ASSERT(isSSE2Present());
m_assembler.movd_rr(src, dst);
@@ -1017,20 +1857,104 @@ public:
void move(TrustedImmPtr imm, RegisterID dest)
{
- m_assembler.movq_i64r(imm.asIntptr(), dest);
+ if (!imm.m_value)
+ m_assembler.xorq_rr(dest, dest);
+ else
+ m_assembler.movq_i64r(imm.asIntptr(), dest);
}
void move(TrustedImm64 imm, RegisterID dest)
{
- m_assembler.movq_i64r(imm.m_value, dest);
+ if (!imm.m_value)
+ m_assembler.xorq_rr(dest, dest);
+ else
+ m_assembler.movq_i64r(imm.m_value, dest);
+ }
+
+ void moveConditionallyDouble(DoubleCondition cond, FPRegisterID left, FPRegisterID right, RegisterID src, RegisterID dest)
+ {
+ ASSERT(isSSE2Present());
+
+ if (cond & DoubleConditionBitInvert)
+ m_assembler.ucomisd_rr(left, right);
+ else
+ m_assembler.ucomisd_rr(right, left);
+ moveConditionallyAfterFloatingPointCompare(cond, left, right, src, dest);
+ }
+
+ void moveConditionallyDouble(DoubleCondition cond, FPRegisterID left, FPRegisterID right, RegisterID thenCase, RegisterID elseCase, RegisterID dest)
+ {
+ ASSERT(isSSE2Present());
+
+ if (thenCase != dest && elseCase != dest) {
+ move(elseCase, dest);
+ elseCase = dest;
+ }
+
+ RegisterID src;
+ if (elseCase == dest)
+ src = thenCase;
+ else {
+ cond = invert(cond);
+ src = elseCase;
+ }
+
+ if (cond & DoubleConditionBitInvert)
+ m_assembler.ucomisd_rr(left, right);
+ else
+ m_assembler.ucomisd_rr(right, left);
+ moveConditionallyAfterFloatingPointCompare(cond, left, right, src, dest);
+ }
+
+ void moveConditionallyFloat(DoubleCondition cond, FPRegisterID left, FPRegisterID right, RegisterID src, RegisterID dest)
+ {
+ ASSERT(isSSE2Present());
+
+ if (cond & DoubleConditionBitInvert)
+ m_assembler.ucomiss_rr(left, right);
+ else
+ m_assembler.ucomiss_rr(right, left);
+ moveConditionallyAfterFloatingPointCompare(cond, left, right, src, dest);
}
+ void moveConditionallyFloat(DoubleCondition cond, FPRegisterID left, FPRegisterID right, RegisterID thenCase, RegisterID elseCase, RegisterID dest)
+ {
+ ASSERT(isSSE2Present());
+
+ if (thenCase != dest && elseCase != dest) {
+ move(elseCase, dest);
+ elseCase = dest;
+ }
+
+ RegisterID src;
+ if (elseCase == dest)
+ src = thenCase;
+ else {
+ cond = invert(cond);
+ src = elseCase;
+ }
+
+ if (cond & DoubleConditionBitInvert)
+ m_assembler.ucomiss_rr(left, right);
+ else
+ m_assembler.ucomiss_rr(right, left);
+ moveConditionallyAfterFloatingPointCompare(cond, left, right, src, dest);
+ }
+
void swap(RegisterID reg1, RegisterID reg2)
{
if (reg1 != reg2)
m_assembler.xchgq_rr(reg1, reg2);
}
+ void signExtend32ToPtr(TrustedImm32 imm, RegisterID dest)
+ {
+ if (!imm.m_value)
+ m_assembler.xorq_rr(dest, dest);
+ else
+ m_assembler.mov_i32r(imm.m_value, dest);
+ }
+
void signExtend32ToPtr(RegisterID src, RegisterID dest)
{
m_assembler.movsxd_rr(src, dest);
@@ -1040,6 +1964,11 @@ public:
{
m_assembler.movl_rr(src, dest);
}
+
+ void zeroExtend32ToPtr(TrustedImm32 src, RegisterID dest)
+ {
+ m_assembler.movl_i32r(src.m_value, dest);
+ }
#else
void move(RegisterID src, RegisterID dest)
{
@@ -1049,7 +1978,46 @@ public:
void move(TrustedImmPtr imm, RegisterID dest)
{
- m_assembler.movl_i32r(imm.asIntptr(), dest);
+ if (!imm.m_value)
+ m_assembler.xorl_rr(dest, dest);
+ else
+ m_assembler.movl_i32r(imm.asIntptr(), dest);
+ }
+
+ void moveConditionallyDouble(DoubleCondition cond, FPRegisterID left, FPRegisterID right, RegisterID src, RegisterID dest)
+ {
+ ASSERT(isSSE2Present());
+
+ if (cond & DoubleConditionBitInvert)
+ m_assembler.ucomisd_rr(left, right);
+ else
+ m_assembler.ucomisd_rr(right, left);
+
+ if (cond == DoubleEqual) {
+ if (left == right) {
+ m_assembler.cmovnpl_rr(src, dest);
+ return;
+ }
+
+ Jump isUnordered(m_assembler.jp());
+ m_assembler.cmovel_rr(src, dest);
+ isUnordered.link(this);
+ return;
+ }
+
+ if (cond == DoubleNotEqualOrUnordered) {
+ if (left == right) {
+ m_assembler.cmovpl_rr(src, dest);
+ return;
+ }
+
+ m_assembler.cmovpl_rr(src, dest);
+ m_assembler.cmovnel_rr(src, dest);
+ return;
+ }
+
+ ASSERT(!(cond & DoubleConditionBitSpecial));
+ m_assembler.cmovl_rr(static_cast<X86Assembler::Condition>(cond & ~DoubleConditionBits), src, dest);
}
void swap(RegisterID reg1, RegisterID reg2)
@@ -1069,6 +2037,190 @@ public:
}
#endif
+ void swap32(RegisterID src, RegisterID dest)
+ {
+ m_assembler.xchgl_rr(src, dest);
+ }
+
+ void swap32(RegisterID src, Address dest)
+ {
+ m_assembler.xchgl_rm(src, dest.offset, dest.base);
+ }
+
+ void moveConditionally32(RelationalCondition cond, RegisterID left, RegisterID right, RegisterID src, RegisterID dest)
+ {
+ m_assembler.cmpl_rr(right, left);
+ cmov(x86Condition(cond), src, dest);
+ }
+
+ void moveConditionally32(RelationalCondition cond, RegisterID left, RegisterID right, RegisterID thenCase, RegisterID elseCase, RegisterID dest)
+ {
+ m_assembler.cmpl_rr(right, left);
+
+ if (thenCase != dest && elseCase != dest) {
+ move(elseCase, dest);
+ elseCase = dest;
+ }
+
+ if (elseCase == dest)
+ cmov(x86Condition(cond), thenCase, dest);
+ else
+ cmov(x86Condition(invert(cond)), elseCase, dest);
+ }
+
+ void moveConditionally32(RelationalCondition cond, RegisterID left, TrustedImm32 right, RegisterID thenCase, RegisterID elseCase, RegisterID dest)
+ {
+ if (!right.m_value) {
+ if (auto resultCondition = commuteCompareToZeroIntoTest(cond)) {
+ moveConditionallyTest32(*resultCondition, left, left, thenCase, elseCase, dest);
+ return;
+ }
+ }
+
+ m_assembler.cmpl_ir(right.m_value, left);
+
+ if (thenCase != dest && elseCase != dest) {
+ move(elseCase, dest);
+ elseCase = dest;
+ }
+
+ if (elseCase == dest)
+ cmov(x86Condition(cond), thenCase, dest);
+ else
+ cmov(x86Condition(invert(cond)), elseCase, dest);
+ }
+
+ void moveConditionallyTest32(ResultCondition cond, RegisterID testReg, RegisterID mask, RegisterID src, RegisterID dest)
+ {
+ m_assembler.testl_rr(testReg, mask);
+ cmov(x86Condition(cond), src, dest);
+ }
+
+ void moveConditionallyTest32(ResultCondition cond, RegisterID left, RegisterID right, RegisterID thenCase, RegisterID elseCase, RegisterID dest)
+ {
+ ASSERT(isInvertible(cond));
+ ASSERT_WITH_MESSAGE(cond != Overflow, "TEST does not set the Overflow Flag.");
+
+ m_assembler.testl_rr(right, left);
+
+ if (thenCase != dest && elseCase != dest) {
+ move(elseCase, dest);
+ elseCase = dest;
+ }
+
+ if (elseCase == dest)
+ cmov(x86Condition(cond), thenCase, dest);
+ else
+ cmov(x86Condition(invert(cond)), elseCase, dest);
+ }
+
+ void moveConditionallyTest32(ResultCondition cond, RegisterID testReg, TrustedImm32 mask, RegisterID src, RegisterID dest)
+ {
+ test32(testReg, mask);
+ cmov(x86Condition(cond), src, dest);
+ }
+
+ void moveConditionallyTest32(ResultCondition cond, RegisterID testReg, TrustedImm32 mask, RegisterID thenCase, RegisterID elseCase, RegisterID dest)
+ {
+ ASSERT(isInvertible(cond));
+ ASSERT_WITH_MESSAGE(cond != Overflow, "TEST does not set the Overflow Flag.");
+
+ test32(testReg, mask);
+
+ if (thenCase != dest && elseCase != dest) {
+ move(elseCase, dest);
+ elseCase = dest;
+ }
+
+ if (elseCase == dest)
+ cmov(x86Condition(cond), thenCase, dest);
+ else
+ cmov(x86Condition(invert(cond)), elseCase, dest);
+ }
+
+ template<typename LeftType, typename RightType>
+ void moveDoubleConditionally32(RelationalCondition cond, LeftType left, RightType right, FPRegisterID thenCase, FPRegisterID elseCase, FPRegisterID dest)
+ {
+ 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().");
+
+ if (thenCase != dest && elseCase != dest) {
+ moveDouble(elseCase, dest);
+ elseCase = dest;
+ }
+
+ if (elseCase == dest) {
+ Jump falseCase = branch32(invert(cond), left, right);
+ moveDouble(thenCase, dest);
+ falseCase.link(this);
+ } else {
+ Jump trueCase = branch32(cond, left, right);
+ moveDouble(elseCase, dest);
+ trueCase.link(this);
+ }
+ }
+
+ template<typename TestType, typename MaskType>
+ void moveDoubleConditionallyTest32(ResultCondition cond, TestType test, MaskType mask, FPRegisterID thenCase, FPRegisterID elseCase, FPRegisterID dest)
+ {
+ 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().");
+
+ if (elseCase == dest && isInvertible(cond)) {
+ Jump falseCase = branchTest32(invert(cond), test, mask);
+ moveDouble(thenCase, dest);
+ falseCase.link(this);
+ } else if (thenCase == dest) {
+ Jump trueCase = branchTest32(cond, test, mask);
+ moveDouble(elseCase, dest);
+ trueCase.link(this);
+ }
+
+ Jump trueCase = branchTest32(cond, test, mask);
+ moveDouble(elseCase, dest);
+ Jump falseCase = jump();
+ trueCase.link(this);
+ moveDouble(thenCase, dest);
+ falseCase.link(this);
+ }
+
+ void moveDoubleConditionallyDouble(DoubleCondition cond, FPRegisterID left, FPRegisterID right, FPRegisterID thenCase, FPRegisterID elseCase, FPRegisterID dest)
+ {
+ if (elseCase == dest) {
+ Jump falseCase = branchDouble(invert(cond), left, right);
+ moveDouble(thenCase, dest);
+ falseCase.link(this);
+ } else if (thenCase == dest) {
+ Jump trueCase = branchDouble(cond, left, right);
+ moveDouble(elseCase, dest);
+ trueCase.link(this);
+ } else {
+ Jump trueCase = branchDouble(cond, left, right);
+ moveDouble(elseCase, dest);
+ Jump falseCase = jump();
+ trueCase.link(this);
+ moveDouble(thenCase, dest);
+ falseCase.link(this);
+ }
+ }
+
+ void moveDoubleConditionallyFloat(DoubleCondition cond, FPRegisterID left, FPRegisterID right, FPRegisterID thenCase, FPRegisterID elseCase, FPRegisterID dest)
+ {
+ if (elseCase == dest) {
+ Jump falseCase = branchFloat(invert(cond), left, right);
+ moveDouble(thenCase, dest);
+ falseCase.link(this);
+ } else if (thenCase == dest) {
+ Jump trueCase = branchFloat(cond, left, right);
+ moveDouble(elseCase, dest);
+ trueCase.link(this);
+ } else {
+ Jump trueCase = branchFloat(cond, left, right);
+ moveDouble(elseCase, dest);
+ Jump falseCase = jump();
+ trueCase.link(this);
+ moveDouble(thenCase, dest);
+ falseCase.link(this);
+ }
+ }
// Forwards / external control flow operations:
//
@@ -1091,7 +2243,8 @@ public:
public:
Jump branch8(RelationalCondition cond, Address left, TrustedImm32 right)
{
- m_assembler.cmpb_im(right.m_value, left.offset, left.base);
+ TrustedImm32 right8(static_cast<int8_t>(right.m_value));
+ m_assembler.cmpb_im(right8.m_value, left.offset, left.base);
return Jump(m_assembler.jCC(x86Condition(cond)));
}
@@ -1103,10 +2256,12 @@ public:
Jump branch32(RelationalCondition cond, RegisterID left, TrustedImm32 right)
{
- if (((cond == Equal) || (cond == NotEqual)) && !right.m_value)
- m_assembler.testl_rr(left, left);
- else
- m_assembler.cmpl_ir(right.m_value, left);
+ if (!right.m_value) {
+ if (auto resultCondition = commuteCompareToZeroIntoTest(cond))
+ return branchTest32(*resultCondition, left, left);
+ }
+
+ m_assembler.cmpl_ir(right.m_value, left);
return Jump(m_assembler.jCC(x86Condition(cond)));
}
@@ -1149,9 +2304,12 @@ public:
{
if (mask.m_value == -1)
m_assembler.testl_rr(reg, reg);
- 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.
- m_assembler.testb_i8r(mask.m_value, reg);
- else
+ 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.
+ if (mask.m_value == 0xff)
+ m_assembler.testb_rr(reg, reg);
+ else
+ m_assembler.testb_i8r(mask.m_value, reg);
+ } else
m_assembler.testl_i32r(mask.m_value, reg);
}
@@ -1183,31 +2341,28 @@ public:
Jump branchTest8(ResultCondition cond, Address address, TrustedImm32 mask = TrustedImm32(-1))
{
- // Byte in TrustedImm32 is not well defined, so be a little permisive here, but don't accept nonsense values.
- ASSERT(mask.m_value >= -128 && mask.m_value <= 255);
- if (mask.m_value == -1)
+ TrustedImm32 mask8(static_cast<int8_t>(mask.m_value));
+ if (mask8.m_value == -1)
m_assembler.cmpb_im(0, address.offset, address.base);
else
- m_assembler.testb_im(mask.m_value, address.offset, address.base);
+ m_assembler.testb_im(mask8.m_value, address.offset, address.base);
return Jump(m_assembler.jCC(x86Condition(cond)));
}
Jump branchTest8(ResultCondition cond, BaseIndex address, TrustedImm32 mask = TrustedImm32(-1))
{
- // Byte in TrustedImm32 is not well defined, so be a little permisive here, but don't accept nonsense values.
- ASSERT(mask.m_value >= -128 && mask.m_value <= 255);
- if (mask.m_value == -1)
+ TrustedImm32 mask8(static_cast<int8_t>(mask.m_value));
+ if (mask8.m_value == -1)
m_assembler.cmpb_im(0, address.offset, address.base, address.index, address.scale);
else
- m_assembler.testb_im(mask.m_value, address.offset, address.base, address.index, address.scale);
+ m_assembler.testb_im(mask8.m_value, address.offset, address.base, address.index, address.scale);
return Jump(m_assembler.jCC(x86Condition(cond)));
}
Jump branch8(RelationalCondition cond, BaseIndex left, TrustedImm32 right)
{
- ASSERT(!(right.m_value & 0xFFFFFF00));
-
- m_assembler.cmpb_im(right.m_value, left.offset, left.base, left.index, left.scale);
+ TrustedImm32 right8(static_cast<int8_t>(right.m_value));
+ m_assembler.cmpb_im(right8.m_value, left.offset, left.base, left.index, left.scale);
return Jump(m_assembler.jCC(x86Condition(cond)));
}
@@ -1227,6 +2382,12 @@ public:
m_assembler.jmp_m(address.offset, address.base);
}
+ // Address is a memory location containing the address to jump to
+ void jump(BaseIndex address)
+ {
+ m_assembler.jmp_m(address.offset, address.base, address.index, address.scale);
+ }
+
// Arithmetic control flow operations:
//
@@ -1272,13 +2433,30 @@ public:
{
if (src1 == dest)
return branchAdd32(cond, src2, dest);
- move(src2, dest);
+ move32IfNeeded(src2, dest);
return branchAdd32(cond, src1, dest);
}
+ Jump branchAdd32(ResultCondition cond, Address op1, RegisterID op2, RegisterID dest)
+ {
+ if (op2 == dest)
+ return branchAdd32(cond, op1, dest);
+ if (op1.base == dest) {
+ load32(op1, dest);
+ return branchAdd32(cond, op2, dest);
+ }
+ zeroExtend32ToPtr(op2, dest);
+ return branchAdd32(cond, op1, dest);
+ }
+
+ Jump branchAdd32(ResultCondition cond, RegisterID src1, Address src2, RegisterID dest)
+ {
+ return branchAdd32(cond, src2, src1, dest);
+ }
+
Jump branchAdd32(ResultCondition cond, RegisterID src, TrustedImm32 imm, RegisterID dest)
{
- move(src, dest);
+ move32IfNeeded(src, dest);
return branchAdd32(cond, imm, dest);
}
@@ -1298,7 +2476,7 @@ public:
return Jump(m_assembler.jCC(x86Condition(cond)));
}
- Jump branchMul32(ResultCondition cond, TrustedImm32 imm, RegisterID src, RegisterID dest)
+ Jump branchMul32(ResultCondition cond, RegisterID src, TrustedImm32 imm, RegisterID dest)
{
mul32(imm, src, dest);
if (cond != Overflow)
@@ -1310,7 +2488,7 @@ public:
{
if (src1 == dest)
return branchMul32(cond, src2, dest);
- move(src2, dest);
+ move32IfNeeded(src2, dest);
return branchMul32(cond, src1, dest);
}
@@ -1349,13 +2527,13 @@ public:
// B := A - B is invalid.
ASSERT(src1 == dest || src2 != dest);
- move(src1, dest);
+ move32IfNeeded(src1, dest);
return branchSub32(cond, src2, dest);
}
Jump branchSub32(ResultCondition cond, RegisterID src1, TrustedImm32 src2, RegisterID dest)
{
- move(src1, dest);
+ move32IfNeeded(src1, dest);
return branchSub32(cond, src2, dest);
}
@@ -1379,6 +2557,11 @@ public:
m_assembler.int3();
}
+ Call nearTailCall()
+ {
+ return Call(m_assembler.jmp(), Call::LinkableNearTail);
+ }
+
Call nearCall()
{
return Call(m_assembler.call(), Call::LinkableNear);
@@ -1401,7 +2584,8 @@ public:
void compare8(RelationalCondition cond, Address left, TrustedImm32 right, RegisterID dest)
{
- m_assembler.cmpb_im(right.m_value, left.offset, left.base);
+ TrustedImm32 right8(static_cast<int8_t>(right.m_value));
+ m_assembler.cmpb_im(right8.m_value, left.offset, left.base);
set32(x86Condition(cond), dest);
}
@@ -1413,10 +2597,14 @@ public:
void compare32(RelationalCondition cond, RegisterID left, TrustedImm32 right, RegisterID dest)
{
- if (((cond == Equal) || (cond == NotEqual)) && !right.m_value)
- m_assembler.testl_rr(left, left);
- else
- m_assembler.cmpl_ir(right.m_value, left);
+ if (!right.m_value) {
+ if (auto resultCondition = commuteCompareToZeroIntoTest(cond)) {
+ test32(*resultCondition, left, left, dest);
+ return;
+ }
+ }
+
+ m_assembler.cmpl_ir(right.m_value, left);
set32(x86Condition(cond), dest);
}
@@ -1427,10 +2615,11 @@ public:
void test8(ResultCondition cond, Address address, TrustedImm32 mask, RegisterID dest)
{
- if (mask.m_value == -1)
+ TrustedImm32 mask8(static_cast<int8_t>(mask.m_value));
+ if (mask8.m_value == -1)
m_assembler.cmpb_im(0, address.offset, address.base);
else
- m_assembler.testb_im(mask.m_value, address.offset, address.base);
+ m_assembler.testb_im(mask8.m_value, address.offset, address.base);
set32(x86Condition(cond), dest);
}
@@ -1440,20 +2629,129 @@ public:
set32(x86Condition(cond), dest);
}
+ void test32(ResultCondition cond, RegisterID reg, RegisterID mask, RegisterID dest)
+ {
+ m_assembler.testl_rr(reg, mask);
+ set32(x86Condition(cond), dest);
+ }
+
+ void test32(ResultCondition cond, RegisterID reg, TrustedImm32 mask, RegisterID dest)
+ {
+ test32(reg, mask);
+ set32(x86Condition(cond), dest);
+ }
+
+ void setCarry(RegisterID dest)
+ {
+ set32(X86Assembler::ConditionC, dest);
+ }
+
// Invert a relational condition, e.g. == becomes !=, < becomes >=, etc.
static RelationalCondition invert(RelationalCondition cond)
{
return static_cast<RelationalCondition>(cond ^ 1);
}
+ static DoubleCondition invert(DoubleCondition cond)
+ {
+ switch (cond) {
+ case DoubleEqual:
+ return DoubleNotEqualOrUnordered;
+ case DoubleNotEqual:
+ return DoubleEqualOrUnordered;
+ case DoubleGreaterThan:
+ return DoubleLessThanOrEqualOrUnordered;
+ case DoubleGreaterThanOrEqual:
+ return DoubleLessThanOrUnordered;
+ case DoubleLessThan:
+ return DoubleGreaterThanOrEqualOrUnordered;
+ case DoubleLessThanOrEqual:
+ return DoubleGreaterThanOrUnordered;
+ case DoubleEqualOrUnordered:
+ return DoubleNotEqual;
+ case DoubleNotEqualOrUnordered:
+ return DoubleEqual;
+ case DoubleGreaterThanOrUnordered:
+ return DoubleLessThanOrEqual;
+ case DoubleGreaterThanOrEqualOrUnordered:
+ return DoubleLessThan;
+ case DoubleLessThanOrUnordered:
+ return DoubleGreaterThanOrEqual;
+ case DoubleLessThanOrEqualOrUnordered:
+ return DoubleGreaterThan;
+ }
+ RELEASE_ASSERT_NOT_REACHED();
+ return DoubleEqual; // make compiler happy
+ }
+
+ static bool isInvertible(ResultCondition cond)
+ {
+ switch (cond) {
+ case Zero:
+ case NonZero:
+ case Signed:
+ case PositiveOrZero:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ static ResultCondition invert(ResultCondition cond)
+ {
+ switch (cond) {
+ case Zero:
+ return NonZero;
+ case NonZero:
+ return Zero;
+ case Signed:
+ return PositiveOrZero;
+ case PositiveOrZero:
+ return Signed;
+ default:
+ RELEASE_ASSERT_NOT_REACHED();
+ return Zero; // Make compiler happy for release builds.
+ }
+ }
+
+ static std::optional<ResultCondition> commuteCompareToZeroIntoTest(RelationalCondition cond)
+ {
+ switch (cond) {
+ case Equal:
+ return Zero;
+ case NotEqual:
+ return NonZero;
+ case LessThan:
+ return Signed;
+ case GreaterThanOrEqual:
+ return PositiveOrZero;
+ break;
+ default:
+ return std::nullopt;
+ }
+ }
+
void nop()
{
m_assembler.nop();
}
+ // We take memoryFence to mean acqrel. This has acqrel semantics on x86.
void memoryFence()
{
- m_assembler.mfence();
+ // lock; orl $0, (%rsp)
+ m_assembler.lock();
+ m_assembler.orl_im(0, 0, X86Registers::esp);
+ }
+
+ // We take this to mean that it prevents motion of normal stores. So, it's a no-op on x86.
+ void storeFence()
+ {
+ }
+
+ // We take this to mean that it prevents motion of normal loads. So, it's a no-op on x86.
+ void loadFence()
+ {
}
static void replaceWithJump(CodeLocationLabel instructionStart, CodeLocationLabel destination)
@@ -1466,28 +2764,61 @@ public:
return X86Assembler::maxJumpReplacementSize();
}
-#if USE(MASM_PROBE)
- struct CPUState {
- #define DECLARE_REGISTER(_type, _regName) \
- _type _regName;
- FOR_EACH_CPU_REGISTER(DECLARE_REGISTER)
- #undef DECLARE_REGISTER
- };
+ static ptrdiff_t patchableJumpSize()
+ {
+ return X86Assembler::patchableJumpSize();
+ }
- struct ProbeContext;
- typedef void (*ProbeFunction)(struct ProbeContext*);
+ static bool supportsFloatingPointRounding()
+ {
+ if (s_sse4_1CheckState == CPUIDCheckState::NotChecked)
+ updateEax1EcxFlags();
+ return s_sse4_1CheckState == CPUIDCheckState::Set;
+ }
- struct ProbeContext {
- ProbeFunction probeFunction;
- void* arg1;
- void* arg2;
- CPUState cpu;
+ static bool supportsAVX()
+ {
+ // AVX still causes mysterious regressions and those regressions can be massive.
+ return false;
+ }
- void dump(const char* indentation = 0);
- private:
- void dumpCPURegisters(const char* indentation);
- };
-#endif // USE(MASM_PROBE)
+ static void updateEax1EcxFlags()
+ {
+ int flags = 0;
+#if COMPILER(MSVC)
+ int cpuInfo[4];
+ __cpuid(cpuInfo, 0x1);
+ flags = cpuInfo[2];
+#elif COMPILER(GCC_OR_CLANG)
+#if CPU(X86_64)
+ asm (
+ "movl $0x1, %%eax;"
+ "cpuid;"
+ "movl %%ecx, %0;"
+ : "=g" (flags)
+ :
+ : "%eax", "%ebx", "%ecx", "%edx"
+ );
+#else
+ asm (
+ "movl $0x1, %%eax;"
+ "pushl %%ebx;"
+ "cpuid;"
+ "popl %%ebx;"
+ "movl %%ecx, %0;"
+ : "=g" (flags)
+ :
+ : "%eax", "%ecx", "%edx"
+ );
+#endif
+#endif // COMPILER(GCC_OR_CLANG)
+ s_sse4_1CheckState = (flags & (1 << 19)) ? CPUIDCheckState::Set : CPUIDCheckState::Clear;
+ s_avxCheckState = (flags & (1 << 28)) ? CPUIDCheckState::Set : CPUIDCheckState::Clear;
+ }
+
+#if ENABLE(MASM_PROBE)
+ void probe(ProbeFunction, void* arg1, void* arg2);
+#endif // ENABLE(MASM_PROBE)
protected:
X86Assembler::Condition x86Condition(RelationalCondition cond)
@@ -1517,6 +2848,84 @@ protected:
m_assembler.movzbl_rr(dest, dest);
}
+ void cmov(X86Assembler::Condition cond, RegisterID src, RegisterID dest)
+ {
+#if CPU(X86_64)
+ m_assembler.cmovq_rr(cond, src, dest);
+#else
+ m_assembler.cmovl_rr(cond, src, dest);
+#endif
+ }
+
+ static bool supportsLZCNT()
+ {
+ if (s_lzcntCheckState == CPUIDCheckState::NotChecked) {
+ int flags = 0;
+#if COMPILER(MSVC)
+ int cpuInfo[4];
+ __cpuid(cpuInfo, 0x80000001);
+ flags = cpuInfo[2];
+#elif COMPILER(GCC_OR_CLANG)
+#if CPU(X86_64)
+ asm (
+ "movl $0x80000001, %%eax;"
+ "cpuid;"
+ "movl %%ecx, %0;"
+ : "=g" (flags)
+ :
+ : "%eax", "%ebx", "%ecx", "%edx"
+ );
+#else
+ asm (
+ "movl $0x80000001, %%eax;"
+ "pushl %%ebx;"
+ "cpuid;"
+ "popl %%ebx;"
+ "movl %%ecx, %0;"
+ : "=g" (flags)
+ :
+ : "%eax", "%ecx", "%edx"
+ );
+#endif
+#endif // COMPILER(GCC_OR_CLANG)
+ s_lzcntCheckState = (flags & 0x20) ? CPUIDCheckState::Set : CPUIDCheckState::Clear;
+ }
+ return s_lzcntCheckState == CPUIDCheckState::Set;
+ }
+
+ static bool supportsBMI1()
+ {
+ if (s_bmi1CheckState == CPUIDCheckState::NotChecked) {
+ int flags = 0;
+#if COMPILER(MSVC)
+ int cpuInfo[4];
+ __cpuid(cpuInfo, 0x80000001);
+ flags = cpuInfo[2];
+#elif COMPILER(GCC_OR_CLANG)
+ asm (
+ "movl $0x7, %%eax;"
+ "movl $0x0, %%ecx;"
+ "cpuid;"
+ "movl %%ebx, %0;"
+ : "=g" (flags)
+ :
+ : "%eax", "%ebx", "%ecx", "%edx"
+ );
+#endif // COMPILER(GCC_OR_CLANG)
+ static int BMI1FeatureBit = 1 << 3;
+ s_bmi1CheckState = (flags & BMI1FeatureBit) ? CPUIDCheckState::Set : CPUIDCheckState::Clear;
+ }
+ return s_bmi1CheckState == CPUIDCheckState::Set;
+ }
+
+ template<int sizeOfRegister>
+ void ctzAfterBsf(RegisterID dst)
+ {
+ Jump srcIsNonZero = m_assembler.jCC(x86Condition(NonZero));
+ move(TrustedImm32(sizeOfRegister), dst);
+ srcIsNonZero.link(this);
+ }
+
private:
// Only MacroAssemblerX86 should be using the following method; SSE2 is always available on
// x86_64, and clients & subclasses of MacroAssembler should be using 'supportsFloatingPoint()'.
@@ -1538,6 +2947,84 @@ private:
m_assembler.testl_i32m(mask.m_value, address.offset, address.base);
}
+ // If lzcnt is not available, use this after BSR
+ // to count the leading zeros.
+ void clz32AfterBsr(RegisterID dst)
+ {
+ Jump srcIsNonZero = m_assembler.jCC(x86Condition(NonZero));
+ move(TrustedImm32(32), dst);
+
+ Jump skipNonZeroCase = jump();
+ srcIsNonZero.link(this);
+ xor32(TrustedImm32(0x1f), dst);
+ skipNonZeroCase.link(this);
+ }
+
+ Jump jumpAfterFloatingPointCompare(DoubleCondition cond, FPRegisterID left, FPRegisterID right)
+ {
+ if (cond == DoubleEqual) {
+ if (left == right)
+ return Jump(m_assembler.jnp());
+ Jump isUnordered(m_assembler.jp());
+ Jump result = Jump(m_assembler.je());
+ isUnordered.link(this);
+ return result;
+ }
+ if (cond == DoubleNotEqualOrUnordered) {
+ if (left == right)
+ return Jump(m_assembler.jp());
+ Jump isUnordered(m_assembler.jp());
+ Jump isEqual(m_assembler.je());
+ isUnordered.link(this);
+ Jump result = jump();
+ isEqual.link(this);
+ return result;
+ }
+
+ ASSERT(!(cond & DoubleConditionBitSpecial));
+ return Jump(m_assembler.jCC(static_cast<X86Assembler::Condition>(cond & ~DoubleConditionBits)));
+ }
+
+ // The 32bit Move does not need the REX byte for low registers, making it shorter.
+ // Use this if the top bits are irrelevant because they will be reset by the next instruction.
+ void move32IfNeeded(RegisterID src, RegisterID dest)
+ {
+ if (src == dest)
+ return;
+ m_assembler.movl_rr(src, dest);
+ }
+
+#if CPU(X86_64)
+ void moveConditionallyAfterFloatingPointCompare(DoubleCondition cond, FPRegisterID left, FPRegisterID right, RegisterID src, RegisterID dest)
+ {
+ if (cond == DoubleEqual) {
+ if (left == right) {
+ m_assembler.cmovnpq_rr(src, dest);
+ return;
+ }
+
+ Jump isUnordered(m_assembler.jp());
+ m_assembler.cmoveq_rr(src, dest);
+ isUnordered.link(this);
+ return;
+ }
+
+ if (cond == DoubleNotEqualOrUnordered) {
+ if (left == right) {
+ m_assembler.cmovpq_rr(src, dest);
+ return;
+ }
+
+ m_assembler.cmovpq_rr(src, dest);
+ m_assembler.cmovneq_rr(src, dest);
+ return;
+ }
+
+ ASSERT(!(cond & DoubleConditionBitSpecial));
+ cmov(static_cast<X86Assembler::Condition>(cond & ~DoubleConditionBits), src, dest);
+ }
+#endif
+
#if CPU(X86)
#if OS(MAC_OS_X)
@@ -1567,7 +3054,7 @@ private:
cpuid;
mov flags, edx;
}
-#elif COMPILER(GCC)
+#elif COMPILER(GCC_OR_CLANG)
asm (
"movl $0x1, %%eax;"
"pushl %%ebx;"
@@ -1588,7 +3075,7 @@ private:
return s_sse2CheckState == HasSSE2;
}
- static SSE2CheckState s_sse2CheckState;
+ JS_EXPORTDATA static SSE2CheckState s_sse2CheckState;
#endif // OS(MAC_OS_X)
#elif !defined(NDEBUG) // CPU(X86)
@@ -1601,10 +3088,18 @@ private:
}
#endif
+
+ enum class CPUIDCheckState {
+ NotChecked,
+ Clear,
+ Set
+ };
+ JS_EXPORT_PRIVATE static CPUIDCheckState s_sse4_1CheckState;
+ JS_EXPORT_PRIVATE static CPUIDCheckState s_avxCheckState;
+ static CPUIDCheckState s_bmi1CheckState;
+ static CPUIDCheckState s_lzcntCheckState;
};
} // namespace JSC
#endif // ENABLE(ASSEMBLER)
-
-#endif // MacroAssemblerX86Common_h