#ifndef jit_x86_shared_MacroAssembler_x86_shared_h
#define jit_x86_shared_MacroAssembler_x86_shared_h
#include "mozilla/Casting.h"
#if defined(JS_CODEGEN_X86)
# include "jit/x86/Assembler-x86.h"
#elif defined(JS_CODEGEN_X64)
# include "jit/x64/Assembler-x64.h"
#endif
namespace js {
namespace jit {
class MacroAssembler;
class MacroAssemblerX86Shared : public Assembler {
private:
MacroAssembler& asMasm();
const MacroAssembler& asMasm() const;
public:
typedef Vector<CodeOffset, 0, SystemAllocPolicy> UsesVector;
protected:
template <class T>
struct Constant {
typedef T Pod;
T value;
UsesVector uses;
explicit Constant(const T& value) : value(value) {}
Constant(Constant<T>&& other)
: value(other.value), uses(std::move(other.uses)) {}
explicit Constant(const Constant<T>&) = delete;
};
using Double = Constant<double>;
Vector<Double, 0, SystemAllocPolicy> doubles_;
typedef HashMap<double, size_t, DefaultHasher<double>, SystemAllocPolicy>
DoubleMap;
DoubleMap doubleMap_;
using Float = Constant<float>;
Vector<Float, 0, SystemAllocPolicy> floats_;
typedef HashMap<float, size_t, DefaultHasher<float>, SystemAllocPolicy>
FloatMap;
FloatMap floatMap_;
struct SimdData : public Constant<SimdConstant> {
explicit SimdData(SimdConstant d) : Constant<SimdConstant>(d) {}
SimdData(SimdData&& d) : Constant<SimdConstant>(std::move(d)) {}
explicit SimdData(const SimdData&) = delete;
SimdConstant::Type type() const { return value.type(); }
};
Vector<SimdData, 0, SystemAllocPolicy> simds_;
typedef HashMap<SimdConstant, size_t, SimdConstant, SystemAllocPolicy>
SimdMap;
SimdMap simdMap_;
template <class T, class Map>
T* getConstant(const typename T::Pod& value, Map& map,
Vector<T, 0, SystemAllocPolicy>& vec);
Float* getFloat(float f);
Double* getDouble(double d);
SimdData* getSimdData(const SimdConstant& v);
public:
using Assembler::call;
MacroAssemblerX86Shared() {}
bool appendRawCode(const uint8_t* code, size_t numBytes) {
return masm.appendRawCode(code, numBytes);
}
void minMaxDouble(FloatRegister srcDest, FloatRegister second, bool canBeNaN,
bool isMax);
void minMaxFloat32(FloatRegister srcDest, FloatRegister second, bool canBeNaN,
bool isMax);
void compareDouble(DoubleCondition cond, FloatRegister lhs,
FloatRegister rhs) {
if (cond & DoubleConditionBitInvert) {
vucomisd(lhs, rhs);
} else {
vucomisd(rhs, lhs);
}
}
void compareFloat(DoubleCondition cond, FloatRegister lhs,
FloatRegister rhs) {
if (cond & DoubleConditionBitInvert) {
vucomiss(lhs, rhs);
} else {
vucomiss(rhs, lhs);
}
}
void branchNegativeZero(FloatRegister reg, Register scratch, Label* label,
bool maybeNonZero = true);
void branchNegativeZeroFloat32(FloatRegister reg, Register scratch,
Label* label);
void move32(Imm32 imm, Register dest) {
mov(ImmWord(uint32_t(imm.value)), dest);
}
void move32(Imm32 imm, const Operand& dest) { movl(imm, dest); }
void move32(Register src, Register dest) { movl(src, dest); }
void move32(Register src, const Operand& dest) { movl(src, dest); }
void test32(Register lhs, Register rhs) { testl(rhs, lhs); }
void test32(const Address& addr, Imm32 imm) { testl(imm, Operand(addr)); }
void test32(const Operand lhs, Imm32 imm) { testl(imm, lhs); }
void test32(Register lhs, Imm32 rhs) { testl(rhs, lhs); }
void cmp32(Register lhs, Imm32 rhs) { cmpl(rhs, lhs); }
void cmp32(Register lhs, Register rhs) { cmpl(rhs, lhs); }
void cmp32(const Address& lhs, Register rhs) { cmp32(Operand(lhs), rhs); }
void cmp32(const Address& lhs, Imm32 rhs) { cmp32(Operand(lhs), rhs); }
void cmp32(const Operand& lhs, Imm32 rhs) { cmpl(rhs, lhs); }
void cmp32(const Operand& lhs, Register rhs) { cmpl(rhs, lhs); }
void cmp32(Register lhs, const Operand& rhs) { cmpl(rhs, lhs); }
CodeOffset cmp32WithPatch(Register lhs, Imm32 rhs) {
return cmplWithPatch(rhs, lhs);
}
void atomic_inc32(const Operand& addr) { lock_incl(addr); }
void atomic_dec32(const Operand& addr) { lock_decl(addr); }
void storeLoadFence() {
if (HasSSE2()) {
masm.mfence();
} else {
lock_addl(Imm32(0), Operand(Address(esp, 0)));
}
}
void branch16(Condition cond, Register lhs, Register rhs, Label* label) {
cmpw(rhs, lhs);
j(cond, label);
}
void branchTest16(Condition cond, Register lhs, Register rhs, Label* label) {
testw(rhs, lhs);
j(cond, label);
}
void jump(Label* label) { jmp(label); }
void jump(JitCode* code) { jmp(code); }
void jump(TrampolinePtr code) { jmp(ImmPtr(code.value)); }
void jump(RepatchLabel* label) { jmp(label); }
void jump(Register reg) { jmp(Operand(reg)); }
void jump(const Address& addr) { jmp(Operand(addr)); }
void convertInt32ToDouble(Register src, FloatRegister dest) {
zeroDouble(dest);
vcvtsi2sd(src, dest, dest);
}
void convertInt32ToDouble(const Address& src, FloatRegister dest) {
convertInt32ToDouble(Operand(src), dest);
}
void convertInt32ToDouble(const BaseIndex& src, FloatRegister dest) {
convertInt32ToDouble(Operand(src), dest);
}
void convertInt32ToDouble(const Operand& src, FloatRegister dest) {
zeroDouble(dest);
vcvtsi2sd(Operand(src), dest, dest);
}
void convertInt32ToFloat32(Register src, FloatRegister dest) {
zeroFloat32(dest);
vcvtsi2ss(src, dest, dest);
}
void convertInt32ToFloat32(const Address& src, FloatRegister dest) {
convertInt32ToFloat32(Operand(src), dest);
}
void convertInt32ToFloat32(const Operand& src, FloatRegister dest) {
zeroFloat32(dest);
vcvtsi2ss(src, dest, dest);
}
Condition testDoubleTruthy(bool truthy, FloatRegister reg) {
ScratchDoubleScope scratch(asMasm());
zeroDouble(scratch);
vucomisd(reg, scratch);
return truthy ? NonZero : Zero;
}
class AutoEnsureByteRegister {
MacroAssemblerX86Shared* masm;
Register original_;
Register substitute_;
public:
template <typename T>
AutoEnsureByteRegister(MacroAssemblerX86Shared* masm, T address,
Register reg)
: masm(masm), original_(reg) {
AllocatableGeneralRegisterSet singleByteRegs(Registers::SingleByteRegs);
if (singleByteRegs.has(reg)) {
substitute_ = reg;
} else {
MOZ_ASSERT(address.base != StackPointer);
do {
substitute_ = singleByteRegs.takeAny();
} while (Operand(address).containsReg(substitute_));
masm->push(substitute_);
masm->mov(reg, substitute_);
}
}
~AutoEnsureByteRegister() {
if (original_ != substitute_) {
masm->pop(substitute_);
}
}
Register reg() { return substitute_; }
};
void load8ZeroExtend(const Operand& src, Register dest) { movzbl(src, dest); }
void load8ZeroExtend(const Address& src, Register dest) {
movzbl(Operand(src), dest);
}
void load8ZeroExtend(const BaseIndex& src, Register dest) {
movzbl(Operand(src), dest);
}
void load8SignExtend(const Operand& src, Register dest) { movsbl(src, dest); }
void load8SignExtend(const Address& src, Register dest) {
movsbl(Operand(src), dest);
}
void load8SignExtend(const BaseIndex& src, Register dest) {
movsbl(Operand(src), dest);
}
template <typename T>
void store8(Imm32 src, const T& dest) {
movb(src, Operand(dest));
}
template <typename T>
void store8(Register src, const T& dest) {
AutoEnsureByteRegister ensure(this, dest, src);
movb(ensure.reg(), Operand(dest));
}
void load16ZeroExtend(const Operand& src, Register dest) {
movzwl(src, dest);
}
void load16ZeroExtend(const Address& src, Register dest) {
movzwl(Operand(src), dest);
}
void load16ZeroExtend(const BaseIndex& src, Register dest) {
movzwl(Operand(src), dest);
}
template <typename S, typename T>
void store16(const S& src, const T& dest) {
movw(src, Operand(dest));
}
void load16SignExtend(const Operand& src, Register dest) {
movswl(src, dest);
}
void load16SignExtend(const Address& src, Register dest) {
movswl(Operand(src), dest);
}
void load16SignExtend(const BaseIndex& src, Register dest) {
movswl(Operand(src), dest);
}
void load32(const Address& address, Register dest) {
movl(Operand(address), dest);
}
void load32(const BaseIndex& src, Register dest) { movl(Operand(src), dest); }
void load32(const Operand& src, Register dest) { movl(src, dest); }
template <typename S, typename T>
void store32(const S& src, const T& dest) {
movl(src, Operand(dest));
}
template <typename S, typename T>
void store32_NoSecondScratch(const S& src, const T& dest) {
store32(src, dest);
}
void loadDouble(const Address& src, FloatRegister dest) { vmovsd(src, dest); }
void loadDouble(const BaseIndex& src, FloatRegister dest) {
vmovsd(src, dest);
}
void loadDouble(const Operand& src, FloatRegister dest) {
switch (src.kind()) {
case Operand::MEM_REG_DISP:
loadDouble(src.toAddress(), dest);
break;
case Operand::MEM_SCALE:
loadDouble(src.toBaseIndex(), dest);
break;
default:
MOZ_CRASH("unexpected operand kind");
}
}
void moveDouble(FloatRegister src, FloatRegister dest) {
vmovapd(src, dest);
}
void zeroDouble(FloatRegister reg) { vxorpd(reg, reg, reg); }
void zeroFloat32(FloatRegister reg) { vxorps(reg, reg, reg); }
void convertFloat32ToDouble(FloatRegister src, FloatRegister dest) {
vcvtss2sd(src, dest, dest);
}
void convertDoubleToFloat32(FloatRegister src, FloatRegister dest) {
vcvtsd2ss(src, dest, dest);
}
void loadInt32x4(const Address& addr, FloatRegister dest) {
vmovdqa(Operand(addr), dest);
}
void loadFloat32x4(const Address& addr, FloatRegister dest) {
vmovaps(Operand(addr), dest);
}
void storeInt32x4(FloatRegister src, const Address& addr) {
vmovdqa(src, Operand(addr));
}
void storeFloat32x4(FloatRegister src, const Address& addr) {
vmovaps(src, Operand(addr));
}
void convertFloat32x4ToInt32x4(FloatRegister src, FloatRegister dest) {
vcvttps2dq(src, dest);
}
void convertInt32x4ToFloat32x4(FloatRegister src, FloatRegister dest) {
vcvtdq2ps(src, dest);
}
void checkedConvertFloat32x4ToInt32x4(FloatRegister src, FloatRegister dest,
Register temp, Label* oolCheck,
Label* rejoin);
void oolConvertFloat32x4ToInt32x4(FloatRegister src, Register temp,
Label* rejoin, Label* onConversionError);
void checkedConvertFloat32x4ToUint32x4(FloatRegister src, FloatRegister dest,
Register temp, FloatRegister tempF,
Label* failed);
void createInt32x4(Register lane0, Register lane1, Register lane2,
Register lane3, FloatRegister dest);
void createFloat32x4(FloatRegister lane0, FloatRegister lane1,
FloatRegister lane2, FloatRegister lane3,
FloatRegister temp, FloatRegister output);
void splatX16(Register input, FloatRegister output);
void splatX8(Register input, FloatRegister output);
void splatX4(Register input, FloatRegister output);
void splatX4(FloatRegister input, FloatRegister output);
void reinterpretSimd(bool isIntegerLaneType, FloatRegister input,
FloatRegister output);
void extractLaneInt32x4(FloatRegister input, Register output, unsigned lane);
void extractLaneFloat32x4(FloatRegister input, FloatRegister output,
unsigned lane, bool canonicalize);
void extractLaneInt16x8(FloatRegister input, Register output, unsigned lane,
SimdSign sign);
void extractLaneInt8x16(FloatRegister input, Register output, unsigned lane,
SimdSign sign);
void extractLaneSimdBool(FloatRegister input, Register output,
unsigned numLanes, unsigned lane);
void insertLaneSimdInt(FloatRegister input, Register value,
FloatRegister output, unsigned lane,
unsigned numLanes);
void insertLaneFloat32x4(FloatRegister input, FloatRegister value,
FloatRegister output, unsigned lane);
void allTrueSimdBool(FloatRegister input, Register output);
void anyTrueSimdBool(FloatRegister input, Register output);
void swizzleInt32x4(FloatRegister input, FloatRegister output,
unsigned lanes[4]);
void swizzleFloat32x4(FloatRegister input, FloatRegister output,
unsigned lanes[4]);
void swizzleInt8x16(FloatRegister input, FloatRegister output,
const mozilla::Maybe<Register>& temp, int8_t lanes[16]);
void shuffleX4(FloatRegister lhs, Operand rhs, FloatRegister out,
const mozilla::Maybe<FloatRegister>& maybeTemp,
unsigned lanes[4]);
void shuffleInt8x16(FloatRegister lhs, FloatRegister rhs,
FloatRegister output,
const mozilla::Maybe<FloatRegister>& maybeFloatTemp,
const mozilla::Maybe<Register>& maybeTemp,
uint8_t lanes[16]);
void compareInt8x16(FloatRegister lhs, Operand rhs, Assembler::Condition cond,
FloatRegister output);
void compareInt16x8(FloatRegister lhs, Operand rhs, Assembler::Condition cond,
FloatRegister output);
void compareInt32x4(FloatRegister lhs, Operand rhs, Assembler::Condition cond,
FloatRegister output);
void compareFloat32x4(FloatRegister lhs, Operand rhs,
Assembler::Condition cond, FloatRegister output);
void addInt8x16(FloatRegister lhs, Operand rhs, FloatRegister output) {
vpaddb(rhs, lhs, output);
}
void addInt16x8(FloatRegister lhs, Operand rhs, FloatRegister output) {
vpaddw(rhs, lhs, output);
}
void addInt32x4(FloatRegister lhs, Operand rhs, FloatRegister output) {
vpaddd(rhs, lhs, output);
}
void addFloat32x4(FloatRegister lhs, Operand rhs, FloatRegister output) {
vaddps(rhs, lhs, output);
}
void addSatInt8x16(FloatRegister lhs, Operand rhs, SimdSign sign,
FloatRegister output) {
if (sign == SimdSign::Signed) {
vpaddsb(rhs, lhs, output);
} else {
vpaddusb(rhs, lhs, output);
}
}
void addSatInt16x8(FloatRegister lhs, Operand rhs, SimdSign sign,
FloatRegister output) {
if (sign == SimdSign::Signed) {
vpaddsw(rhs, lhs, output);
} else {
vpaddusw(rhs, lhs, output);
}
}
void subInt8x16(FloatRegister lhs, Operand rhs, FloatRegister output) {
vpsubb(rhs, lhs, output);
}
void subInt16x8(FloatRegister lhs, Operand rhs, FloatRegister output) {
vpsubw(rhs, lhs, output);
}
void subInt32x4(FloatRegister lhs, Operand rhs, FloatRegister output) {
vpsubd(rhs, lhs, output);
}
void subFloat32x4(FloatRegister lhs, Operand rhs, FloatRegister output) {
vsubps(rhs, lhs, output);
}
void subSatInt8x16(FloatRegister lhs, Operand rhs, SimdSign sign,
FloatRegister output) {
if (sign == SimdSign::Signed) {
vpsubsb(rhs, lhs, output);
} else {
vpsubusb(rhs, lhs, output);
}
}
void subSatInt16x8(FloatRegister lhs, Operand rhs, SimdSign sign,
FloatRegister output) {
if (sign == SimdSign::Signed) {
vpsubsw(rhs, lhs, output);
} else {
vpsubusw(rhs, lhs, output);
}
}
void mulInt16x8(FloatRegister lhs, Operand rhs, FloatRegister output) {
vpmullw(rhs, lhs, output);
}
void mulInt32x4(FloatRegister lhs, Operand rhs,
const mozilla::Maybe<FloatRegister>& temp,
FloatRegister output);
void mulFloat32x4(FloatRegister lhs, Operand rhs, FloatRegister output) {
vmulps(rhs, lhs, output);
}
void negInt8x16(Operand in, FloatRegister out) {
zeroSimd128Int(out);
packedSubInt8(in, out);
}
void negInt16x8(Operand in, FloatRegister out) {
zeroSimd128Int(out);
packedSubInt16(in, out);
}
void negInt32x4(Operand in, FloatRegister out) {
zeroSimd128Int(out);
packedSubInt32(in, out);
}
void negFloat32x4(Operand in, FloatRegister out);
void notInt8x16(Operand in, FloatRegister out);
void notInt16x8(Operand in, FloatRegister out);
void notInt32x4(Operand in, FloatRegister out);
void notFloat32x4(Operand in, FloatRegister out);
void divFloat32x4(FloatRegister lhs, Operand rhs, FloatRegister output) {
vdivps(rhs, lhs, output);
}
void minFloat32x4(FloatRegister lhs, Operand rhs, FloatRegister output);
void maxFloat32x4(FloatRegister lhs, Operand rhs, FloatRegister temp,
FloatRegister output);
void minNumFloat32x4(FloatRegister lhs, Operand rhs, FloatRegister temp,
FloatRegister output);
void maxNumFloat32x4(FloatRegister lhs, Operand rhs, FloatRegister temp,
FloatRegister output);
void absFloat32x4(Operand in, FloatRegister out);
void bitwiseAndFloat32x4(FloatRegister lhs, const Operand& rhs,
FloatRegister dest) {
vandps(rhs, lhs, dest);
}
void bitwiseAndSimdInt(FloatRegister lhs, const Operand& rhs,
FloatRegister dest) {
vpand(rhs, lhs, dest);
}
void bitwiseOrFloat32x4(FloatRegister lhs, const Operand& rhs,
FloatRegister dest) {
vorps(rhs, lhs, dest);
}
void bitwiseOrSimdInt(FloatRegister lhs, const Operand& rhs,
FloatRegister dest) {
vpor(rhs, lhs, dest);
}
void bitwiseXorFloat32x4(FloatRegister lhs, const Operand& rhs,
FloatRegister dest) {
vxorps(rhs, lhs, dest);
}
void bitwiseXorSimdInt(FloatRegister lhs, const Operand& rhs,
FloatRegister dest) {
vpxor(rhs, lhs, dest);
}
void bitwiseAndNotFloat32x4(FloatRegister lhs, const Operand& rhs,
FloatRegister dest) {
vandnps(rhs, lhs, dest);
}
void bitwiseAndNotSimdInt(FloatRegister lhs, const Operand& rhs,
FloatRegister dest) {
vpandn(rhs, lhs, dest);
}
void zeroSimd128Float(FloatRegister dest) { vxorps(dest, dest, dest); }
void zeroSimd128Int(FloatRegister dest) { vpxor(dest, dest, dest); }
void selectSimd128(FloatRegister mask, FloatRegister onTrue,
FloatRegister onFalse, FloatRegister temp,
FloatRegister output);
void selectX4(FloatRegister mask, FloatRegister onTrue, FloatRegister onFalse,
FloatRegister temp, FloatRegister output) {
if (AssemblerX86Shared::HasAVX()) {
vblendvps(mask, onTrue, onFalse, output);
} else {
selectSimd128(mask, onTrue, onFalse, temp, output);
}
}
template <class T, class Reg>
inline void loadScalar(const Operand& src, Reg dest);
template <class T, class Reg>
inline void storeScalar(Reg src, const Address& dest);
template <class T>
inline void loadAlignedVector(const Address& src, FloatRegister dest);
template <class T>
inline void storeAlignedVector(FloatRegister src, const Address& dest);
void loadAlignedSimd128Int(const Address& src, FloatRegister dest) {
vmovdqa(Operand(src), dest);
}
void loadAlignedSimd128Int(const Operand& src, FloatRegister dest) {
vmovdqa(src, dest);
}
void storeAlignedSimd128Int(FloatRegister src, const Address& dest) {
vmovdqa(src, Operand(dest));
}
void moveSimd128Int(FloatRegister src, FloatRegister dest) {
vmovdqa(src, dest);
}
FloatRegister reusedInputInt32x4(FloatRegister src, FloatRegister dest) {
if (HasAVX()) {
return src;
}
moveSimd128Int(src, dest);
return dest;
}
FloatRegister reusedInputAlignedInt32x4(const Operand& src,
FloatRegister dest) {
if (HasAVX() && src.kind() == Operand::FPREG) {
return FloatRegister::FromCode(src.fpu());
}
loadAlignedSimd128Int(src, dest);
return dest;
}
void loadUnalignedSimd128Int(const Address& src, FloatRegister dest) {
vmovdqu(Operand(src), dest);
}
void loadUnalignedSimd128Int(const BaseIndex& src, FloatRegister dest) {
vmovdqu(Operand(src), dest);
}
void loadUnalignedSimd128Int(const Operand& src, FloatRegister dest) {
vmovdqu(src, dest);
}
void storeUnalignedSimd128Int(FloatRegister src, const Address& dest) {
vmovdqu(src, Operand(dest));
}
void storeUnalignedSimd128Int(FloatRegister src, const BaseIndex& dest) {
vmovdqu(src, Operand(dest));
}
void storeUnalignedSimd128Int(FloatRegister src, const Operand& dest) {
vmovdqu(src, dest);
}
void packedEqualInt32x4(const Operand& src, FloatRegister dest) {
vpcmpeqd(src, dest, dest);
}
void packedGreaterThanInt32x4(const Operand& src, FloatRegister dest) {
vpcmpgtd(src, dest, dest);
}
void packedAddInt8(const Operand& src, FloatRegister dest) {
vpaddb(src, dest, dest);
}
void packedSubInt8(const Operand& src, FloatRegister dest) {
vpsubb(src, dest, dest);
}
void packedAddInt16(const Operand& src, FloatRegister dest) {
vpaddw(src, dest, dest);
}
void packedSubInt16(const Operand& src, FloatRegister dest) {
vpsubw(src, dest, dest);
}
void packedAddInt32(const Operand& src, FloatRegister dest) {
vpaddd(src, dest, dest);
}
void packedSubInt32(const Operand& src, FloatRegister dest) {
vpsubd(src, dest, dest);
}
void packedRcpApproximationFloat32x4(const Operand& src, FloatRegister dest) {
vrcpps(src, dest);
}
void packedRcpSqrtApproximationFloat32x4(const Operand& src,
FloatRegister dest) {
vrsqrtps(src, dest);
}
void packedSqrtFloat32x4(const Operand& src, FloatRegister dest) {
vsqrtps(src, dest);
}
public:
void packedLeftShiftByScalarInt16x8(FloatRegister in, Register count,
Register temp, FloatRegister dest);
void packedRightShiftByScalarInt16x8(FloatRegister in, Register count,
Register temp, FloatRegister dest);
void packedUnsignedRightShiftByScalarInt16x8(FloatRegister in, Register count,
Register temp,
FloatRegister dest);
void packedLeftShiftByScalarInt16x8(Imm32 count, FloatRegister dest) {
count.value &= 15;
vpsllw(count, dest, dest);
}
void packedRightShiftByScalarInt16x8(Imm32 count, FloatRegister dest) {
count.value &= 15;
vpsraw(count, dest, dest);
}
void packedUnsignedRightShiftByScalarInt16x8(Imm32 count,
FloatRegister dest) {
count.value &= 15;
vpsrlw(count, dest, dest);
}
void packedLeftShiftByScalarInt32x4(FloatRegister in, Register count,
Register temp, FloatRegister dest);
void packedRightShiftByScalarInt32x4(FloatRegister in, Register count,
Register temp, FloatRegister dest);
void packedUnsignedRightShiftByScalarInt32x4(FloatRegister in, Register count,
Register temp,
FloatRegister dest);
void packedLeftShiftByScalarInt32x4(Imm32 count, FloatRegister dest) {
count.value &= 31;
vpslld(count, dest, dest);
}
void packedRightShiftByScalarInt32x4(Imm32 count, FloatRegister dest) {
count.value &= 31;
vpsrad(count, dest, dest);
}
void packedUnsignedRightShiftByScalarInt32x4(Imm32 count,
FloatRegister dest) {
count.value &= 31;
vpsrld(count, dest, dest);
}
void loadAlignedSimd128Float(const Address& src, FloatRegister dest) {
vmovaps(Operand(src), dest);
}
void loadAlignedSimd128Float(const Operand& src, FloatRegister dest) {
vmovaps(src, dest);
}
void storeAlignedSimd128Float(FloatRegister src, const Address& dest) {
vmovaps(src, Operand(dest));
}
void moveSimd128Float(FloatRegister src, FloatRegister dest) {
vmovaps(src, dest);
}
FloatRegister reusedInputFloat32x4(FloatRegister src, FloatRegister dest) {
if (HasAVX()) {
return src;
}
moveSimd128Float(src, dest);
return dest;
}
FloatRegister reusedInputAlignedFloat32x4(const Operand& src,
FloatRegister dest) {
if (HasAVX() && src.kind() == Operand::FPREG) {
return FloatRegister::FromCode(src.fpu());
}
loadAlignedSimd128Float(src, dest);
return dest;
}
void loadUnalignedSimd128Float(const Address& src, FloatRegister dest) {
vmovups(Operand(src), dest);
}
void loadUnalignedSimd128Float(const BaseIndex& src, FloatRegister dest) {
vmovdqu(Operand(src), dest);
}
void loadUnalignedSimd128Float(const Operand& src, FloatRegister dest) {
vmovups(src, dest);
}
void storeUnalignedSimd128Float(FloatRegister src, const Address& dest) {
vmovups(src, Operand(dest));
}
void storeUnalignedSimd128Float(FloatRegister src, const BaseIndex& dest) {
vmovups(src, Operand(dest));
}
void storeUnalignedSimd128Float(FloatRegister src, const Operand& dest) {
vmovups(src, dest);
}
void packedAddFloat32(const Operand& src, FloatRegister dest) {
vaddps(src, dest, dest);
}
void packedSubFloat32(const Operand& src, FloatRegister dest) {
vsubps(src, dest, dest);
}
void packedMulFloat32(const Operand& src, FloatRegister dest) {
vmulps(src, dest, dest);
}
void packedDivFloat32(const Operand& src, FloatRegister dest) {
vdivps(src, dest, dest);
}
static uint32_t ComputeShuffleMask(uint32_t x = 0, uint32_t y = 1,
uint32_t z = 2, uint32_t w = 3) {
MOZ_ASSERT(x < 4 && y < 4 && z < 4 && w < 4);
uint32_t r = (w << 6) | (z << 4) | (y << 2) | (x << 0);
MOZ_ASSERT(r < 256);
return r;
}
void shuffleInt32(uint32_t mask, FloatRegister src, FloatRegister dest) {
vpshufd(mask, src, dest);
}
void moveLowInt32(FloatRegister src, Register dest) { vmovd(src, dest); }
void moveHighPairToLowPairFloat32(FloatRegister src, FloatRegister dest) {
vmovhlps(src, dest, dest);
}
void shuffleFloat32(uint32_t mask, FloatRegister src, FloatRegister dest) {
FloatRegister srcCopy = reusedInputFloat32x4(src, dest);
vshufps(mask, srcCopy, srcCopy, dest);
}
void shuffleMix(uint32_t mask, const Operand& src, FloatRegister dest) {
vshufps(mask, src, dest, dest);
}
void moveFloatAsDouble(Register src, FloatRegister dest) {
vmovd(src, dest);
vcvtss2sd(dest, dest, dest);
}
void loadFloatAsDouble(const Address& src, FloatRegister dest) {
vmovss(src, dest);
vcvtss2sd(dest, dest, dest);
}
void loadFloatAsDouble(const BaseIndex& src, FloatRegister dest) {
vmovss(src, dest);
vcvtss2sd(dest, dest, dest);
}
void loadFloatAsDouble(const Operand& src, FloatRegister dest) {
loadFloat32(src, dest);
vcvtss2sd(dest, dest, dest);
}
void loadFloat32(const Address& src, FloatRegister dest) {
vmovss(src, dest);
}
void loadFloat32(const BaseIndex& src, FloatRegister dest) {
vmovss(src, dest);
}
void loadFloat32(const Operand& src, FloatRegister dest) {
switch (src.kind()) {
case Operand::MEM_REG_DISP:
loadFloat32(src.toAddress(), dest);
break;
case Operand::MEM_SCALE:
loadFloat32(src.toBaseIndex(), dest);
break;
default:
MOZ_CRASH("unexpected operand kind");
}
}
void moveFloat32(FloatRegister src, FloatRegister dest) {
vmovaps(src, dest);
}
void convertDoubleToInt32(FloatRegister src, Register dest, Label* fail,
bool negativeZeroCheck = true) {
if (negativeZeroCheck) {
branchNegativeZero(src, dest, fail);
}
ScratchDoubleScope scratch(asMasm());
vcvttsd2si(src, dest);
convertInt32ToDouble(dest, scratch);
vucomisd(scratch, src);
j(Assembler::Parity, fail);
j(Assembler::NotEqual, fail);
}
void convertFloat32ToInt32(FloatRegister src, Register dest, Label* fail,
bool negativeZeroCheck = true) {
if (negativeZeroCheck) {
branchNegativeZeroFloat32(src, dest, fail);
}
ScratchFloat32Scope scratch(asMasm());
vcvttss2si(src, dest);
convertInt32ToFloat32(dest, scratch);
vucomiss(scratch, src);
j(Assembler::Parity, fail);
j(Assembler::NotEqual, fail);
}
inline void clampIntToUint8(Register reg);
bool maybeInlineDouble(double d, FloatRegister dest) {
if (mozilla::IsPositiveZero(d)) {
zeroDouble(dest);
return true;
}
return false;
}
bool maybeInlineFloat(float f, FloatRegister dest) {
if (mozilla::IsPositiveZero(f)) {
zeroFloat32(dest);
return true;
}
return false;
}
bool maybeInlineSimd128Int(const SimdConstant& v, const FloatRegister& dest) {
static const SimdConstant zero = SimdConstant::SplatX4(0);
static const SimdConstant minusOne = SimdConstant::SplatX4(-1);
if (v == zero) {
zeroSimd128Int(dest);
return true;
}
if (v == minusOne) {
vpcmpeqw(Operand(dest), dest, dest);
return true;
}
return false;
}
bool maybeInlineSimd128Float(const SimdConstant& v,
const FloatRegister& dest) {
static const SimdConstant zero = SimdConstant::SplatX4(0.f);
if (v == zero) {
zeroSimd128Float(dest);
return true;
}
return false;
}
void convertBoolToInt32(Register source, Register dest) {
movzbl(source, dest);
}
void emitSet(Assembler::Condition cond, Register dest,
Assembler::NaNCond ifNaN = Assembler::NaN_HandledByCond) {
if (AllocatableGeneralRegisterSet(Registers::SingleByteRegs).has(dest)) {
setCC(cond, dest);
movzbl(dest, dest);
if (ifNaN != Assembler::NaN_HandledByCond) {
Label noNaN;
j(Assembler::NoParity, &noNaN);
mov(ImmWord(ifNaN == Assembler::NaN_IsTrue), dest);
bind(&noNaN);
}
} else {
Label end;
Label ifFalse;
if (ifNaN == Assembler::NaN_IsFalse) {
j(Assembler::Parity, &ifFalse);
}
movl(Imm32(1), dest);
j(cond, &end);
if (ifNaN == Assembler::NaN_IsTrue) {
j(Assembler::Parity, &end);
}
bind(&ifFalse);
mov(ImmWord(0), dest);
bind(&end);
}
}
CodeOffset toggledJump(Label* label) {
CodeOffset offset(size());
jump(label);
return offset;
}
template <typename T>
void computeEffectiveAddress(const T& address, Register dest) {
lea(Operand(address), dest);
}
void checkStackAlignment() {
}
CodeOffset labelForPatch() { return CodeOffset(size()); }
void abiret() { ret(); }
protected:
bool buildOOLFakeExitFrame(void* fakeReturnAddr);
};
template <>
inline void MacroAssemblerX86Shared::loadAlignedVector<float>(
const Address& src, FloatRegister dest) {
loadAlignedSimd128Float(src, dest);
}
template <typename T>
inline void MacroAssemblerX86Shared::loadAlignedVector(const Address& src,
FloatRegister dest) {
loadAlignedSimd128Int(src, dest);
}
template <>
inline void MacroAssemblerX86Shared::storeAlignedVector<float>(
FloatRegister src, const Address& dest) {
storeAlignedSimd128Float(src, dest);
}
template <typename T>
inline void MacroAssemblerX86Shared::storeAlignedVector(FloatRegister src,
const Address& dest) {
storeAlignedSimd128Int(src, dest);
}
template <>
inline void MacroAssemblerX86Shared::loadScalar<int8_t>(const Operand& src,
Register dest) {
load8ZeroExtend(src, dest);
}
template <>
inline void MacroAssemblerX86Shared::loadScalar<int16_t>(const Operand& src,
Register dest) {
load16ZeroExtend(src, dest);
}
template <>
inline void MacroAssemblerX86Shared::loadScalar<int32_t>(const Operand& src,
Register dest) {
load32(src, dest);
}
template <>
inline void MacroAssemblerX86Shared::loadScalar<float>(const Operand& src,
FloatRegister dest) {
loadFloat32(src, dest);
}
template <>
inline void MacroAssemblerX86Shared::storeScalar<int8_t>(Register src,
const Address& dest) {
store8(src, dest);
}
template <>
inline void MacroAssemblerX86Shared::storeScalar<int16_t>(Register src,
const Address& dest) {
store16(src, dest);
}
template <>
inline void MacroAssemblerX86Shared::storeScalar<int32_t>(Register src,
const Address& dest) {
store32(src, dest);
}
template <>
inline void MacroAssemblerX86Shared::storeScalar<float>(FloatRegister src,
const Address& dest) {
vmovss(src, dest);
}
} }
#endif