Operand holder / fix memory corruption

This commit is contained in:
Lander Gallastegi 2025-04-07 21:18:30 +02:00
parent 46e2cbd2ab
commit f18971022d
15 changed files with 557 additions and 493 deletions

View file

@ -22,12 +22,12 @@ static void EmitCondition(EmitContext& ctx, const IR::Inst* ref, Label& label, b
ctx.Code().jmp(label);
}
} else {
const Operand& op = ctx.Def(cond.InstRecursive())[0];
if (op.isREG()) {
Reg8 reg = op.getReg().cvt8();
const OperandHolder& op = ctx.Def(cond.InstRecursive())[0];
if (op.IsReg()) {
Reg8 reg = op.Reg().cvt8();
ctx.Code().test(reg, reg);
} else {
ctx.Code().test(op, 0xff);
ctx.Code().test(op.Mem(), 0xff);
}
if (invert) {
ctx.Code().jz(label);

View file

@ -16,23 +16,23 @@ void EmitBitCastU16F16(EmitContext& ctx, const Operands& dest, const Operands& s
}
void EmitBitCastU32F32(EmitContext& ctx, const Operands& dest, const Operands& src) {
if (src[0].isMEM()) {
if (src[0].IsMem()) {
MovGP(ctx, dest[0], src[0]);
} else if (dest[0].isMEM()) {
ctx.Code().movd(dest[0].getAddress(), src[0].getReg().cvt128());
} else if (dest[0].IsMem()) {
ctx.Code().movd(dest[0].Mem(), src[0].Xmm());
} else {
ctx.Code().movd(dword[rsp - 4], src[0].getReg().cvt128());
ctx.Code().movd(dword[rsp - 4], src[0].Xmm());
MovGP(ctx, dest[0], dword[rsp - 4]);
}
}
void EmitBitCastU64F64(EmitContext& ctx, const Operands& dest, const Operands& src) {
if (src[0].isMEM()) {
if (src[0].IsMem()) {
MovGP(ctx, dest[0], src[0]);
} else if (dest[0].isMEM()) {
ctx.Code().movq(dest[0].getAddress(), src[0].getReg().cvt128());
} else if (dest[0].IsMem()) {
ctx.Code().movq(dest[0].Mem(), src[0].Xmm());
} else {
ctx.Code().movq(qword[rsp - 8], src[0].getReg().cvt128());
ctx.Code().movq(qword[rsp - 8], src[0].Xmm());
MovGP(ctx, dest[0], qword[rsp - 8]);
}
}
@ -42,40 +42,40 @@ void EmitBitCastF16U16(EmitContext& ctx, const Operands& dest, const Operands& s
}
void EmitBitCastF32U32(EmitContext& ctx, const Operands& dest, const Operands& src) {
if (dest[0].isMEM()) {
if (dest[0].IsMem()) {
MovGP(ctx, dest[0], src[0]);
} else if (src[0].isMEM()) {
ctx.Code().movd(dest[0].getReg().cvt128(), src[0].getAddress());
} else if (src[0].IsMem()) {
ctx.Code().movd(dest[0].Xmm(), src[0].Mem());
} else {
MovGP(ctx, dword[rsp - 4], src[0]);
ctx.Code().movd(dest[0].getReg().cvt128(), dword[rsp - 4]);
ctx.Code().movd(dest[0].Xmm(), dword[rsp - 4]);
}
}
void EmitBitCastF64U64(EmitContext& ctx, const Operands& dest, const Operands& src) {
if (dest[0].isMEM()) {
if (dest[0].IsMem()) {
MovGP(ctx, dest[0], src[0]);
} else if (src[0].isMEM()) {
ctx.Code().movq(dest[0].getReg().cvt128(), src[0].getAddress());
} else if (src[0].IsMem()) {
ctx.Code().movq(dest[0].Xmm(), src[0].Mem());
} else {
MovGP(ctx, qword[rsp - 8], src[0]);
ctx.Code().mov(dest[0].getReg().cvt128(), qword[rsp - 8]);
ctx.Code().mov(dest[0].Xmm(), qword[rsp - 8]);
}
}
void EmitPackUint2x32(EmitContext& ctx, const Operands& dest, const Operands& src) {
const bool is_mem = dest[0].isMEM() && (src[0].isMEM() || src[1].isMEM());
Reg tmp = is_mem ? ctx.TempGPReg() : dest[0].getReg();
const bool is_mem = dest[0].IsMem() && (src[0].IsMem() || src[1].IsMem());
Reg tmp = is_mem ? ctx.TempGPReg() : dest[0].Reg();
MovGP(ctx, tmp, src[1]);
ctx.Code().shl(tmp, 32);
ctx.Code().or_(tmp, src[0]);
ctx.Code().or_(tmp, src[0].Op());
MovGP(ctx, dest[0], tmp);
}
void EmitUnpackUint2x32(EmitContext& ctx, const Operands& dest, const Operands& src) {
Reg src0 = src[0].isMEM() ? ctx.TempGPReg() : src[0].getReg();
Reg src0 = src[0].IsMem() ? ctx.TempGPReg() : src[0].Reg();
MovGP(ctx, src0, src[0]);
Reg dest1 = dest[1].isMEM() ? ctx.TempGPReg() : dest[1].getReg().changeBit(64);
Reg dest1 = dest[1].IsMem() ? ctx.TempGPReg() : dest[1].Reg().changeBit(64);
MovGP(ctx, dest1, src0);
ctx.Code().shr(dest1, 32);
MovGP(ctx, dest[1], dest1);
@ -83,9 +83,9 @@ void EmitUnpackUint2x32(EmitContext& ctx, const Operands& dest, const Operands&
}
void EmitPackFloat2x32(EmitContext& ctx, const Operands& dest, const Operands& src) {
Xmm tmp = dest[0].isMEM() ? ctx.TempXmmReg() : dest[0].getReg().cvt128();
Xmm tmp = dest[0].IsMem() ? ctx.TempXmmReg() : dest[0].Xmm();
MovFloat(ctx, tmp, src[0]);
ctx.Code().pinsrd(tmp, src[1], 1);
ctx.Code().pinsrd(tmp, src[1].Op(), 1);
MovFloat(ctx, dest[0], tmp);
}

View file

@ -12,7 +12,7 @@ using namespace Xbyak::util;
namespace {
template <u32 N>
static const Operand& GetSuffleOperand(const Operands& comp1, const Operands& comp2, u32 index) {
static const OperandHolder& GetSuffleOperand(const Operands& comp1, const Operands& comp2, u32 index) {
if (index < N) {
return comp1[index];
} else {

View file

@ -61,11 +61,11 @@ void EmitReadConst(EmitContext& ctx, const Operands& dest, const Operands& base,
Reg& tmp = ctx.TempGPReg();
MovGP(ctx, tmp, base[1]);
ctx.Code().shl(tmp, 32);
ctx.Code().or_(tmp, base[0]);
if (offset[0].isMEM()) {
ctx.Code().add(tmp, offset[0]);
ctx.Code().or_(tmp, base[0].Op());
if (offset[0].IsMem()) {
ctx.Code().add(tmp, offset[0].Mem());
} else {
ctx.Code().lea(tmp, ptr[tmp + offset[0].getReg().cvt64()]);
ctx.Code().lea(tmp, ptr[tmp + offset[0].Reg().cvt64()]);
}
MovGP(ctx, dest[0], dword[tmp]);
}

View file

@ -11,64 +11,64 @@ using namespace Xbyak::util;
void EmitConvertS16F16(EmitContext& ctx, const Operands& dest, const Operands& src) {
Xmm tmp_xmm = ctx.TempXmmReg();
Reg tmp_reg = dest[0].isMEM() ? ctx.TempGPReg().cvt32() : dest[0].getReg().cvt32();
EmitInlineF16ToF32(ctx, tmp_xmm, src[0]);
Reg tmp_reg = dest[0].IsMem() ? ctx.TempGPReg().cvt32() : dest[0].Reg().cvt32();
EmitInlineF16ToF32(ctx, tmp_xmm, src[0].Op());
ctx.Code().cvttss2si(tmp_reg, tmp_xmm);
ctx.Code().and_(tmp_reg, 0xFFFF);
MovGP(ctx, dest[0], tmp_reg);
}
void EmitConvertS16F32(EmitContext& ctx, const Operands& dest, const Operands& src) {
Reg tmp = dest[0].isMEM() ? ctx.TempGPReg().cvt32() : dest[0].getReg().cvt32();
ctx.Code().cvttss2si(tmp, src[0]);
Reg tmp = dest[0].IsMem() ? ctx.TempGPReg().cvt32() : dest[0].Reg().cvt32();
ctx.Code().cvttss2si(tmp, src[0].Op());
ctx.Code().and_(tmp, 0xFFFF);
MovGP(ctx, dest[0], tmp);
}
void EmitConvertS16F64(EmitContext& ctx, const Operands& dest, const Operands& src) {
Reg tmp = dest[0].isMEM() ? ctx.TempGPReg().cvt32() : dest[0].getReg().cvt32();
ctx.Code().cvttsd2si(tmp, src[0]);
Reg tmp = dest[0].IsMem() ? ctx.TempGPReg().cvt32() : dest[0].Reg().cvt32();
ctx.Code().cvttsd2si(tmp, src[0].Op());
ctx.Code().and_(tmp, 0xFFFF);
MovGP(ctx, dest[0], tmp);
}
void EmitConvertS32F16(EmitContext& ctx, const Operands& dest, const Operands& src) {
Xmm tmp_xmm = ctx.TempXmmReg();
Reg tmp_reg = dest[0].isMEM() ? ctx.TempGPReg().cvt32() : dest[0].getReg().cvt32();
EmitInlineF16ToF32(ctx, tmp_xmm, src[0]);
Reg tmp_reg = dest[0].IsMem() ? ctx.TempGPReg().cvt32() : dest[0].Reg();
EmitInlineF16ToF32(ctx, tmp_xmm, src[0].Op());
ctx.Code().cvttss2si(tmp_reg, tmp_xmm);
MovGP(ctx, dest[0], tmp_reg);
}
void EmitConvertS32F32(EmitContext& ctx, const Operands& dest, const Operands& src) {
Reg tmp = dest[0].isMEM() ? ctx.TempGPReg().cvt32() : dest[0].getReg().cvt32();
ctx.Code().cvttss2si(tmp, src[0]);
Reg tmp = dest[0].IsMem() ? ctx.TempGPReg().cvt32() : dest[0].Reg();
ctx.Code().cvttss2si(tmp, src[0].Op());
MovGP(ctx, dest[0], tmp);
}
void EmitConvertS32F64(EmitContext& ctx, const Operands& dest, const Operands& src) {
Reg tmp = dest[0].isMEM() ? ctx.TempGPReg().cvt32() : dest[0].getReg().cvt32();
ctx.Code().cvttsd2si(tmp, src[0]);
Reg tmp = dest[0].IsMem() ? ctx.TempGPReg().cvt32() : dest[0].Reg();
ctx.Code().cvttsd2si(tmp, src[0].Op());
MovGP(ctx, dest[0], tmp);
}
void EmitConvertS64F16(EmitContext& ctx, const Operands& dest, const Operands& src) {
Xmm tmp_xmm = ctx.TempXmmReg();
Reg tmp_reg = dest[0].isMEM() ? ctx.TempGPReg() : dest[0].getReg();
EmitInlineF16ToF32(ctx, tmp_xmm, src[0]);
Reg tmp_reg = dest[0].IsMem() ? ctx.TempGPReg() : dest[0].Reg();
EmitInlineF16ToF32(ctx, tmp_xmm, src[0].Op());
ctx.Code().cvttss2si(tmp_reg, tmp_xmm);
MovGP(ctx, dest[0], tmp_reg);
}
void EmitConvertS64F32(EmitContext& ctx, const Operands& dest, const Operands& src) {
Reg tmp = dest[0].isMEM() ? ctx.TempGPReg() : dest[0].getReg();
ctx.Code().cvttss2si(tmp, src[0]);
Reg tmp = dest[0].IsMem() ? ctx.TempGPReg() : dest[0].Reg();
ctx.Code().cvttss2si(tmp, src[0].Op());
MovGP(ctx, dest[0], tmp);
}
void EmitConvertS64F64(EmitContext& ctx, const Operands& dest, const Operands& src) {
Reg tmp = dest[0].isMEM() ? ctx.TempGPReg() : dest[0].getReg();
ctx.Code().cvttsd2si(tmp, src[0]);
Reg tmp = dest[0].IsMem() ? ctx.TempGPReg() : dest[0].Reg();
ctx.Code().cvttsd2si(tmp, src[0].Op());
MovGP(ctx, dest[0], tmp);
}
@ -117,51 +117,51 @@ void EmitConvertU32U64(EmitContext& ctx, const Operands& dest, const Operands& s
}
void EmitConvertF16F32(EmitContext& ctx, const Operands& dest, const Operands& src) {
EmitInlineF32ToF16(ctx, dest[0], src[0]);
EmitInlineF32ToF16(ctx, dest[0].Op(), src[0].Op());
}
void EmitConvertF32F16(EmitContext& ctx, const Operands& dest, const Operands& src) {
EmitInlineF16ToF32(ctx, dest[0], src[0]);
EmitInlineF16ToF32(ctx, dest[0].Op(), src[0].Op());
}
void EmitConvertF32F64(EmitContext& ctx, const Operands& dest, const Operands& src) {
Xmm tmp = dest[0].isMEM() ? ctx.TempXmmReg() : dest[0].getReg().cvt128();
ctx.Code().cvtsd2ss(tmp, src[0]);
Xmm tmp = dest[0].IsMem() ? ctx.TempXmmReg() : dest[0].Xmm();
ctx.Code().cvtsd2ss(tmp, src[0].Op());
MovFloat(ctx, dest[0], tmp);
}
void EmitConvertF64F32(EmitContext& ctx, const Operands& dest, const Operands& src) {
Xmm tmp = dest[0].isMEM() ? ctx.TempXmmReg() : dest[0].getReg().cvt128();
ctx.Code().cvtss2sd(tmp, src[0]);
Xmm tmp = dest[0].IsMem() ? ctx.TempXmmReg() : dest[0].Xmm();
ctx.Code().cvtss2sd(tmp, src[0].Op());
MovDouble(ctx, dest[0], tmp);
}
void EmitConvertF16S8(EmitContext& ctx, const Operands& dest, const Operands& src) {
Reg tmp_reg = dest[0].isMEM() ? ctx.TempGPReg().cvt32() : dest[0].getReg().cvt32();
Reg tmp_reg = dest[0].IsMem() ? ctx.TempGPReg().cvt32() : dest[0].Reg().cvt32();
Xmm tmp_xmm = ctx.TempXmmReg();
ctx.Code().movsx(tmp_reg, src[0]);
MovGP(ctx, tmp_reg, src[0]);
ctx.Code().cvtsi2ss(tmp_xmm, tmp_reg);
EmitInlineF32ToF16(ctx, dest[0], tmp_xmm);
EmitInlineF32ToF16(ctx, dest[0].Op(), tmp_xmm);
}
void EmitConvertF16S16(EmitContext& ctx, const Operands& dest, const Operands& src) {
Reg tmp_reg = dest[0].isMEM() ? ctx.TempGPReg().cvt32() : dest[0].getReg().cvt32();
Reg tmp_reg = dest[0].IsMem() ? ctx.TempGPReg().cvt32() : dest[0].Reg().cvt32();
Xmm tmp_xmm = ctx.TempXmmReg();
ctx.Code().movsx(tmp_reg, src[0]);
MovGP(ctx, tmp_reg, src[0]);
ctx.Code().cvtsi2ss(tmp_xmm, tmp_reg);
EmitInlineF32ToF16(ctx, dest[0], tmp_xmm);
EmitInlineF32ToF16(ctx, dest[0].Op(), tmp_xmm);
}
void EmitConvertF16S32(EmitContext& ctx, const Operands& dest, const Operands& src) {
Xmm tmp = ctx.TempXmmReg();
ctx.Code().cvtsi2ss(tmp, src[0]);
EmitInlineF32ToF16(ctx, dest[0], tmp);
ctx.Code().cvtsi2ss(tmp, src[0].Op());
EmitInlineF32ToF16(ctx, dest[0].Op(), tmp);
}
void EmitConvertF16S64(EmitContext& ctx, const Operands& dest, const Operands& src) {
Xmm tmp = ctx.TempXmmReg();
ctx.Code().cvtsi2ss(tmp, src[0]);
EmitInlineF32ToF16(ctx, dest[0], tmp);
ctx.Code().cvtsi2ss(tmp, src[0].Op());
EmitInlineF32ToF16(ctx, dest[0].Op(), tmp);
}
void EmitConvertF16U8(EmitContext& ctx, const Operands& dest, const Operands& src) {
@ -182,29 +182,29 @@ void EmitConvertF16U64(EmitContext& ctx, const Operands& dest, const Operands& s
void EmitConvertF32S8(EmitContext& ctx, const Operands& dest, const Operands& src) {
Reg tmp_reg = ctx.TempGPReg().cvt32();
Xmm tmp_xmm = dest[0].isMEM() ? ctx.TempXmmReg() : dest[0].getReg().cvt128();
ctx.Code().movsx(tmp_reg, src[0]);
Xmm tmp_xmm = dest[0].IsMem() ? ctx.TempXmmReg() : dest[0].Xmm();
MovGP(ctx, tmp_reg, src[0]);
ctx.Code().cvtsi2ss(tmp_xmm, tmp_reg);
MovFloat(ctx, dest[0], tmp_xmm);
}
void EmitConvertF32S16(EmitContext& ctx, const Operands& dest, const Operands& src) {
Reg tmp_reg = ctx.TempGPReg().cvt32();
Xmm tmp_xmm = dest[0].isMEM() ? ctx.TempXmmReg() : dest[0].getReg().cvt128();
ctx.Code().movsx(tmp_reg, src[0]);
Xmm tmp_xmm = dest[0].IsMem() ? ctx.TempXmmReg() : dest[0].Xmm();
MovGP(ctx, tmp_reg, src[0]);
ctx.Code().cvtsi2ss(tmp_xmm, tmp_reg);
MovFloat(ctx, dest[0], tmp_xmm);
}
void EmitConvertF32S32(EmitContext& ctx, const Operands& dest, const Operands& src) {
Xmm tmp = dest[0].isMEM() ? ctx.TempXmmReg() : dest[0].getReg().cvt128();
ctx.Code().cvtsi2ss(tmp, src[0]);
Xmm tmp = dest[0].IsMem() ? ctx.TempXmmReg() : dest[0].Xmm();
ctx.Code().cvtsi2ss(tmp, src[0].Op());
MovFloat(ctx, dest[0], tmp);
}
void EmitConvertF32S64(EmitContext& ctx, const Operands& dest, const Operands& src) {
Xmm tmp = dest[0].isMEM() ? ctx.TempXmmReg() : dest[0].getReg().cvt128();
ctx.Code().cvtsi2ss(tmp, src[0]);
Xmm tmp = dest[0].IsMem() ? ctx.TempXmmReg() : dest[0].Xmm();
ctx.Code().cvtsi2ss(tmp, src[0].Op());
MovFloat(ctx, dest[0], tmp);
}
@ -226,29 +226,29 @@ void EmitConvertF32U64(EmitContext& ctx, const Operands& dest, const Operands& s
void EmitConvertF64S8(EmitContext& ctx, const Operands& dest, const Operands& src) {
Reg tmp_reg = ctx.TempGPReg().cvt32();
Xmm tmp_xmm = dest[0].isMEM() ? ctx.TempXmmReg() : dest[0].getReg().cvt128();
ctx.Code().movsx(tmp_reg, src[0]);
Xmm tmp_xmm = dest[0].IsMem() ? ctx.TempXmmReg() : dest[0].Xmm();
MovGP(ctx, tmp_reg, src[0]);
ctx.Code().cvtsi2sd(tmp_xmm, tmp_reg);
MovDouble(ctx, dest[0], tmp_xmm);
}
void EmitConvertF64S16(EmitContext& ctx, const Operands& dest, const Operands& src) {
Reg tmp_reg = ctx.TempGPReg().cvt32();
Xmm tmp_xmm = dest[0].isMEM() ? ctx.TempXmmReg() : dest[0].getReg().cvt128();
ctx.Code().movsx(tmp_reg, src[0]);
Xmm tmp_xmm = dest[0].IsMem() ? ctx.TempXmmReg() : dest[0].Xmm();
MovGP(ctx, tmp_reg, src[0]);
ctx.Code().cvtsi2sd(tmp_xmm, tmp_reg);
MovDouble(ctx, dest[0], tmp_xmm);
}
void EmitConvertF64S32(EmitContext& ctx, const Operands& dest, const Operands& src) {
Xmm tmp = dest[0].isMEM() ? ctx.TempXmmReg() : dest[0].getReg().cvt128();
ctx.Code().cvtsi2sd(tmp, src[0]);
Xmm tmp = dest[0].IsMem() ? ctx.TempXmmReg() : dest[0].Xmm();
ctx.Code().cvtsi2sd(tmp, src[0].Op());
MovDouble(ctx, dest[0], tmp);
}
void EmitConvertF64S64(EmitContext& ctx, const Operands& dest, const Operands& src) {
Xmm tmp = dest[0].isMEM() ? ctx.TempXmmReg() : dest[0].getReg().cvt128();
ctx.Code().cvtsi2sd(tmp, src[0]);
Xmm tmp = dest[0].IsMem() ? ctx.TempXmmReg() : dest[0].Xmm();
ctx.Code().cvtsi2sd(tmp, src[0].Op());
MovDouble(ctx, dest[0], tmp);
}

View file

@ -13,57 +13,55 @@ using namespace Xbyak::util;
void EmitFPAbs16(EmitContext& ctx, const Operands& dest, const Operands& src) {
Reg tmp = dest[0].isMEM() ? ctx.TempGPReg().cvt16() : dest[0].getReg().cvt16();
MovGP(ctx, tmp, src[0]);
ctx.Code().and_(tmp, 0x7FFF);
MovGP(ctx, dest[0], tmp);
MovGP(ctx, dest[0], src[0]);
ctx.Code().and_(dest[0].Op(), 0x7FFF);
}
void EmitFPAbs32(EmitContext& ctx, const Operands& dest, const Operands& src) {
Reg reg_tmp = ctx.TempXmmReg();
Xmm xmm_tmp = dest[0].isMEM() ? ctx.TempXmmReg() : dest[0].getReg().cvt128();
Xmm xmm_tmp = dest[0].IsMem() ? ctx.TempXmmReg() : dest[0].Xmm();
ctx.Code().mov(reg_tmp, 0x7FFFFFFF);
ctx.Code().movd(xmm_tmp, reg_tmp);
ctx.Code().andps(xmm_tmp, src[0]);
ctx.Code().andps(xmm_tmp, src[0].Op());
MovFloat(ctx, dest[0], xmm_tmp);
}
void EmitFPAbs64(EmitContext& ctx, const Operands& dest, const Operands& src) {
Reg reg_tmp = ctx.TempGPReg();
Xmm xmm_tmp = dest[0].isMEM() ? ctx.TempXmmReg() : dest[0].getReg().cvt128();
Xmm xmm_tmp = dest[0].IsMem() ? ctx.TempXmmReg() : dest[0].Xmm();
ctx.Code().mov(reg_tmp, 0x7FFFFFFFFFFFFFFF);
ctx.Code().movq(xmm_tmp, reg_tmp);
ctx.Code().andpd(xmm_tmp, src[0]);
ctx.Code().andpd(xmm_tmp, src[0].Op());
MovFloat(ctx, dest[0], xmm_tmp);
}
void EmitFPAdd16(EmitContext& ctx, const Operands& dest, const Operands& op1, const Operands& op2) {
Xmm tmp1 = ctx.TempXmmReg();
Xmm tmp2 = ctx.TempXmmReg();
EmitInlineF16ToF32(ctx, tmp1, op1[0]);
EmitInlineF16ToF32(ctx, tmp2, op2[0]);
EmitInlineF16ToF32(ctx, tmp1, op1[0].Op());
EmitInlineF16ToF32(ctx, tmp2, op2[0].Op());
ctx.Code().addss(tmp1, tmp2);
EmitInlineF32ToF16(ctx, dest[0], tmp1);
EmitInlineF32ToF16(ctx, dest[0].Op(), tmp1);
}
void EmitFPAdd32(EmitContext& ctx, const Operands& dest, const Operands& op1, const Operands& op2) {
Xmm tmp = dest[0].isMEM() ? ctx.TempXmmReg() : dest[0].getReg().cvt128();
Xmm tmp = dest[0].IsMem() ? ctx.TempXmmReg() : dest[0].Xmm();
MovFloat(ctx, tmp, op1[0]);
ctx.Code().addss(tmp, op2[0]);
ctx.Code().addss(tmp, op2[0].Op());
MovFloat(ctx, dest[0], tmp);
}
void EmitFPAdd64(EmitContext& ctx, const Operands& dest, const Operands& op1, const Operands& op2) {
Xmm tmp = dest[0].isMEM() ? ctx.TempXmmReg() : dest[0].getReg().cvt128();
Xmm tmp = dest[0].IsMem() ? ctx.TempXmmReg() : dest[0].Xmm();
MovDouble(ctx, tmp, op1[0]);
ctx.Code().addsd(tmp, op2[0]);
ctx.Code().addsd(tmp, op2[0].Op());
MovDouble(ctx, dest[0], tmp);
}
void EmitFPSub32(EmitContext& ctx, const Operands& dest, const Operands& op1, const Operands& op2) {
Xmm tmp = dest[0].isMEM() ? ctx.TempXmmReg() : dest[0].getReg().cvt128();
Xmm tmp = dest[0].IsMem() ? ctx.TempXmmReg() : dest[0].Xmm();
MovFloat(ctx, tmp, op1[0]);
ctx.Code().subss(tmp, op2[0]);
ctx.Code().subss(tmp, op2[0].Op());
MovFloat(ctx, dest[0], tmp);
}
@ -71,58 +69,54 @@ void EmitFPFma16(EmitContext& ctx, const Operands& dest, const Operands& op1, co
Xmm tmp1 = ctx.TempXmmReg();
Xmm tmp2 = ctx.TempXmmReg();
Xmm tmp3 = ctx.TempXmmReg();
EmitInlineF16ToF32(ctx, tmp1, op1[0]);
EmitInlineF16ToF32(ctx, tmp2, op2[0]);
EmitInlineF16ToF32(ctx, tmp3, op3[0]);
EmitInlineF16ToF32(ctx, tmp1, op1[0].Op());
EmitInlineF16ToF32(ctx, tmp2, op2[0].Op());
EmitInlineF16ToF32(ctx, tmp3, op3[0].Op());
ctx.Code().vfmadd132ss(tmp3, tmp1, tmp2);
EmitInlineF32ToF16(ctx, dest[0], tmp3);
EmitInlineF32ToF16(ctx, dest[0].Op(), tmp3);
}
void EmitFPFma32(EmitContext& ctx, const Operands& dest, const Operands& op1, const Operands& op2, const Operands& op3) {
Xmm tmp1 = dest[0].isMEM() ? ctx.TempXmmReg() : dest[0].getReg().cvt128();
Xmm tmp2 = op1[0].isMEM() ? ctx.TempXmmReg() : op1[0].getReg().cvt128();
Xmm tmp3 = op2[0].isMEM() ? ctx.TempXmmReg() : op2[0].getReg().cvt128();
Xmm tmp1 = dest[0].IsMem() ? ctx.TempXmmReg() : dest[0].Xmm();
Xmm tmp2 = op2[0].IsMem() ? ctx.TempXmmReg() : op2[0].Xmm();
MovFloat(ctx, tmp1, op3[0]);
MovFloat(ctx, tmp2, op1[0]);
MovFloat(ctx, tmp3, op2[0]);
ctx.Code().vfmadd132ss(tmp3, tmp1, tmp2);
MovFloat(ctx, dest[0], tmp3);
MovFloat(ctx, tmp2, op2[0]);
ctx.Code().vfmadd132ss(tmp2, tmp1, op1[0].Op());
MovFloat(ctx, dest[0], tmp2);
}
void EmitFPFma64(EmitContext& ctx, const Operands& dest, const Operands& op1, const Operands& op2, const Operands& op3) {
Xmm tmp1 = dest[0].isMEM() ? ctx.TempXmmReg() : dest[0].getReg().cvt128();
Xmm tmp2 = op1[0].isMEM() ? ctx.TempXmmReg() : op1[0].getReg().cvt128();
Xmm tmp3 = op2[0].isMEM() ? ctx.TempXmmReg() : op2[0].getReg().cvt128();
Xmm tmp1 = dest[0].IsMem() ? ctx.TempXmmReg() : dest[0].Xmm();
Xmm tmp2 = op2[0].IsMem() ? ctx.TempXmmReg() : op2[0].Xmm();
MovDouble(ctx, tmp1, op3[0]);
MovDouble(ctx, tmp2, op1[0]);
MovDouble(ctx, tmp3, op2[0]);
ctx.Code().vfmadd132sd(tmp3, tmp1, tmp2);
MovDouble(ctx, dest[0], tmp3);
MovDouble(ctx, tmp2, op2[0]);
ctx.Code().vfmadd132sd(tmp2, tmp1, op1[0].Op());
MovDouble(ctx, dest[0], tmp2);
}
void EmitFPMax32(EmitContext& ctx, const Operands& dest, const Operands& op1, const Operands& op2, bool is_legacy) {
if (is_legacy) {
Xmm tmp1 = ctx.TempXmmReg();
Xmm tmp2 = ctx.TempXmmReg();
MovFloat(ctx, tmp1, op1[0]);
MovFloat(ctx, tmp2, op1[0]);
ctx.Code().maxss(tmp2, op2[0]);
MovFloat(ctx, tmp1, op1[0].Op());
MovFloat(ctx, tmp2, op1[0].Op());
ctx.Code().maxss(tmp2, op2[0].Op());
ctx.Code().cmpunordss(tmp1, tmp1);
ctx.Code().andps(tmp1, op2[0]);
ctx.Code().andps(tmp1, op2[0].Op());
ctx.Code().orps(tmp2, tmp1);
MovFloat(ctx, dest[0], tmp2);
} else {
Xmm tmp = dest[0].isMEM() ? ctx.TempXmmReg() : dest[0].getReg().cvt128();
Xmm tmp = dest[0].IsMem() ? ctx.TempXmmReg() : dest[0].Xmm();
MovFloat(ctx, tmp, op1[0]);
ctx.Code().maxss(tmp, op2[0]);
ctx.Code().maxss(tmp, op2[0].Op());
MovFloat(ctx, dest[0], tmp);
}
}
void EmitFPMax64(EmitContext& ctx, const Operands& dest, const Operands& op1, const Operands& op2) {
Xmm tmp = dest[0].isMEM() ? ctx.TempXmmReg() : dest[0].getReg().cvt128();
Xmm tmp = dest[0].IsMem() ? ctx.TempXmmReg() : dest[0].Xmm();
MovDouble(ctx, tmp, op1[0]);
ctx.Code().maxsd(tmp, op2[0]);
ctx.Code().maxsd(tmp, op2[0].Op());
MovDouble(ctx, dest[0], tmp);
}
@ -130,87 +124,85 @@ void EmitFPMin32(EmitContext& ctx, const Operands& dest, const Operands& op1, co
if (is_legacy) {
Xmm tmp1 = ctx.TempXmmReg();
Xmm tmp2 = ctx.TempXmmReg();
MovFloat(ctx, tmp1, op1[0]);
MovFloat(ctx, tmp2, op1[0]);
ctx.Code().minss(tmp2, op2[0]);
MovFloat(ctx, tmp1, op1[0].Op());
MovFloat(ctx, tmp2, op1[0].Op());
ctx.Code().minss(tmp2, op2[0].Op());
ctx.Code().cmpunordss(tmp1, tmp1);
ctx.Code().andps(tmp1, op2[0]);
ctx.Code().andps(tmp1, op2[0].Op());
ctx.Code().orps(tmp2, tmp1);
MovFloat(ctx, dest[0], tmp2);
} else {
Xmm tmp = dest[0].isMEM() ? ctx.TempXmmReg() : dest[0].getReg().cvt128();
Xmm tmp = dest[0].IsMem() ? ctx.TempXmmReg() : dest[0].Xmm();
MovFloat(ctx, tmp, op1[0]);
ctx.Code().minss(tmp, op2[0]);
ctx.Code().minss(tmp, op2[0].Op());
MovFloat(ctx, dest[0], tmp);
}
}
void EmitFPMin64(EmitContext& ctx, const Operands& dest, const Operands& op1, const Operands& op2) {
Xmm tmp = dest[0].isMEM() ? ctx.TempXmmReg() : dest[0].getReg().cvt128();
Xmm tmp = dest[0].IsMem() ? ctx.TempXmmReg() : dest[0].Xmm();
MovDouble(ctx, tmp, op1[0]);
ctx.Code().minsd(tmp, op2[0]);
ctx.Code().minsd(tmp, op2[0].Op());
MovDouble(ctx, dest[0], tmp);
}
void EmitFPMul16(EmitContext& ctx, const Operands& dest, const Operands& op1, const Operands& op2) {
Xmm tmp1 = ctx.TempXmmReg();
Xmm tmp2 = ctx.TempXmmReg();
EmitInlineF16ToF32(ctx, tmp1, op1[0]);
EmitInlineF16ToF32(ctx, tmp2, op2[0]);
EmitInlineF16ToF32(ctx, tmp1, op1[0].Op());
EmitInlineF16ToF32(ctx, tmp2, op2[0].Op());
ctx.Code().mulss(tmp1, tmp2);
EmitInlineF32ToF16(ctx, dest[0], tmp1);
EmitInlineF32ToF16(ctx, dest[0].Op(), tmp1);
}
void EmitFPMul32(EmitContext& ctx, const Operands& dest, const Operands& op1, const Operands& op2) {
Xmm tmp = dest[0].isMEM() ? ctx.TempXmmReg() : dest[0].getReg().cvt128();
Xmm tmp = dest[0].IsMem() ? ctx.TempXmmReg() : dest[0].Xmm();
MovFloat(ctx, tmp, op1[0]);
ctx.Code().mulss(tmp, op2[0]);
ctx.Code().mulss(tmp, op2[0].Op());
MovFloat(ctx, dest[0], tmp);
}
void EmitFPMul64(EmitContext& ctx, const Operands& dest, const Operands& op1, const Operands& op2) {
Xmm tmp = dest[0].isMEM() ? ctx.TempXmmReg() : dest[0].getReg().cvt128();
Xmm tmp = dest[0].IsMem() ? ctx.TempXmmReg() : dest[0].Xmm();
MovDouble(ctx, tmp, op1[0]);
ctx.Code().mulsd(tmp, op2[0]);
ctx.Code().mulsd(tmp, op2[0].Op());
MovDouble(ctx, dest[0], tmp);
}
void EmitFPDiv32(EmitContext& ctx, const Operands& dest, const Operands& op1, const Operands& op2) {
Xmm tmp = dest[0].isMEM() ? ctx.TempXmmReg() : dest[0].getReg().cvt128();
Xmm tmp = dest[0].IsMem() ? ctx.TempXmmReg() : dest[0].Xmm();
MovFloat(ctx, tmp, op1[0]);
ctx.Code().divss(tmp, op2[0]);
ctx.Code().divss(tmp, op2[0].Op());
MovFloat(ctx, dest[0], tmp);
}
void EmitFPDiv64(EmitContext& ctx, const Operands& dest, const Operands& op1, const Operands& op2) {
Xmm tmp = dest[0].isMEM() ? ctx.TempXmmReg() : dest[0].getReg().cvt128();
Xmm tmp = dest[0].IsMem() ? ctx.TempXmmReg() : dest[0].Xmm();
MovDouble(ctx, tmp, op1[0]);
ctx.Code().divsd(tmp, op2[0]);
ctx.Code().divsd(tmp, op2[0].Op());
MovDouble(ctx, dest[0], tmp);
}
void EmitFPNeg16(EmitContext& ctx, const Operands& dest, const Operands& op1) {
Reg tmp = dest[0].isMEM() ? ctx.TempGPReg().cvt16() : dest[0].getReg().cvt16();
MovGP(ctx, tmp, op1[0]);
ctx.Code().xor_(tmp, 0x8000);
MovGP(ctx, dest[0], tmp);
MovGP(ctx, dest[0], op1[0]);
ctx.Code().xor_(dest[0].Op(), 0x8000);
}
void EmitFPNeg32(EmitContext& ctx, const Operands& dest, const Operands& op1) {
Xmm tmp_xmm = dest[0].isMEM() ? ctx.TempXmmReg() : dest[0].getReg().cvt128();
Xmm tmp_xmm = dest[0].IsMem() ? ctx.TempXmmReg() : dest[0].Xmm();
Reg tmp_reg = ctx.TempGPReg().cvt32();
ctx.Code().mov(tmp_reg, 0x80000000);
ctx.Code().movd(tmp_xmm, tmp_reg);
ctx.Code().xorps(tmp_xmm, op1[0]);
ctx.Code().xorps(tmp_xmm, op1[0].Op());
MovFloat(ctx, dest[0], tmp_xmm);
}
void EmitFPNeg64(EmitContext& ctx, const Operands& dest, const Operands& op1) {
Xmm tmp_xmm = dest[0].isMEM() ? ctx.TempXmmReg() : dest[0].getReg().cvt128();
Xmm tmp_xmm = dest[0].IsMem() ? ctx.TempXmmReg() : dest[0].Xmm();
Reg tmp_reg = ctx.TempXmmReg();
ctx.Code().mov(tmp_reg, 0x8000000000000000);
ctx.Code().movq(tmp_xmm, tmp_reg);
ctx.Code().xorpd(tmp_xmm, op1[0]);
ctx.Code().xorpd(tmp_xmm, op1[0].Op());
MovDouble(ctx, dest[0], tmp_xmm);
}
@ -236,39 +228,39 @@ void EmitFPLog2(EmitContext& ctx) {
}
void EmitFPRecip32(EmitContext& ctx, const Operands& dest, const Operands& op1) {
Xmm tmp = dest[0].isMEM() ? ctx.TempXmmReg() : dest[0].getReg().cvt128();
ctx.Code().rcpss(tmp, op1[0]);
Xmm tmp = dest[0].IsMem() ? ctx.TempXmmReg() : dest[0].Xmm();
ctx.Code().rcpss(tmp, op1[0].Op());
MovFloat(ctx, dest[0], tmp);
}
void EmitFPRecip64(EmitContext& ctx, const Operands& dest, const Operands& op1) {
Xmm tmp_xmm = dest[0].isMEM() ? ctx.TempXmmReg() : dest[0].getReg().cvt128();
Xmm tmp_xmm = dest[0].IsMem() ? ctx.TempXmmReg() : dest[0].Xmm();
Reg tmp_reg = ctx.TempGPReg();
ctx.Code().mov(tmp_reg, 1);
ctx.Code().cvtsi2sd(tmp_xmm, tmp_reg);
ctx.Code().divsd(tmp_xmm, op1[0]);
ctx.Code().divsd(tmp_xmm, op1[0].Op());
MovDouble(ctx, dest[0], tmp_xmm);
}
void EmitFPRecipSqrt32(EmitContext& ctx, const Operands& dest, const Operands& op1) {
Xmm tmp = dest[0].isMEM() ? ctx.TempXmmReg() : dest[0].getReg().cvt128();
ctx.Code().rsqrtss(tmp, op1[0]);
Xmm tmp = dest[0].IsMem() ? ctx.TempXmmReg() : dest[0].Xmm();
ctx.Code().rsqrtss(tmp, op1[0].Op());
MovFloat(ctx, dest[0], tmp);
}
void EmitFPRecipSqrt64(EmitContext& ctx, const Operands& dest, const Operands& op1) {
Xmm tmp_xmm = dest[0].isMEM() ? ctx.TempXmmReg() : dest[0].getReg().cvt128();
Xmm tmp_xmm = dest[0].IsMem() ? ctx.TempXmmReg() : dest[0].Xmm();
Reg tmp_reg = ctx.TempGPReg();
ctx.Code().mov(tmp_reg, 1);
ctx.Code().cvtsi2sd(tmp_xmm, tmp_reg);
ctx.Code().divsd(tmp_xmm, op1[0]);
ctx.Code().divsd(tmp_xmm, op1[0].Op());
ctx.Code().sqrtsd(tmp_xmm, tmp_xmm);
MovDouble(ctx, dest[0], tmp_xmm);
}
void EmitFPSqrt(EmitContext& ctx, const Operands& dest, const Operands& op1) {
Xmm tmp = dest[0].isMEM() ? ctx.TempXmmReg() : dest[0].getReg().cvt128();
ctx.Code().sqrtss(tmp, op1[0]);
Xmm tmp = dest[0].IsMem() ? ctx.TempXmmReg() : dest[0].Xmm();
ctx.Code().sqrtss(tmp, op1[0].Op());
MovFloat(ctx, dest[0], tmp);
}
@ -288,84 +280,84 @@ void EmitFPClamp16(EmitContext& ctx, const Operands& dest, const Operands& op, c
Xmm tmp1 = ctx.TempXmmReg();
Xmm tmp2 = ctx.TempXmmReg();
Xmm tmp3 = ctx.TempXmmReg();
EmitInlineF16ToF32(ctx, tmp1, op[0]);
EmitInlineF16ToF32(ctx, tmp2, min[0]);
EmitInlineF16ToF32(ctx, tmp3, max[0]);
EmitInlineF16ToF32(ctx, tmp1, op[0].Op());
EmitInlineF16ToF32(ctx, tmp2, min[0].Op());
EmitInlineF16ToF32(ctx, tmp3, max[0].Op());
ctx.Code().maxss(tmp1, tmp2);
ctx.Code().minss(tmp1, tmp3);
EmitInlineF32ToF16(ctx, dest[0], tmp1);
EmitInlineF32ToF16(ctx, dest[0].Op(), tmp1);
}
void EmitFPClamp32(EmitContext& ctx, const Operands& dest, const Operands& op, const Operands& min, const Operands& max) {
Xmm tmp = dest[0].isMEM() ? ctx.TempXmmReg() : dest[0].getReg().cvt128();
Xmm tmp = dest[0].IsMem() ? ctx.TempXmmReg() : dest[0].Xmm();
MovFloat(ctx, tmp, op[0]);
ctx.Code().maxss(tmp, min[0]);
ctx.Code().minss(tmp, max[0]);
ctx.Code().maxss(tmp, min[0].Op());
ctx.Code().minss(tmp, max[0].Op());
MovFloat(ctx, dest[0], tmp);
}
void EmitFPClamp64(EmitContext& ctx, const Operands& dest, const Operands& op, const Operands& min, const Operands& max) {
Xmm tmp = dest[0].isMEM() ? ctx.TempXmmReg() : dest[0].getReg().cvt128();
Xmm tmp = dest[0].IsMem() ? ctx.TempXmmReg() : dest[0].Xmm();
MovDouble(ctx, tmp, op[0]);
ctx.Code().maxsd(tmp, min[0]);
ctx.Code().minsd(tmp, max[0]);
ctx.Code().maxsd(tmp, min[0].Op());
ctx.Code().minsd(tmp, max[0].Op());
MovDouble(ctx, dest[0], tmp);
}
void EmitFPRoundEven16(EmitContext& ctx, const Operands& dest, const Operands& op1) {
Xmm tmp = ctx.TempXmmReg();
EmitInlineF16ToF32(ctx, tmp, op1[0]);
EmitInlineF16ToF32(ctx, tmp, op1[0].Op());
ctx.Code().roundss(tmp, tmp, 0x00);
EmitInlineF32ToF16(ctx, dest[0], tmp);
EmitInlineF32ToF16(ctx, dest[0].Op(), tmp);
}
void EmitFPRoundEven32(EmitContext& ctx, const Operands& dest, const Operands& op1) {
Xmm tmp = dest[0].isMEM() ? ctx.TempXmmReg() : dest[0].getReg().cvt128();
ctx.Code().roundss(tmp, op1[0], 0x00);
Xmm tmp = dest[0].IsMem() ? ctx.TempXmmReg() : dest[0].Xmm();
ctx.Code().roundss(tmp, op1[0].Op(), 0x00);
MovFloat(ctx, dest[0], tmp);
}
void EmitFPRoundEven64(EmitContext& ctx, const Operands& dest, const Operands& op1) {
Xmm tmp = dest[0].isMEM() ? ctx.TempXmmReg() : dest[0].getReg().cvt128();
ctx.Code().roundsd(tmp, op1[0], 0x00);
Xmm tmp = dest[0].IsMem() ? ctx.TempXmmReg() : dest[0].Xmm();
ctx.Code().roundsd(tmp, op1[0].Op(), 0x00);
MovDouble(ctx, dest[0], tmp);
}
void EmitFPFloor16(EmitContext& ctx, const Operands& dest, const Operands& op1) {
Xmm tmp = ctx.TempXmmReg();
EmitInlineF16ToF32(ctx, tmp, op1[0]);
EmitInlineF16ToF32(ctx, tmp, op1[0].Op());
ctx.Code().roundss(tmp, tmp, 0x01);
EmitInlineF32ToF16(ctx, dest[0], tmp);
EmitInlineF32ToF16(ctx, dest[0].Op(), tmp);
}
void EmitFPFloor32(EmitContext& ctx, const Operands& dest, const Operands& op1) {
Xmm tmp = dest[0].isMEM() ? ctx.TempXmmReg() : dest[0].getReg().cvt128();
ctx.Code().roundss(tmp, op1[0], 0x01);
Xmm tmp = dest[0].IsMem() ? ctx.TempXmmReg() : dest[0].Xmm();
ctx.Code().roundss(tmp, op1[0].Op(), 0x01);
MovFloat(ctx, dest[0], tmp);
}
void EmitFPFloor64(EmitContext& ctx, const Operands& dest, const Operands& op1) {
Xmm tmp = dest[0].isMEM() ? ctx.TempXmmReg() : dest[0].getReg().cvt128();
ctx.Code().roundsd(tmp, op1[0], 0x01);
Xmm tmp = dest[0].IsMem() ? ctx.TempXmmReg() : dest[0].Xmm();
ctx.Code().roundsd(tmp, op1[0].Op(), 0x01);
MovDouble(ctx, dest[0], tmp);
}
void EmitFPCeil16(EmitContext& ctx, const Operands& dest, const Operands& op1) {
Xmm tmp = ctx.TempXmmReg();
EmitInlineF16ToF32(ctx, tmp, op1[0]);
EmitInlineF16ToF32(ctx, tmp, op1[0].Op());
ctx.Code().roundss(tmp, tmp, 0x02);
EmitInlineF32ToF16(ctx, dest[0], tmp);
EmitInlineF32ToF16(ctx, dest[0].Op(), tmp);
}
void EmitFPCeil32(EmitContext& ctx, const Operands& dest, const Operands& op1) {
Xmm tmp = dest[0].isMEM() ? ctx.TempXmmReg() : dest[0].getReg().cvt128();
ctx.Code().roundss(tmp, op1[0], 0x02);
Xmm tmp = dest[0].IsMem() ? ctx.TempXmmReg() : dest[0].Xmm();
ctx.Code().roundss(tmp, op1[0].Op(), 0x02);
MovFloat(ctx, dest[0], tmp);
}
void EmitFPCeil64(EmitContext& ctx, const Operands& dest, const Operands& op1) {
Xmm tmp = dest[0].isMEM() ? ctx.TempXmmReg() : dest[0].getReg().cvt128();
ctx.Code().roundsd(tmp, op1[0], 0x02);
Xmm tmp = dest[0].IsMem() ? ctx.TempXmmReg() : dest[0].Xmm();
ctx.Code().roundsd(tmp, op1[0].Op(), 0x02);
MovDouble(ctx, dest[0], tmp);
}
@ -409,7 +401,7 @@ void EmitFPOrdEqual16(EmitContext& ctx, const Operands& dest, const Operands& lh
Label not_nan;
EmitFPUnordEqual16(ctx, dest, lhs, rhs);
ctx.Code().jnp(not_nan);
ctx.Code().mov(dest[0], 0);
ctx.Code().mov(dest[0].Op(), 0);
ctx.Code().L(not_nan);
}
@ -417,7 +409,7 @@ void EmitFPOrdEqual32(EmitContext& ctx, const Operands& dest, const Operands& lh
Label not_nan;
EmitFPUnordEqual32(ctx, dest, lhs, rhs);
ctx.Code().jnp(not_nan);
ctx.Code().mov(dest[0], 0);
ctx.Code().mov(dest[0].Op(), 0);
ctx.Code().L(not_nan);
}
@ -425,46 +417,46 @@ void EmitFPOrdEqual64(EmitContext& ctx, const Operands& dest, const Operands& lh
Label not_nan;
EmitFPUnordEqual64(ctx, dest, lhs, rhs);
ctx.Code().jnp(not_nan);
ctx.Code().mov(dest[0], 0);
ctx.Code().mov(dest[0].Op(), 0);
ctx.Code().L(not_nan);
}
void EmitFPUnordEqual16(EmitContext& ctx, const Operands& dest, const Operands& lhs, const Operands& rhs) {
Xmm tmp1 = ctx.TempXmmReg();
Xmm tmp2 = ctx.TempXmmReg();
EmitInlineF16ToF32(ctx, tmp1, lhs[0]);
EmitInlineF16ToF32(ctx, tmp2, rhs[0]);
EmitInlineF16ToF32(ctx, tmp1, lhs[0].Op());
EmitInlineF16ToF32(ctx, tmp2, rhs[0].Op());
ctx.Code().ucomiss(tmp1, tmp2);
ctx.Code().sete(dest[0]);
ctx.Code().sete(dest[0].Op());
}
void EmitFPUnordEqual32(EmitContext& ctx, const Operands& dest, const Operands& lhs, const Operands& rhs) {
Xmm tmp = lhs[0].isMEM() ? ctx.TempXmmReg() : lhs[0].getReg().cvt128();
Xmm tmp = lhs[0].IsMem() ? ctx.TempXmmReg() : lhs[0].Xmm();
MovFloat(ctx, tmp, lhs[0]);
ctx.Code().ucomiss(tmp, rhs[0]);
ctx.Code().sete(dest[0]);
ctx.Code().ucomiss(tmp, rhs[0].Op());
ctx.Code().sete(dest[0].Op());
}
void EmitFPUnordEqual64(EmitContext& ctx, const Operands& dest, const Operands& lhs, const Operands& rhs) {
Xmm tmp = lhs[0].isMEM() ? ctx.TempXmmReg() : lhs[0].getReg().cvt128();
Xmm tmp = lhs[0].IsMem() ? ctx.TempXmmReg() : lhs[0].Xmm();
MovDouble(ctx, tmp, lhs[0]);
ctx.Code().ucomisd(tmp, rhs[0]);
ctx.Code().sete(dest[0]);
ctx.Code().ucomisd(tmp, rhs[0].Op());
ctx.Code().sete(dest[0].Op());
}
void EmitFPOrdNotEqual16(EmitContext& ctx, const Operands& dest, const Operands& lhs, const Operands& rhs) {
Label not_nan;
EmitFPUnordNotEqual16(ctx, dest, lhs, rhs);
ctx.Code().jnp(not_nan);
ctx.Code().mov(dest[0], 0);
ctx.Code().mov(dest[0].Op(), 0);
ctx.Code().L(not_nan);
}
void EmitFPOrdNotEqual32(EmitContext& ctx, const Operands& dest, const Operands& lhs, const Operands& rhs) {
Label not_nan;
Xmm tmp = lhs[0].isMEM() ? ctx.TempXmmReg() : lhs[0].getReg().cvt128();
Xmm tmp = lhs[0].IsMem() ? ctx.TempXmmReg() : lhs[0].Xmm();
ctx.Code().jnp(not_nan);
ctx.Code().mov(dest[0], 0);
ctx.Code().mov(dest[0].Op(), 0);
ctx.Code().L(not_nan);
}
@ -472,38 +464,38 @@ void EmitFPOrdNotEqual64(EmitContext& ctx, const Operands& dest, const Operands&
Label not_nan;
EmitFPUnordNotEqual64(ctx, dest, lhs, rhs);
ctx.Code().jnp(not_nan);
ctx.Code().mov(dest[0], 0);
ctx.Code().mov(dest[0].Op(), 0);
ctx.Code().L(not_nan);
}
void EmitFPUnordNotEqual16(EmitContext& ctx, const Operands& dest, const Operands& lhs, const Operands& rhs) {
Xmm tmp1 = ctx.TempXmmReg();
Xmm tmp2 = ctx.TempXmmReg();
EmitInlineF16ToF32(ctx, tmp1, lhs[0]);
EmitInlineF16ToF32(ctx, tmp2, rhs[0]);
EmitInlineF16ToF32(ctx, tmp1, lhs[0].Op());
EmitInlineF16ToF32(ctx, tmp2, rhs[0].Op());
ctx.Code().ucomiss(tmp1, tmp2);
ctx.Code().setne(dest[0]);
ctx.Code().setne(dest[0].Op());
}
void EmitFPUnordNotEqual32(EmitContext& ctx, const Operands& dest, const Operands& lhs, const Operands& rhs) {
Xmm tmp = lhs[0].isMEM() ? ctx.TempXmmReg() : lhs[0].getReg().cvt128();
Xmm tmp = lhs[0].IsMem() ? ctx.TempXmmReg() : lhs[0].Xmm();
MovFloat(ctx, tmp, lhs[0]);
ctx.Code().ucomiss(tmp, rhs[0]);
ctx.Code().setne(dest[0]);
ctx.Code().ucomiss(tmp, rhs[0].Op());
ctx.Code().setne(dest[0].Op());
}
void EmitFPUnordNotEqual64(EmitContext& ctx, const Operands& dest, const Operands& lhs, const Operands& rhs) {
Xmm tmp = lhs[0].isMEM() ? ctx.TempXmmReg() : lhs[0].getReg().cvt128();
Xmm tmp = lhs[0].IsMem() ? ctx.TempXmmReg() : lhs[0].Xmm();
MovDouble(ctx, tmp, lhs[0]);
ctx.Code().ucomisd(tmp, rhs[0]);
ctx.Code().setne(dest[0]);
ctx.Code().ucomisd(tmp, rhs[0].Op());
ctx.Code().setne(dest[0].Op());
}
void EmitFPOrdLessThan16(EmitContext& ctx, const Operands& dest, const Operands& lhs, const Operands& rhs) {
Label not_nan;
EmitFPUnordLessThan16(ctx, dest, lhs, rhs);
ctx.Code().jnp(not_nan);
ctx.Code().mov(dest[0], 0);
ctx.Code().mov(dest[0].Op(), 0);
ctx.Code().L(not_nan);
}
@ -511,7 +503,7 @@ void EmitFPOrdLessThan32(EmitContext& ctx, const Operands& dest, const Operands&
Label not_nan;
EmitFPUnordLessThan32(ctx, dest, lhs, rhs);
ctx.Code().jnp(not_nan);
ctx.Code().mov(dest[0], 0);
ctx.Code().mov(dest[0].Op(), 0);
ctx.Code().L(not_nan);
}
@ -519,38 +511,38 @@ void EmitFPOrdLessThan64(EmitContext& ctx, const Operands& dest, const Operands&
Label not_nan;
EmitFPUnordLessThan64(ctx, dest, lhs, rhs);
ctx.Code().jnp(not_nan);
ctx.Code().mov(dest[0], 0);
ctx.Code().mov(dest[0].Op(), 0);
ctx.Code().L(not_nan);
}
void EmitFPUnordLessThan16(EmitContext& ctx, const Operands& dest, const Operands& lhs, const Operands& rhs) {
Xmm tmp1 = ctx.TempXmmReg();
Xmm tmp2 = ctx.TempXmmReg();
EmitInlineF16ToF32(ctx, tmp1, lhs[0]);
EmitInlineF16ToF32(ctx, tmp2, rhs[0]);
EmitInlineF16ToF32(ctx, tmp1, lhs[0].Op());
EmitInlineF16ToF32(ctx, tmp2, rhs[0].Op());
ctx.Code().ucomiss(tmp1, tmp2);
ctx.Code().setb(dest[0]);
ctx.Code().setb(dest[0].Op());
}
void EmitFPUnordLessThan32(EmitContext& ctx, const Operands& dest, const Operands& lhs, const Operands& rhs) {
Xmm tmp = lhs[0].isMEM() ? ctx.TempXmmReg() : lhs[0].getReg().cvt128();
Xmm tmp = lhs[0].IsMem() ? ctx.TempXmmReg() : lhs[0].Xmm();
MovFloat(ctx, tmp, lhs[0]);
ctx.Code().ucomiss(tmp, rhs[0]);
ctx.Code().setb(dest[0]);
ctx.Code().ucomiss(tmp, rhs[0].Op());
ctx.Code().setb(dest[0].Op());
}
void EmitFPUnordLessThan64(EmitContext& ctx, const Operands& dest, const Operands& lhs, const Operands& rhs) {
Xmm tmp = lhs[0].isMEM() ? ctx.TempXmmReg() : lhs[0].getReg().cvt128();
Xmm tmp = lhs[0].IsMem() ? ctx.TempXmmReg() : lhs[0].Xmm();
MovDouble(ctx, tmp, lhs[0]);
ctx.Code().ucomisd(tmp, rhs[0]);
ctx.Code().setb(dest[0]);
ctx.Code().ucomisd(tmp, rhs[0].Op());
ctx.Code().setb(dest[0].Op());
}
void EmitFPOrdGreaterThan16(EmitContext& ctx, const Operands& dest, const Operands& lhs, const Operands& rhs) {
Label not_nan;
EmitFPUnordGreaterThan16(ctx, dest, lhs, rhs);
ctx.Code().jnp(not_nan);
ctx.Code().mov(dest[0], 0);
ctx.Code().mov(dest[0].Op(), 0);
ctx.Code().L(not_nan);
}
@ -558,7 +550,7 @@ void EmitFPOrdGreaterThan32(EmitContext& ctx, const Operands& dest, const Operan
Label not_nan;
EmitFPUnordGreaterThan32(ctx, dest, lhs, rhs);
ctx.Code().jnp(not_nan);
ctx.Code().mov(dest[0], 0);
ctx.Code().mov(dest[0].Op(), 0);
ctx.Code().L(not_nan);
}
@ -566,38 +558,38 @@ void EmitFPOrdGreaterThan64(EmitContext& ctx, const Operands& dest, const Operan
Label not_nan;
EmitFPUnordGreaterThan64(ctx, dest, lhs, rhs);
ctx.Code().jnp(not_nan);
ctx.Code().mov(dest[0], 0);
ctx.Code().mov(dest[0].Op(), 0);
ctx.Code().L(not_nan);
}
void EmitFPUnordGreaterThan16(EmitContext& ctx, const Operands& dest, const Operands& lhs, const Operands& rhs) {
Xmm tmp1 = ctx.TempXmmReg();
Xmm tmp2 = ctx.TempXmmReg();
EmitInlineF16ToF32(ctx, tmp1, lhs[0]);
EmitInlineF16ToF32(ctx, tmp2, rhs[0]);
EmitInlineF16ToF32(ctx, tmp1, lhs[0].Op());
EmitInlineF16ToF32(ctx, tmp2, rhs[0].Op());
ctx.Code().ucomiss(tmp1, tmp2);
ctx.Code().seta(dest[0]);
ctx.Code().seta(dest[0].Op());
}
void EmitFPUnordGreaterThan32(EmitContext& ctx, const Operands& dest, const Operands& lhs, const Operands& rhs) {
Xmm tmp = lhs[0].isMEM() ? ctx.TempXmmReg() : lhs[0].getReg().cvt128();
Xmm tmp = lhs[0].IsMem() ? ctx.TempXmmReg() : lhs[0].Xmm();
MovFloat(ctx, tmp, lhs[0]);
ctx.Code().ucomiss(tmp, rhs[0]);
ctx.Code().seta(dest[0]);
ctx.Code().ucomiss(tmp, rhs[0].Op());
ctx.Code().seta(dest[0].Op());
}
void EmitFPUnordGreaterThan64(EmitContext& ctx, const Operands& dest, const Operands& lhs, const Operands& rhs) {
Xmm tmp = lhs[0].isMEM() ? ctx.TempXmmReg() : lhs[0].getReg().cvt128();
Xmm tmp = lhs[0].IsMem() ? ctx.TempXmmReg() : lhs[0].Xmm();
MovDouble(ctx, tmp, lhs[0]);
ctx.Code().ucomisd(tmp, rhs[0]);
ctx.Code().seta(dest[0]);
ctx.Code().ucomisd(tmp, rhs[0].Op());
ctx.Code().seta(dest[0].Op());
}
void EmitFPOrdLessThanEqual16(EmitContext& ctx, const Operands& dest, const Operands& lhs, const Operands& rhs) {
Label not_nan;
EmitFPUnordLessThanEqual16(ctx, dest, lhs, rhs);
ctx.Code().jnp(not_nan);
ctx.Code().mov(dest[0], 0);
ctx.Code().mov(dest[0].Op(), 0);
ctx.Code().L(not_nan);
}
@ -605,7 +597,7 @@ void EmitFPOrdLessThanEqual32(EmitContext& ctx, const Operands& dest, const Oper
Label not_nan;
EmitFPUnordLessThanEqual32(ctx, dest, lhs, rhs);
ctx.Code().jnp(not_nan);
ctx.Code().mov(dest[0], 0);
ctx.Code().mov(dest[0].Op(), 0);
ctx.Code().L(not_nan);
}
@ -613,38 +605,38 @@ void EmitFPOrdLessThanEqual64(EmitContext& ctx, const Operands& dest, const Oper
Label not_nan;
EmitFPUnordLessThanEqual64(ctx, dest, lhs, rhs);
ctx.Code().jnp(not_nan);
ctx.Code().mov(dest[0], 0);
ctx.Code().mov(dest[0].Op(), 0);
ctx.Code().L(not_nan);
}
void EmitFPUnordLessThanEqual16(EmitContext& ctx, const Operands& dest, const Operands& lhs, const Operands& rhs) {
Xmm tmp1 = ctx.TempXmmReg();
Xmm tmp2 = ctx.TempXmmReg();
EmitInlineF16ToF32(ctx, tmp1, lhs[0]);
EmitInlineF16ToF32(ctx, tmp2, rhs[0]);
EmitInlineF16ToF32(ctx, tmp1, lhs[0].Op());
EmitInlineF16ToF32(ctx, tmp2, rhs[0].Op());
ctx.Code().ucomiss(tmp1, tmp2);
ctx.Code().setbe(dest[0]);
ctx.Code().setbe(dest[0].Op());
}
void EmitFPUnordLessThanEqual32(EmitContext& ctx, const Operands& dest, const Operands& lhs, const Operands& rhs) {
Xmm tmp = lhs[0].isMEM() ? ctx.TempXmmReg() : lhs[0].getReg().cvt128();
Xmm tmp = lhs[0].IsMem() ? ctx.TempXmmReg() : lhs[0].Xmm();
MovFloat(ctx, tmp, lhs[0]);
ctx.Code().ucomiss(tmp, rhs[0]);
ctx.Code().setbe(dest[0]);
ctx.Code().ucomiss(tmp, rhs[0].Op());
ctx.Code().setbe(dest[0].Op());
}
void EmitFPUnordLessThanEqual64(EmitContext& ctx, const Operands& dest, const Operands& lhs, const Operands& rhs) {
Xmm tmp = lhs[0].isMEM() ? ctx.TempXmmReg() : lhs[0].getReg().cvt128();
Xmm tmp = lhs[0].IsMem() ? ctx.TempXmmReg() : lhs[0].Xmm();
MovDouble(ctx, tmp, lhs[0]);
ctx.Code().ucomisd(tmp, rhs[0]);
ctx.Code().setbe(dest[0]);
ctx.Code().ucomisd(tmp, rhs[0].Op());
ctx.Code().setbe(dest[0].Op());
}
void EmitFPOrdGreaterThanEqual16(EmitContext& ctx, const Operands& dest, const Operands& lhs, const Operands& rhs) {
Label not_nan;
EmitFPUnordGreaterThanEqual16(ctx, dest, lhs, rhs);
ctx.Code().jnp(not_nan);
ctx.Code().mov(dest[0], 0);
ctx.Code().mov(dest[0].Op(), 0);
ctx.Code().L(not_nan);
}
@ -652,7 +644,7 @@ void EmitFPOrdGreaterThanEqual32(EmitContext& ctx, const Operands& dest, const O
Label not_nan;
EmitFPUnordGreaterThanEqual32(ctx, dest, lhs, rhs);
ctx.Code().jnp(not_nan);
ctx.Code().mov(dest[0], 0);
ctx.Code().mov(dest[0].Op(), 0);
ctx.Code().L(not_nan);
}
@ -660,52 +652,52 @@ void EmitFPOrdGreaterThanEqual64(EmitContext& ctx, const Operands& dest, const O
Label not_nan;
EmitFPUnordGreaterThanEqual64(ctx, dest, lhs, rhs);
ctx.Code().jnp(not_nan);
ctx.Code().mov(dest[0], 0);
ctx.Code().mov(dest[0].Op(), 0);
ctx.Code().L(not_nan);
}
void EmitFPUnordGreaterThanEqual16(EmitContext& ctx, const Operands& dest, const Operands& lhs, const Operands& rhs) {
Xmm tmp1 = ctx.TempXmmReg();
Xmm tmp2 = ctx.TempXmmReg();
EmitInlineF16ToF32(ctx, tmp1, lhs[0]);
EmitInlineF16ToF32(ctx, tmp2, rhs[0]);
EmitInlineF16ToF32(ctx, tmp1, lhs[0].Op());
EmitInlineF16ToF32(ctx, tmp2, rhs[0].Op());
ctx.Code().ucomiss(tmp1, tmp2);
ctx.Code().setae(dest[0]);
ctx.Code().setae(dest[0].Op());
}
void EmitFPUnordGreaterThanEqual32(EmitContext& ctx, const Operands& dest, const Operands& lhs, const Operands& rhs) {
Xmm tmp = lhs[0].isMEM() ? ctx.TempXmmReg() : lhs[0].getReg().cvt128();
Xmm tmp = lhs[0].IsMem() ? ctx.TempXmmReg() : lhs[0].Xmm();
MovFloat(ctx, tmp, lhs[0]);
ctx.Code().ucomiss(tmp, rhs[0]);
ctx.Code().setae(dest[0]);
ctx.Code().ucomiss(tmp, rhs[0].Op());
ctx.Code().setae(dest[0].Op());
}
void EmitFPUnordGreaterThanEqual64(EmitContext& ctx, const Operands& dest, const Operands& lhs, const Operands& rhs) {
Xmm tmp = lhs[0].isMEM() ? ctx.TempXmmReg() : lhs[0].getReg().cvt128();
Xmm tmp = lhs[0].IsMem() ? ctx.TempXmmReg() : lhs[0].Xmm();
MovDouble(ctx, tmp, lhs[0]);
ctx.Code().ucomisd(tmp, rhs[0]);
ctx.Code().setae(dest[0]);
ctx.Code().ucomisd(tmp, rhs[0].Op());
ctx.Code().setae(dest[0].Op());
}
void EmitFPIsNan16(EmitContext& ctx, const Operands& dest, const Operands& op) {
Xmm tmp = ctx.TempXmmReg();
EmitInlineF16ToF32(ctx, tmp, op[0]);
EmitInlineF16ToF32(ctx, tmp, op[0].Op());
ctx.Code().ucomiss(tmp, tmp);
ctx.Code().setp(dest[0]);
ctx.Code().setp(dest[0].Op());
}
void EmitFPIsNan32(EmitContext& ctx, const Operands& dest, const Operands& op) {
Xmm tmp = dest[0].isMEM() ? ctx.TempXmmReg() : dest[0].getReg().cvt128();
Xmm tmp = dest[0].IsMem() ? ctx.TempXmmReg() : dest[0].Xmm();
MovFloat(ctx, tmp, op[0]);
ctx.Code().ucomiss(tmp, tmp);
ctx.Code().setp(dest[0]);
ctx.Code().setp(dest[0].Op());
}
void EmitFPIsNan64(EmitContext& ctx, const Operands& dest, const Operands& op) {
Xmm tmp = dest[0].isMEM() ? ctx.TempXmmReg() : dest[0].getReg().cvt128();
Xmm tmp = dest[0].IsMem() ? ctx.TempXmmReg() : dest[0].Xmm();
MovDouble(ctx, tmp, op[0]);
ctx.Code().ucomisd(tmp, tmp);
ctx.Code().setp(dest[0]);
ctx.Code().setp(dest[0].Op());
}
void EmitFPIsInf32(EmitContext& ctx) {

View file

@ -6,6 +6,7 @@
#include <boost/container/static_vector.hpp>
#include <xbyak/xbyak.h>
#include "common/types.h"
#include "shader_recompiler/backend/asm_x64/x64_emit_context.h"
namespace Shader::IR {
enum class Attribute : u64;
@ -16,10 +17,6 @@ class Value;
} // namespace Shader::IR
namespace Shader::Backend::X64 {
using Operands = boost::container::static_vector<Xbyak::Operand, 4>;
class EmitContext;
// Microinstruction emitters
void EmitPhi(EmitContext& ctx);

View file

@ -12,8 +12,12 @@ using namespace Xbyak::util;
namespace {
static bool EmitSaveRegTemp(EmitContext ctx, const Reg& save, const Operand& dest) {
if (dest.getIdx() == save.getIdx()) {
static bool IsReg(const OperandHolder& op, const Reg& reg) {
return op.IsReg() && op.Reg().getIdx() == reg.getIdx();
}
static bool EmitSaveRegTemp(EmitContext ctx, const Reg& save, const OperandHolder& dest) {
if (IsReg(dest, save)) {
// Destination is reg, no need to save
return false;
}
@ -28,47 +32,47 @@ static void EmitRestoreRegTemp(EmitContext ctx, const Reg& save) {
} // namespace
void EmitIAdd32(EmitContext& ctx, const Operands& dest, const Operands& op1, const Operands& op2) {
if (dest[0].isREG() && op1[0].isREG() && op2[0].isREG()) {
ctx.Code().lea(dest[0].getReg(), ptr[op1[0].getReg() + op2[0].getReg()]);
if (dest[0].IsReg() && op1[0].IsReg() && op2[0].IsReg()) {
ctx.Code().lea(dest[0].Reg(), ptr[op1[0].Reg() + op2[0].Reg()]);
} else {
Reg tmp = dest[0].isMEM() ? ctx.TempGPReg(false).cvt32() : dest[0].getReg().cvt32();
OperandHolder tmp = op2[0].IsMem() && dest[0].IsMem() ? ctx.TempGPReg().cvt32() : dest[0];
MovGP(ctx, tmp, op1[0]);
ctx.Code().add(tmp, op2[0]);
ctx.Code().add(tmp.Op(), op2[0].Op());
MovGP(ctx, dest[0], tmp);
}
}
void EmitIAdd64(EmitContext& ctx, const Operands& dest, const Operands& op1, const Operands& op2) {
if (dest[0].isREG() && op1[0].isREG() && op2[0].isREG()) {
ctx.Code().lea(dest[0].getReg(), ptr[op1[0].getReg() + op2[0].getReg()]);
if (dest[0].IsReg() && op1[0].IsReg() && op2[0].IsReg()) {
ctx.Code().lea(dest[0].Reg(), ptr[op1[0].Reg() + op2[0].Reg()]);
} else {
Reg tmp = dest[0].isMEM() ? ctx.TempGPReg(false) : dest[0].getReg();
OperandHolder tmp = op2[0].IsMem() && dest[0].IsMem() ? ctx.TempGPReg() : dest[0];
MovGP(ctx, tmp, op1[0]);
ctx.Code().add(tmp, op2[0]);
ctx.Code().add(tmp.Op(), op2[0].Op());
MovGP(ctx, dest[0], tmp);
}
}
void EmitIAddCary32(EmitContext& ctx, const Operands& dest, const Operands& op1, const Operands& op2) {
Reg tmp = dest[0].isMEM() ? ctx.TempGPReg(false).cvt32() : dest[0].getReg().cvt32();
Operand carry = dest[1];
carry.setBit(1);
OperandHolder tmp = op2[0].IsMem() && dest[0].IsMem() ? ctx.TempGPReg().cvt32() : dest[0];
OperandHolder carry = dest[1];
carry.Op().setBit(1);
MovGP(ctx, tmp, op1[0]);
ctx.Code().add(tmp, op2[0]);
ctx.Code().setc(carry);
ctx.Code().add(tmp.Op(), op2[0].Op());
ctx.Code().setc(carry.Op());
}
void EmitISub32(EmitContext& ctx, const Operands& dest, const Operands& op1, const Operands& op2) {
Reg tmp = dest[0].isMEM() ? ctx.TempGPReg(false).cvt32() : dest[0].getReg().cvt32();
OperandHolder tmp = op2[0].IsMem() && dest[0].IsMem() ? ctx.TempGPReg().cvt32() : dest[0];
MovGP(ctx, tmp, op1[0]);
ctx.Code().sub(tmp, op2[0]);
ctx.Code().sub(tmp.Op(), op2[0].Op());
MovGP(ctx, dest[0], tmp);
}
void EmitISub64(EmitContext& ctx, const Operands& dest, const Operands& op1, const Operands& op2) {
Reg tmp = dest[0].isMEM() ? ctx.TempGPReg(false) : dest[0].getReg();
OperandHolder tmp = op2[0].IsMem() && dest[0].IsMem() ? ctx.TempGPReg() : dest[0];
MovGP(ctx, tmp, op1[0]);
ctx.Code().sub(tmp, op2[0]);
ctx.Code().sub(tmp.Op(), op2[0].Op());
MovGP(ctx, dest[0], tmp);
}
@ -81,29 +85,29 @@ void EmitUMulExt(EmitContext& ctx) {
}
void EmitIMul32(EmitContext& ctx, const Operands& dest, const Operands& op1, const Operands& op2) {
Reg tmp = dest[0].isMEM() ? ctx.TempGPReg(false).cvt32() : dest[0].getReg().cvt32();
Reg tmp = dest[0].IsMem() ? ctx.TempGPReg().cvt32() : dest[0].Reg();
MovGP(ctx, tmp, op1[0]);
ctx.Code().imul(tmp, op2[0]);
ctx.Code().imul(tmp, op2[0].Op());
MovGP(ctx, dest[0], tmp);
}
void EmitIMul64(EmitContext& ctx, const Operands& dest, const Operands& op1, const Operands& op2) {
Reg tmp = dest[0].isMEM() ? ctx.TempGPReg(false) : dest[0].getReg();
Reg tmp = dest[0].IsMem() ? ctx.TempGPReg() : dest[0].Reg();
MovGP(ctx, tmp, op1[0]);
ctx.Code().imul(tmp, op2[0]);
ctx.Code().imul(tmp, op2[0].Op());
MovGP(ctx, dest[0], tmp);
}
void EmitSDiv32(EmitContext& ctx, const Operands& dest, const Operands& op1, const Operands& op2) {
bool rax_saved = EmitSaveRegTemp(ctx, rax, dest[0]);
bool rdx_saved = EmitSaveRegTemp(ctx, rdx, dest[0]);
Reg tmp = op2[0].getReg().cvt32();
while (tmp.getIdx() == rax.getIdx()) {
OperandHolder tmp = op2[0];
while (IsReg(tmp, rax)) {
tmp = ctx.TempGPReg().cvt32();
}
MovGP(ctx, tmp, op2[0]);
MovGP(ctx, eax, op1[0]);
ctx.Code().idiv(tmp);
ctx.Code().idiv(tmp.Op());
MovGP(ctx, dest[0], eax);
if (rdx_saved) {
EmitRestoreRegTemp(ctx, rdx);
@ -116,13 +120,13 @@ void EmitSDiv32(EmitContext& ctx, const Operands& dest, const Operands& op1, con
void EmitUDiv32(EmitContext& ctx, const Operands& dest, const Operands& op1, const Operands& op2) {
bool rax_saved = EmitSaveRegTemp(ctx, rax, dest[0]);
bool rdx_saved = EmitSaveRegTemp(ctx, rdx, dest[0]);
Reg tmp = op2[0].getReg().cvt32();
while (tmp.getIdx() == rax.getIdx()) {
OperandHolder tmp = op2[0];
while (IsReg(tmp, rax)) {
tmp = ctx.TempGPReg().cvt32();
}
MovGP(ctx, tmp, op2[0]);
MovGP(ctx, eax, op1[0]);
ctx.Code().div(tmp);
ctx.Code().div(tmp.Op());
MovGP(ctx, dest[0], eax);
if (rdx_saved) {
EmitRestoreRegTemp(ctx, rdx);
@ -135,13 +139,13 @@ void EmitUDiv32(EmitContext& ctx, const Operands& dest, const Operands& op1, con
void EmitSMod32(EmitContext& ctx, const Operands& dest, const Operands& op1, const Operands& op2) {
bool rax_saved = EmitSaveRegTemp(ctx, rax, dest[0]);
bool rdx_saved = EmitSaveRegTemp(ctx, rdx, dest[0]);
Reg tmp = op2[0].getReg().cvt32();
while (tmp.getIdx() == rax.getIdx()) {
OperandHolder tmp = op2[0];
while (IsReg(tmp, rax)) {
tmp = ctx.TempGPReg().cvt32();
}
MovGP(ctx, tmp, op2[0]);
MovGP(ctx, eax, op1[0]);
ctx.Code().idiv(tmp);
ctx.Code().idiv(tmp.Op());
MovGP(ctx, dest[0], edx);
if (rdx_saved) {
EmitRestoreRegTemp(ctx, rdx);
@ -154,13 +158,13 @@ void EmitSMod32(EmitContext& ctx, const Operands& dest, const Operands& op1, con
void EmitUMod32(EmitContext& ctx, const Operands& dest, const Operands& op1, const Operands& op2) {
bool rax_saved = EmitSaveRegTemp(ctx, rax, dest[0]);
bool rdx_saved = EmitSaveRegTemp(ctx, rdx, dest[0]);
Reg tmp = op2[0].getReg().cvt32();
while (tmp.getIdx() == rax.getIdx()) {
OperandHolder tmp = op2[0];
while (IsReg(tmp, rax)) {
tmp = ctx.TempGPReg().cvt32();
}
MovGP(ctx, tmp, op2[0]);
MovGP(ctx, eax, op1[0]);
ctx.Code().div(tmp);
ctx.Code().div(tmp.Op());
MovGP(ctx, dest[0], edx);
if (rdx_saved) {
EmitRestoreRegTemp(ctx, rdx);
@ -171,36 +175,30 @@ void EmitUMod32(EmitContext& ctx, const Operands& dest, const Operands& op1, con
}
void EmitINeg32(EmitContext& ctx, const Operands& dest, const Operands& op) {
Reg tmp = dest[0].isMEM() ? ctx.TempGPReg(false).cvt32() : dest[0].getReg().cvt32();
MovGP(ctx, tmp, op[0]);
ctx.Code().neg(tmp);
MovGP(ctx, dest[0], tmp);
MovGP(ctx, dest[0], op[0]);
ctx.Code().neg(dest[0].Op());
}
void EmitINeg64(EmitContext& ctx, const Operands& dest, const Operands& op) {
Reg tmp = dest[0].isMEM() ? ctx.TempGPReg(false) : dest[0].getReg();
MovGP(ctx, tmp, op[0]);
ctx.Code().neg(tmp);
MovGP(ctx, dest[0], tmp);
MovGP(ctx, dest[0], op[0]);
ctx.Code().neg(dest[0].Op());
}
void EmitIAbs32(EmitContext& ctx, const Operands& dest, const Operands& op) {
Label done;
Reg tmp = dest[0].isMEM() ? ctx.TempGPReg(false).cvt32() : dest[0].getReg().cvt32();
MovGP(ctx, tmp, op[0]);
ctx.Code().cmp(tmp, 0);
MovGP(ctx, dest[0], op[0]);
ctx.Code().cmp(dest[0].Op(), 0);
ctx.Code().jns(done);
ctx.Code().neg(tmp);
ctx.Code().neg(dest[0].Op());
ctx.Code().L(done);
MovGP(ctx, dest[0], tmp);
}
void EmitShiftLeftLogical32(EmitContext& ctx, const Operands& dest, const Operands& base, const Operands& shift) {
bool rcx_saved = EmitSaveRegTemp(ctx, rcx, dest[0]);
Reg tmp = dest[0].getIdx() == rcx.getIdx() ? ctx.TempGPReg(false).cvt32() : dest[0].getReg().cvt32();
OperandHolder tmp = IsReg(dest[0], rcx) ? ctx.TempGPReg().cvt32() : dest[0];
MovGP(ctx, tmp, base[0]);
MovGP(ctx, cl, shift[0]);
ctx.Code().shl(tmp, cl);
ctx.Code().shl(tmp.Op(), cl);
MovGP(ctx, dest[0], tmp);
if (rcx_saved) {
EmitRestoreRegTemp(ctx, rcx);
@ -209,10 +207,10 @@ void EmitShiftLeftLogical32(EmitContext& ctx, const Operands& dest, const Operan
void EmitShiftLeftLogical64(EmitContext& ctx, const Operands& dest, const Operands& base, const Operands& shift) {
bool rcx_saved = EmitSaveRegTemp(ctx, rcx, dest[0]);
Reg tmp = dest[0].getIdx() == rcx.getIdx() ? ctx.TempGPReg(false) : dest[0].getReg();
OperandHolder tmp = IsReg(dest[0], rcx) ? ctx.TempGPReg() : dest[0];
MovGP(ctx, tmp, base[0]);
MovGP(ctx, cl, shift[0]);
ctx.Code().shl(tmp, cl);
ctx.Code().shl(tmp.Op(), cl);
MovGP(ctx, dest[0], tmp);
if (rcx_saved) {
EmitRestoreRegTemp(ctx, rcx);
@ -221,10 +219,10 @@ void EmitShiftLeftLogical64(EmitContext& ctx, const Operands& dest, const Operan
void EmitShiftRightLogical32(EmitContext& ctx, const Operands& dest, const Operands& base, const Operands& shift) {
bool rcx_saved = EmitSaveRegTemp(ctx, rcx, dest[0]);
Reg tmp = dest[0].isMEM() ? ctx.TempGPReg(false).cvt32() : dest[0].getReg().cvt32();
OperandHolder tmp = IsReg(dest[0], rcx) ? ctx.TempGPReg().cvt32() : dest[0];
MovGP(ctx, tmp, base[0]);
MovGP(ctx, cl, shift[0]);
ctx.Code().shr(tmp, cl);
ctx.Code().shr(tmp.Op(), cl);
MovGP(ctx, dest[0], tmp);
if (rcx_saved) {
EmitRestoreRegTemp(ctx, rcx);
@ -233,10 +231,10 @@ void EmitShiftRightLogical32(EmitContext& ctx, const Operands& dest, const Opera
void EmitShiftRightLogical64(EmitContext& ctx, const Operands& dest, const Operands& base, const Operands& shift) {
bool rcx_saved = EmitSaveRegTemp(ctx, rcx, dest[0]);
Reg tmp = dest[0].isMEM() ? ctx.TempGPReg(false) : dest[0].getReg();
OperandHolder tmp = IsReg(dest[0], rcx) ? ctx.TempGPReg() : dest[0];
MovGP(ctx, tmp, base[0]);
MovGP(ctx, cl, shift[0]);
ctx.Code().shr(tmp, cl);
ctx.Code().shr(tmp.Op(), cl);
MovGP(ctx, dest[0], tmp);
if (rcx_saved) {
EmitRestoreRegTemp(ctx, rcx);
@ -245,10 +243,10 @@ void EmitShiftRightLogical64(EmitContext& ctx, const Operands& dest, const Opera
void EmitShiftRightArithmetic32(EmitContext& ctx, const Operands& dest, const Operands& base, const Operands& shift) {
bool rcx_saved = EmitSaveRegTemp(ctx, rcx, dest[0]);
Reg tmp = dest[0].isMEM() ? ctx.TempGPReg(false).cvt32() : dest[0].getReg().cvt32();
OperandHolder tmp = IsReg(dest[0], rcx) ? ctx.TempGPReg().cvt32() : dest[0];
MovGP(ctx, tmp, base[0]);
MovGP(ctx, cl, shift[0]);
ctx.Code().sar(tmp, cl);
ctx.Code().sar(tmp.Op(), cl);
MovGP(ctx, dest[0], tmp);
if (rcx_saved) {
EmitRestoreRegTemp(ctx, rcx);
@ -257,10 +255,10 @@ void EmitShiftRightArithmetic32(EmitContext& ctx, const Operands& dest, const Op
void EmitShiftRightArithmetic64(EmitContext& ctx, const Operands& dest, const Operands& base, const Operands& shift) {
bool rcx_saved = EmitSaveRegTemp(ctx, rcx, dest[0]);
Reg tmp = dest[0].isMEM() ? ctx.TempGPReg(false) : dest[0].getReg();
OperandHolder tmp = IsReg(dest[0], rcx) ? ctx.TempGPReg() : dest[0];
MovGP(ctx, tmp, base[0]);
MovGP(ctx, cl, shift[0]);
ctx.Code().sar(tmp, cl);
ctx.Code().sar(tmp.Op(), cl);
MovGP(ctx, dest[0], tmp);
if (rcx_saved) {
EmitRestoreRegTemp(ctx, rcx);
@ -268,37 +266,37 @@ void EmitShiftRightArithmetic64(EmitContext& ctx, const Operands& dest, const Op
}
void EmitBitwiseAnd32(EmitContext& ctx, const Operands& dest, const Operands& op1, const Operands& op2) {
Reg tmp = dest[0].isMEM() ? ctx.TempGPReg(false).cvt32() : dest[0].getReg().cvt32();
OperandHolder tmp = op2[0].IsMem() && dest[0].IsMem() ? ctx.TempGPReg().cvt32() : dest[0];
MovGP(ctx, tmp, op1[0]);
ctx.Code().and_(tmp, op2[0]);
ctx.Code().and_(tmp.Op(), op2[0].Op());
MovGP(ctx, dest[0], tmp);
}
void EmitBitwiseAnd64(EmitContext& ctx, const Operands& dest, const Operands& op1, const Operands& op2) {
Reg tmp = dest[0].isMEM() ? ctx.TempGPReg(false) : dest[0].getReg();
OperandHolder tmp = op2[0].IsMem() && dest[0].IsMem() ? ctx.TempGPReg() : dest[0];
MovGP(ctx, tmp, op1[0]);
ctx.Code().and_(tmp, op2[0]);
ctx.Code().and_(tmp.Op(), op2[0].Op());
MovGP(ctx, dest[0], tmp);
}
void EmitBitwiseOr32(EmitContext& ctx, const Operands& dest, const Operands& op1, const Operands& op2) {
Reg tmp = dest[0].isMEM() ? ctx.TempGPReg(false).cvt32() : dest[0].getReg().cvt32();
OperandHolder tmp = op2[0].IsMem() && dest[0].IsMem() ? ctx.TempGPReg().cvt32() : dest[0];
MovGP(ctx, tmp, op1[0]);
ctx.Code().or_(tmp, op2[0]);
ctx.Code().or_(tmp.Op(), op2[0].Op());
MovGP(ctx, dest[0], tmp);
}
void EmitBitwiseOr64(EmitContext& ctx, const Operands& dest, const Operands& op1, const Operands& op2) {
Reg tmp = dest[0].isMEM() ? ctx.TempGPReg(false) : dest[0].getReg();
OperandHolder tmp = op2[0].IsMem() && dest[0].IsMem() ? ctx.TempGPReg() : dest[0];
MovGP(ctx, tmp, op1[0]);
ctx.Code().or_(tmp, op2[0]);
ctx.Code().or_(tmp.Op(), op2[0].Op());
MovGP(ctx, dest[0], tmp);
}
void EmitBitwiseXor32(EmitContext& ctx, const Operands& dest, const Operands& op1, const Operands& op2) {
Reg tmp = dest[0].isMEM() ? ctx.TempGPReg(false).cvt32() : dest[0].getReg().cvt32();
OperandHolder tmp = op2[0].IsMem() && dest[0].IsMem() ? ctx.TempGPReg().cvt32() : dest[0];
MovGP(ctx, tmp, op1[0]);
ctx.Code().xor_(tmp, op2[0]);
ctx.Code().xor_(tmp.Op(), op2[0].Op());
MovGP(ctx, dest[0], tmp);
}
@ -327,10 +325,8 @@ void EmitBitCount64(EmitContext& ctx) {
}
void EmitBitwiseNot32(EmitContext& ctx, const Operands& dest, const Operands& op) {
Reg tmp = dest[0].isMEM() ? ctx.TempGPReg(false).cvt32() : dest[0].getReg().cvt32();
MovGP(ctx, tmp, op[0]);
ctx.Code().not_(tmp);
MovGP(ctx, dest[0], tmp);
MovGP(ctx, dest[0], op[0]);
ctx.Code().not_(dest[0].Op());
}
void EmitFindSMsb32(EmitContext& ctx) {
@ -350,153 +346,153 @@ void EmitFindILsb64(EmitContext& ctx) {
}
void EmitSMin32(EmitContext& ctx, const Operands& dest, const Operands& op1, const Operands& op2) {
Reg tmp = dest[0].isMEM() ? ctx.TempGPReg(false).cvt32() : dest[0].getReg().cvt32();
Reg tmp = dest[0].IsMem() ? ctx.TempGPReg().cvt32() : dest[0].Reg();
MovGP(ctx, tmp, op1[0]);
ctx.Code().cmp(tmp, op2[0]);
ctx.Code().cmovg(tmp, op2[0]);
ctx.Code().cmp(tmp, op2[0].Op());
ctx.Code().cmovg(tmp, op2[0].Op());
MovGP(ctx, dest[0], tmp);
}
void EmitUMin32(EmitContext& ctx, const Operands& dest, const Operands& op1, const Operands& op2) {
Reg tmp = dest[0].isMEM() ? ctx.TempGPReg(false).cvt32() : dest[0].getReg().cvt32();
Reg tmp = dest[0].IsMem() ? ctx.TempGPReg().cvt32() : dest[0].Reg();
MovGP(ctx, tmp, op1[0]);
ctx.Code().cmp(tmp, op2[0]);
ctx.Code().cmova(tmp, op2[0]);
ctx.Code().cmp(tmp, op2[0].Op());
ctx.Code().cmova(tmp, op2[0].Op());
MovGP(ctx, dest[0], tmp);
}
void EmitSMax32(EmitContext& ctx, const Operands& dest, const Operands& op1, const Operands& op2) {
Reg tmp = dest[0].isMEM() ? ctx.TempGPReg(false).cvt32() : dest[0].getReg().cvt32();
Reg tmp = dest[0].IsMem() ? ctx.TempGPReg().cvt32() : dest[0].Reg();
MovGP(ctx, tmp, op1[0]);
ctx.Code().cmp(tmp, op2[0]);
ctx.Code().cmovl(tmp, op2[0]);
ctx.Code().cmp(tmp, op2[0].Op());
ctx.Code().cmovl(tmp, op2[0].Op());
MovGP(ctx, dest[0], tmp);
}
void EmitUMax32(EmitContext& ctx, const Operands& dest, const Operands& op1, const Operands& op2) {
Reg tmp = dest[0].isMEM() ? ctx.TempGPReg(false).cvt32() : dest[0].getReg().cvt32();
Reg tmp = dest[0].IsMem() ? ctx.TempGPReg().cvt32() : dest[0].Reg();
MovGP(ctx, tmp, op1[0]);
ctx.Code().cmp(tmp, op2[0]);
ctx.Code().cmovb(tmp, op2[0]);
ctx.Code().cmp(tmp, op2[0].Op());
ctx.Code().cmovb(tmp, op2[0].Op());
MovGP(ctx, dest[0], tmp);
}
void EmitSClamp32(EmitContext& ctx, const Operands& dest, const Operands& value, const Operands& min, const Operands& max) {
Reg tmp = dest[0].isMEM() ? ctx.TempGPReg(false).cvt32() : dest[0].getReg().cvt32();
Reg tmp = dest[0].IsMem() ? ctx.TempGPReg().cvt32() : dest[0].Reg();
MovGP(ctx, tmp, value[0]);
ctx.Code().cmp(tmp, min[0]);
ctx.Code().cmovl(tmp, min[0]);
ctx.Code().cmp(tmp, max[0]);
ctx.Code().cmovg(tmp, max[0]);
ctx.Code().cmp(tmp, min[0].Op());
ctx.Code().cmovl(tmp, min[0].Op());
ctx.Code().cmp(tmp, max[0].Op());
ctx.Code().cmovg(tmp, max[0].Op());
MovGP(ctx, dest[0], tmp);
}
void EmitUClamp32(EmitContext& ctx, const Operands& dest, const Operands& value, const Operands& min, const Operands& max) {
Reg tmp = dest[0].isMEM() ? ctx.TempGPReg(false).cvt32() : dest[0].getReg().cvt32();
Reg tmp = dest[0].IsMem() ? ctx.TempGPReg().cvt32() : dest[0].Reg();
MovGP(ctx, tmp, value[0]);
ctx.Code().cmp(tmp, min[0]);
ctx.Code().cmovb(tmp, min[0]);
ctx.Code().cmp(tmp, max[0]);
ctx.Code().cmova(tmp, max[0]);
ctx.Code().cmp(tmp, min[0].Op());
ctx.Code().cmovb(tmp, min[0].Op());
ctx.Code().cmp(tmp, max[0].Op());
ctx.Code().cmova(tmp, max[0].Op());
MovGP(ctx, dest[0], tmp);
}
void EmitSLessThan32(EmitContext& ctx, const Operands& dest, const Operands& lhs, const Operands& rhs) {
Reg tmp = lhs[0].isMEM() && rhs[0].isMEM() ? ctx.TempGPReg(false).cvt32() : lhs[0].getReg().cvt32();
OperandHolder tmp = lhs[0].IsMem() && rhs[0].IsMem() ? ctx.TempGPReg().cvt32() : lhs[0];
MovGP(ctx, tmp, lhs[0]);
ctx.Code().cmp(tmp, rhs[0]);
ctx.Code().setl(dest[0]);
ctx.Code().cmp(tmp.Op(), rhs[0].Op());
ctx.Code().setl(dest[0].Op());
}
void EmitSLessThan64(EmitContext& ctx, const Operands& dest, const Operands& lhs, const Operands& rhs) {
Reg tmp = lhs[0].isMEM() && rhs[0].isMEM() ? ctx.TempGPReg(false) : lhs[0].getReg();
OperandHolder tmp = lhs[0].IsMem() && rhs[0].IsMem() ? ctx.TempGPReg() : lhs[0];
MovGP(ctx, tmp, lhs[0]);
ctx.Code().cmp(tmp, rhs[0]);
ctx.Code().setl(dest[0]);
ctx.Code().cmp(tmp.Op(), rhs[0].Op());
ctx.Code().setl(dest[0].Op());
}
void EmitULessThan32(EmitContext& ctx, const Operands& dest, const Operands& lhs, const Operands& rhs) {
Reg tmp = lhs[0].isMEM() && rhs[0].isMEM() ? ctx.TempGPReg(false).cvt32() : lhs[0].getReg().cvt32();
OperandHolder tmp = lhs[0].IsMem() && rhs[0].IsMem() ? ctx.TempGPReg().cvt32() : lhs[0];
MovGP(ctx, tmp, lhs[0]);
ctx.Code().cmp(tmp, rhs[0]);
ctx.Code().setb(dest[0]);
ctx.Code().cmp(tmp.Op(), rhs[0].Op());
ctx.Code().setb(dest[0].Op());
}
void EmitULessThan64(EmitContext& ctx, const Operands& dest, const Operands& lhs, const Operands& rhs) {
Reg tmp = lhs[0].isMEM() && rhs[0].isMEM() ? ctx.TempGPReg(false) : lhs[0].getReg();
OperandHolder tmp = lhs[0].IsMem() && rhs[0].IsMem() ? ctx.TempGPReg() : lhs[0];
MovGP(ctx, tmp, lhs[0]);
ctx.Code().cmp(tmp, rhs[0]);
ctx.Code().setb(dest[0]);
ctx.Code().cmp(tmp.Op(), rhs[0].Op());
ctx.Code().setb(dest[0].Op());
}
void EmitIEqual32(EmitContext& ctx, const Operands& dest, const Operands& lhs, const Operands& rhs) {
Reg tmp = lhs[0].isMEM() && rhs[0].isMEM() ? ctx.TempGPReg(false).cvt32() : lhs[0].getReg().cvt32();
OperandHolder tmp = lhs[0].IsMem() && rhs[0].IsMem() ? ctx.TempGPReg().cvt32() : lhs[0];
MovGP(ctx, tmp, lhs[0]);
ctx.Code().cmp(tmp, rhs[0]);
ctx.Code().sete(dest[0]);
ctx.Code().cmp(tmp.Op(), rhs[0].Op());
ctx.Code().sete(dest[0].Op());
}
void EmitIEqual64(EmitContext& ctx, const Operands& dest, const Operands& lhs, const Operands& rhs) {
Reg tmp = lhs[0].isMEM() && rhs[0].isMEM() ? ctx.TempGPReg(false) : lhs[0].getReg();
OperandHolder tmp = lhs[0].IsMem() && rhs[0].IsMem() ? ctx.TempGPReg() : lhs[0];
MovGP(ctx, tmp, lhs[0]);
ctx.Code().cmp(tmp, rhs[0]);
ctx.Code().sete(dest[0]);
ctx.Code().cmp(tmp.Op(), rhs[0].Op());
ctx.Code().sete(dest[0].Op());
}
void EmitSLessThanEqual(EmitContext& ctx, const Operands& dest, const Operands& lhs, const Operands& rhs) {
Reg tmp = lhs[0].isMEM() && rhs[0].isMEM() ? ctx.TempGPReg(false).cvt32() : lhs[0].getReg().cvt32();
OperandHolder tmp = lhs[0].IsMem() && rhs[0].IsMem() ? ctx.TempGPReg().cvt32() : lhs[0];
MovGP(ctx, tmp, lhs[0]);
ctx.Code().cmp(tmp, rhs[0]);
ctx.Code().setle(dest[0]);
ctx.Code().cmp(tmp.Op(), rhs[0].Op());
ctx.Code().setle(dest[0].Op());
}
void EmitULessThanEqual(EmitContext& ctx, const Operands& dest, const Operands& lhs, const Operands& rhs) {
Reg tmp = lhs[0].isMEM() && rhs[0].isMEM() ? ctx.TempGPReg(false).cvt32() : lhs[0].getReg().cvt32();
OperandHolder tmp = lhs[0].IsMem() && rhs[0].IsMem() ? ctx.TempGPReg().cvt32() : lhs[0];
MovGP(ctx, tmp, lhs[0]);
ctx.Code().cmp(tmp, rhs[0]);
ctx.Code().setbe(dest[0]);
ctx.Code().cmp(tmp.Op(), rhs[0].Op());
ctx.Code().setbe(dest[0].Op());
}
void EmitSGreaterThan(EmitContext& ctx, const Operands& dest, const Operands& lhs, const Operands& rhs) {
Reg tmp = lhs[0].isMEM() && rhs[0].isMEM() ? ctx.TempGPReg(false).cvt32() : lhs[0].getReg().cvt32();
OperandHolder tmp = lhs[0].IsMem() && rhs[0].IsMem() ? ctx.TempGPReg().cvt32() : lhs[0];
MovGP(ctx, tmp, lhs[0]);
ctx.Code().cmp(tmp, rhs[0]);
ctx.Code().setg(dest[0]);
ctx.Code().cmp(tmp.Op(), rhs[0].Op());
ctx.Code().setg(dest[0].Op());
}
void EmitUGreaterThan(EmitContext& ctx, const Operands& dest, const Operands& lhs, const Operands& rhs) {
Reg tmp = lhs[0].isMEM() && rhs[0].isMEM() ? ctx.TempGPReg(false).cvt32() : lhs[0].getReg().cvt32();
OperandHolder tmp = lhs[0].IsMem() && rhs[0].IsMem() ? ctx.TempGPReg().cvt32() : lhs[0];
MovGP(ctx, tmp, lhs[0]);
ctx.Code().cmp(tmp, rhs[0]);
ctx.Code().seta(dest[0]);
ctx.Code().cmp(tmp.Op(), rhs[0].Op());
ctx.Code().seta(dest[0].Op());
}
void EmitINotEqual32(EmitContext& ctx, const Operands& dest, const Operands& lhs, const Operands& rhs) {
Reg tmp = lhs[0].isMEM() && rhs[0].isMEM() ? ctx.TempGPReg(false).cvt32() : lhs[0].getReg().cvt32();
OperandHolder tmp = lhs[0].IsMem() && rhs[0].IsMem() ? ctx.TempGPReg().cvt32() : lhs[0];
MovGP(ctx, tmp, lhs[0]);
ctx.Code().cmp(tmp, rhs[0]);
ctx.Code().setne(dest[0]);
ctx.Code().cmp(tmp.Op(), rhs[0].Op());
ctx.Code().setne(dest[0].Op());
}
void EmitINotEqual64(EmitContext& ctx, const Operands& dest, const Operands& lhs, const Operands& rhs) {
Reg tmp = lhs[0].isMEM() && rhs[0].isMEM() ? ctx.TempGPReg(false) : lhs[0].getReg();
OperandHolder tmp = lhs[0].IsMem() && rhs[0].IsMem() ? ctx.TempGPReg() : lhs[0];
MovGP(ctx, tmp, lhs[0]);
ctx.Code().cmp(tmp, rhs[0]);
ctx.Code().setne(dest[0]);
ctx.Code().cmp(tmp.Op(), rhs[0].Op());
ctx.Code().setne(dest[0].Op());
}
void EmitSGreaterThanEqual(EmitContext& ctx, const Operands& dest, const Operands& lhs, const Operands& rhs) {
Reg tmp = lhs[0].isMEM() && rhs[0].isMEM() ? ctx.TempGPReg(false).cvt32() : lhs[0].getReg().cvt32();
OperandHolder tmp = lhs[0].IsMem() && rhs[0].IsMem() ? ctx.TempGPReg().cvt32() : lhs[0];
MovGP(ctx, tmp, lhs[0]);
ctx.Code().cmp(tmp, rhs[0]);
ctx.Code().setge(dest[0]);
ctx.Code().cmp(tmp.Op(), rhs[0].Op());
ctx.Code().setge(dest[0].Op());
}
void EmitUGreaterThanEqual(EmitContext& ctx, const Operands& dest, const Operands& lhs, const Operands& rhs) {
Reg tmp = lhs[0].isMEM() && rhs[0].isMEM() ? ctx.TempGPReg(false).cvt32() : lhs[0].getReg().cvt32();
OperandHolder tmp = lhs[0].IsMem() && rhs[0].IsMem() ? ctx.TempGPReg().cvt32() : lhs[0];
MovGP(ctx, tmp, lhs[0]);
ctx.Code().cmp(tmp, rhs[0]);
ctx.Code().setae(dest[0]);
ctx.Code().cmp(tmp.Op(), rhs[0].Op());
ctx.Code().setae(dest[0].Op());
}
} // namespace Shader::Backend::X64

View file

@ -10,31 +10,29 @@ using namespace Xbyak;
using namespace Xbyak::util;
void EmitLogicalOr(EmitContext& ctx, const Operands& dest, const Operands& op1, const Operands& op2) {
Reg tmp = dest[0].isMEM() ? ctx.TempGPReg().cvt8() : dest[0].getReg().cvt8();
Reg tmp = dest[0].IsMem() ? ctx.TempGPReg().cvt8() : dest[0].Reg().cvt8();
MovGP(ctx, tmp, op1[0]);
ctx.Code().or_(tmp, op2[0]);
ctx.Code().or_(tmp, op2[0].Op());
MovGP(ctx, dest[0], tmp);
}
void EmitLogicalAnd(EmitContext& ctx, const Operands& dest, const Operands& op1, const Operands& op2) {
Reg tmp = dest[0].isMEM() ? ctx.TempGPReg().cvt8() : dest[0].getReg().cvt8();
Reg tmp = dest[0].IsMem() ? ctx.TempGPReg().cvt8() : dest[0].Reg().cvt8();
MovGP(ctx, tmp, op1[0]);
ctx.Code().and_(tmp, op2[0]);
ctx.Code().and_(tmp, op2[0].Op());
MovGP(ctx, dest[0], tmp);
}
void EmitLogicalXor(EmitContext& ctx, const Operands& dest, const Operands& op1, const Operands& op2) {
Reg tmp = dest[0].isMEM() ? ctx.TempGPReg().cvt8() : dest[0].getReg().cvt8();
Reg tmp = dest[0].IsMem() ? ctx.TempGPReg().cvt8() : dest[0].Reg().cvt8();
MovGP(ctx, tmp, op1[0]);
ctx.Code().xor_(tmp, op2[0]);
ctx.Code().xor_(tmp, op2[0].Op());
MovGP(ctx, dest[0], tmp);
}
void EmitLogicalNot(EmitContext& ctx, const Operands& dest, const Operands& op) {
Reg tmp = dest[0].isMEM() ? ctx.TempGPReg().cvt8() : dest[0].getReg().cvt8();
MovGP(ctx, tmp, op[0]);
ctx.Code().not_(tmp);
MovGP(ctx, dest[0], tmp);
MovGP(ctx, dest[0], op[0]);
ctx.Code().not_(dest[0].Op());
}
} // namespace Shader::Backend::X64

View file

@ -11,7 +11,7 @@ using namespace Xbyak::util;
void EmitSelectU1(EmitContext& ctx, const Operands& dest, const Operands& cond, const Operands& true_value, const Operands& false_value) {
Label false_label, end_label;
Reg tmp = cond[0].isMEM() ? ctx.TempGPReg().cvt8() : cond[0].getReg().cvt8();
Reg tmp = cond[0].IsMem() ? ctx.TempGPReg().cvt8() : cond[0].Reg().cvt8();
MovGP(ctx, tmp, cond[0]);
ctx.Code().test(tmp, tmp);
ctx.Code().jz(false_label);
@ -44,7 +44,7 @@ void EmitSelectF16(EmitContext& ctx, const Operands& dest, const Operands& cond,
void EmitSelectF32(EmitContext& ctx, const Operands& dest, const Operands& cond, const Operands& true_value, const Operands& false_value) {
Label false_label, end_label;
Reg tmp = cond[0].isMEM() ? ctx.TempGPReg().cvt8() : cond[0].getReg().cvt8();
Reg tmp = cond[0].IsMem() ? ctx.TempGPReg().cvt8() : cond[0].Reg().cvt8();
MovGP(ctx, tmp, cond[0]);
ctx.Code().test(tmp, tmp);
ctx.Code().jz(false_label);
@ -57,7 +57,7 @@ void EmitSelectF32(EmitContext& ctx, const Operands& dest, const Operands& cond,
void EmitSelectF64(EmitContext& ctx, const Operands& dest, const Operands& cond, const Operands& true_value, const Operands& false_value) {
Label false_label, end_label;
Reg tmp = cond[0].isMEM() ? ctx.TempGPReg().cvt8() : cond[0].getReg().cvt8();
Reg tmp = cond[0].IsMem() ? ctx.TempGPReg().cvt8() : cond[0].Reg().cvt8();
MovGP(ctx, tmp, cond[0]);
ctx.Code().test(tmp, tmp);
ctx.Code().jz(false_label);

View file

@ -30,7 +30,7 @@ void EmitDiscard(EmitContext& ctx) {
}
void EmitDiscardCond(EmitContext& ctx, const Operands& condition) {
Reg tmp = condition[0].isMEM() ? ctx.TempGPReg().cvt8() : condition[0].getReg().cvt8();
Reg tmp = condition[0].IsMem() ? ctx.TempGPReg().cvt8() : condition[0].Reg().cvt8();
MovGP(ctx, tmp, condition[0]);
ctx.Code().test(tmp, tmp);
ctx.Code().jnz(ctx.EndLabel());

View file

@ -76,19 +76,19 @@ Operands EmitContext::Def(const IR::Value& value) {
switch (value.Type()) {
case IR::Type::U1:
operands.push_back(TempGPReg().cvt8());
code.mov(operands.back(), value.U1());
code.mov(operands.back().Reg(), value.U1());
break;
case IR::Type::U8:
operands.push_back(TempGPReg().cvt8());
code.mov(operands.back(), value.U8());
code.mov(operands.back().Reg(), value.U8());
break;
case IR::Type::U16:
operands.push_back(TempGPReg().cvt16());
code.mov(operands.back(), value.U16());
code.mov(operands.back().Reg(), value.U16());
break;
case IR::Type::U32:
operands.push_back(TempGPReg().cvt32());
code.mov(operands.back(), value.U32());
code.mov(operands.back().Reg(), value.U32());
break;
case IR::Type::F32: {
code.mov(tmp.cvt32(), std::bit_cast<u32>(value.F32()));
@ -99,7 +99,7 @@ Operands EmitContext::Def(const IR::Value& value) {
}
case IR::Type::U64:
operands.push_back(TempGPReg());
code.mov(operands.back(), value.U64());
code.mov(operands.back().Reg(), value.U64());
break;
case IR::Type::F64: {
code.mov(tmp, std::bit_cast<u64>(value.F64()));
@ -110,19 +110,19 @@ Operands EmitContext::Def(const IR::Value& value) {
}
case IR::Type::ScalarReg:
operands.push_back(TempGPReg().cvt32());
code.mov(operands.back(), std::bit_cast<u32>(value.ScalarReg()));
code.mov(operands.back().Reg(), std::bit_cast<u32>(value.ScalarReg()));
break;
case IR::Type::VectorReg:
operands.push_back(TempXmmReg().cvt32());
code.mov(operands.back(), std::bit_cast<u32>(value.VectorReg()));
code.mov(operands.back().Reg(), std::bit_cast<u32>(value.VectorReg()));
break;
case IR::Type::Attribute:
operands.push_back(TempGPReg());
code.mov(operands.back(), std::bit_cast<u64>(value.Attribute()));
code.mov(operands.back().Reg(), std::bit_cast<u64>(value.Attribute()));
break;
case IR::Type::Patch:
operands.push_back(TempGPReg());
code.mov(operands.back(), std::bit_cast<u64>(value.Patch()));
code.mov(operands.back().Reg(), std::bit_cast<u64>(value.Patch()));
break;
default:
UNREACHABLE_MSG("Unsupported value type: {}", IR::NameOf(value.Type()));
@ -195,7 +195,7 @@ void EmitContext::SpillInst(RegAllocContext& ctx, const ActiveInstInterval& inte
ctx.active_spill_intervals.push_back(interval);
} else {
Operands& operands = inst_to_operands[spill_candidate->inst];
Reg reg = operands[spill_candidate->component].getReg();
Reg reg = operands[spill_candidate->component].Reg();
inst_to_operands[interval.inst][interval.component] =
reg.isXMM() ? reg : ResizeRegToType(reg, interval.inst);
operands[spill_candidate->component] = get_operand(spill_candidate->inst);
@ -288,7 +288,7 @@ void EmitContext::AllocateRegisters() {
// Free old interval resources
for (auto it = ctx.active_gp_intervals.begin(); it != ctx.active_gp_intervals.end();) {
if (it->end < interval.start) {
Reg64 reg = inst_to_operands[it->inst][it->component].getReg().cvt64();
Reg64 reg = inst_to_operands[it->inst][it->component].Reg().cvt64();
ctx.free_gp_regs.push_back(reg);
it = ctx.active_gp_intervals.erase(it);
} else {
@ -297,7 +297,7 @@ void EmitContext::AllocateRegisters() {
}
for (auto it = ctx.active_xmm_intervals.begin(); it != ctx.active_xmm_intervals.end();) {
if (it->end < interval.start) {
Xmm reg = inst_to_operands[it->inst][it->component].getReg().cvt128();
Xmm reg = inst_to_operands[it->inst][it->component].Xmm();
ctx.free_xmm_regs.push_back(reg);
it = ctx.active_xmm_intervals.erase(it);
} else {
@ -307,7 +307,7 @@ void EmitContext::AllocateRegisters() {
for (auto it = ctx.active_spill_intervals.begin();
it != ctx.active_spill_intervals.end();) {
if (it->end < interval.start) {
const Address& addr = inst_to_operands[it->inst][it->component].getAddress();
const Address& addr = inst_to_operands[it->inst][it->component].Mem();
ctx.free_stack_slots.push_back(addr.getDisp());
it = ctx.active_spill_intervals.erase(it);
} else {

View file

@ -11,7 +11,78 @@
namespace Shader::Backend::X64 {
using Operands = boost::container::static_vector<Xbyak::Operand, 4>;
class OperandHolder {
public:
OperandHolder() : op() {}
OperandHolder(const OperandHolder&) = default;
OperandHolder(OperandHolder&&) = default;
OperandHolder& operator=(const OperandHolder&) = default;
OperandHolder& operator=(OperandHolder&&) = default;
OperandHolder(const Xbyak::Reg& reg_) : reg(reg_) {}
OperandHolder(const Xbyak::Xmm& xmm_) : xmm(xmm_) {}
OperandHolder(const Xbyak::Address& mem_) : mem(mem_) {}
OperandHolder(const Xbyak::Operand& op_) : op(op_) {}
[[nodiscard]] inline Xbyak::Operand& Op() {
return op;
}
[[nodiscard]] inline const Xbyak::Operand& Op() const {
return op;
}
[[nodiscard]] inline Xbyak::Reg& Reg() {
ASSERT(IsReg());
return reg;
}
[[nodiscard]] inline const Xbyak::Reg& Reg() const {
ASSERT(IsReg());
return reg;
}
[[nodiscard]] inline Xbyak::Xmm& Xmm() {
ASSERT(IsXmm());
return xmm;
}
[[nodiscard]] inline const Xbyak::Xmm& Xmm() const {
ASSERT(IsXmm());
return xmm;
}
[[nodiscard]] inline Xbyak::Address& Mem() {
ASSERT(IsMem());
return mem;
}
[[nodiscard]] inline const Xbyak::Address& Mem() const {
ASSERT(IsMem());
return mem;
}
[[nodiscard]] inline bool IsReg() const {
return op.isREG();
}
[[nodiscard]] inline bool IsXmm() const {
return op.isXMM();
}
[[nodiscard]] inline bool IsMem() const {
return op.isMEM();
}
private:
union {
Xbyak::Operand op;
Xbyak::Reg reg;
Xbyak::Xmm xmm;
Xbyak::Address mem;
};
};
using Operands = boost::container::static_vector<OperandHolder, 4>;
class EmitContext {
public:

View file

@ -107,63 +107,73 @@ Reg ResizeRegToType(const Reg& reg, const IR::Value& value) {
return reg;
}
void MovFloat(EmitContext& ctx, const Xbyak::Operand& dst, const Xbyak::Operand& src) {
void MovFloat(EmitContext& ctx, const OperandHolder& dst, const OperandHolder& src) {
CodeGenerator& c = ctx.Code();
if (src == dst) {
if (src.Op() == dst.Op()) {
return;
}
if (src.isMEM() && dst.isMEM()) {
if (src.IsMem() && dst.IsMem()) {
Reg tmp = ctx.TempGPReg(false).cvt32();
c.mov(tmp, src);
c.mov(dst, tmp);
} else if (src.isMEM() && dst.isXMM()) {
c.movss(dst.getReg().cvt128(), src.getAddress());
} else if (src.isXMM() && dst.isMEM()) {
c.movss(dst.getAddress(), src.getReg().cvt128());
} else if (src.isXMM() && dst.isXMM()) {
c.movaps(dst.getReg().cvt128(), src.getReg().cvt128());
c.mov(tmp, src.Mem());
c.mov(dst.Mem(), tmp);
} else if (src.IsMem() && dst.IsXmm()) {
c.movss(dst.Xmm(), src.Mem());
} else if (src.IsXmm() && dst.IsMem()) {
c.movss(dst.Mem(), src.Xmm());
} else if (src.IsXmm() && dst.IsXmm()) {
c.movaps(dst.Xmm(), src.Xmm());
} else {
UNREACHABLE_MSG("Unsupported mov float {} {}", src.toString(), dst.toString());
UNREACHABLE_MSG("Unsupported mov float {} {}", src.Op().toString(), dst.Op().toString());
}
}
void MovDouble(EmitContext& ctx, const Xbyak::Operand& dst, const Xbyak::Operand& src) {
void MovDouble(EmitContext& ctx, const OperandHolder& dst, const OperandHolder& src) {
CodeGenerator& c = ctx.Code();
if (src == dst) {
if (src.Op() == dst.Op()) {
return;
}
if (src.isMEM() && dst.isMEM()) {
if (src.IsMem() && dst.IsMem()) {
const Reg64& tmp = ctx.TempGPReg(false);
c.mov(tmp, src);
c.mov(dst, tmp);
} else if (src.isMEM() && dst.isXMM()) {
c.movsd(dst.getReg().cvt128(), src.getAddress());
} else if (src.isXMM() && dst.isMEM()) {
c.movsd(dst.getAddress(), src.getReg().cvt128());
} else if (src.isXMM() && dst.isXMM()) {
c.movapd(dst.getReg().cvt128(), src.getReg().cvt128());
c.mov(tmp, src.Mem());
c.mov(dst.Mem(), tmp);
} else if (src.IsMem() && dst.IsXmm()) {
c.movsd(dst.Xmm(), src.Mem());
} else if (src.IsXmm() && dst.IsMem()) {
c.movsd(dst.Mem(), src.Xmm());
} else if (src.IsXmm() && dst.IsXmm()) {
c.movapd(dst.Xmm(), src.Xmm());
} else {
UNREACHABLE_MSG("Unsupported mov double {} {}", src.toString(), dst.toString());
UNREACHABLE_MSG("Unsupported mov double {} {}", src.Op().toString(), dst.Op().toString());
}
}
void MovGP(EmitContext& ctx, const Xbyak::Operand& dst, const Xbyak::Operand& src) {
void MovGP(EmitContext& ctx, const OperandHolder& dst, const OperandHolder& src) {
CodeGenerator& c = ctx.Code();
if (src == dst) {
if (src.Op() == dst.Op()) {
return;
}
Reg tmp = dst.isMEM() ? ctx.TempGPReg(false).changeBit(dst.getBit()) : dst.getReg();
if (src.getBit() < dst.getBit() && !src.isBit(32)) {
c.movzx(tmp, src);
} else if (src.getBit() > dst.getBit()) {
Operand src_tmp = src;
src_tmp.setBit(dst.getBit());
c.mov(tmp, src_tmp);
const bool is_mem2mem = src.IsMem() && dst.IsMem();
const u32 src_bit = src.Op().getBit();
const u32 dst_bit = dst.Op().getBit();
OperandHolder tmp = is_mem2mem ? ctx.TempGPReg(false).changeBit(dst_bit) : dst;
if (src_bit < dst_bit) {
if (!dst.IsMem() && !src.Op().isBit(32)) {
c.movzx(tmp.Reg(), src.Op());
} else {
if (dst.IsMem()) {
c.mov(tmp.Op(), 0);
}
c.mov(tmp.Op(), src.Op());
}
} else if (src_bit > dst_bit) {
OperandHolder src_tmp = src;
src_tmp.Op().setBit(dst_bit);
c.mov(tmp.Op(), src_tmp.Op());
} else {
c.mov(tmp, src);
c.mov(tmp.Op(), src.Op());
}
if (dst.isMEM()) {
c.mov(dst, tmp);
if (is_mem2mem) {
c.mov(dst.Op(), tmp.Op());
}
}
@ -194,56 +204,56 @@ void MovValue(EmitContext& ctx, const Operands& dst, const IR::Value& src) {
}
} else {
CodeGenerator& c = ctx.Code();
const bool is_mem = dst[0].isMEM();
const bool is_mem = dst[0].IsMem();
Reg64& tmp = ctx.TempGPReg(false);
switch (src.Type()) {
case IR::Type::U1:
c.mov(is_mem ? tmp.cvt8() : dst[0], src.U1());
c.mov(is_mem ? tmp.cvt8() : dst[0].Reg(), src.U1());
break;
case IR::Type::U8:
c.mov(is_mem ? tmp.cvt8() : dst[0], src.U8());
c.mov(is_mem ? tmp.cvt8() : dst[0].Reg(), src.U8());
break;
case IR::Type::U16:
c.mov(is_mem ? tmp.cvt16() : dst[0], src.U16());
c.mov(is_mem ? tmp.cvt16() : dst[0].Reg(), src.U16());
break;
case IR::Type::U32:
c.mov(is_mem ? tmp.cvt32() : dst[0], src.U32());
c.mov(is_mem ? tmp.cvt32() : dst[0].Reg(), src.U32());
break;
case IR::Type::F32:
c.mov(tmp.cvt32(), std::bit_cast<u32>(src.F32()));
c.mov(tmp.cvt32(), static_cast<u32>(src.F32()));
if (!is_mem) {
c.movd(dst[0].getReg().cvt128(), tmp.cvt32());
c.movd(dst[0].Xmm(), tmp.cvt32());
return;
}
break;
case IR::Type::U64:
c.mov(is_mem ? tmp : dst[0], src.U64());
c.mov(is_mem ? tmp : dst[0].Reg(), src.U64());
break;
case IR::Type::F64:
c.mov(tmp, std::bit_cast<u64>(src.F64()));
c.mov(tmp, static_cast<u64>(src.F64()));
if (!is_mem) {
c.movq(dst[0].getReg().cvt128(), tmp);
c.movq(dst[0].Xmm(), tmp);
return;
}
break;
case IR::Type::ScalarReg:
c.mov(is_mem ? tmp.cvt32() : dst[0], std::bit_cast<u32>(src.ScalarReg()));
c.mov(is_mem ? tmp.cvt32() : dst[0].Reg(), static_cast<u32>(src.ScalarReg()));
break;
case IR::Type::VectorReg:
c.mov(is_mem ? tmp.cvt32() : dst[0], std::bit_cast<u32>(src.VectorReg()));
c.mov(is_mem ? tmp.cvt32() : dst[0].Reg(), static_cast<u32>(src.VectorReg()));
break;
case IR::Type::Attribute:
c.mov(is_mem ? tmp : dst[0], std::bit_cast<u64>(src.Attribute()));
c.mov(is_mem ? tmp : dst[0].Reg(), std::bit_cast<u64>(src.Attribute()));
break;
case IR::Type::Patch:
c.mov(is_mem ? tmp : dst[0], std::bit_cast<u64>(src.Patch()));
c.mov(is_mem ? tmp : dst[0].Reg(), std::bit_cast<u64>(src.Patch()));
break;
default:
UNREACHABLE_MSG("Unsupported type {}", IR::NameOf(src.Type()));
break;
}
if (is_mem) {
c.mov(dst[0], tmp);
c.mov(dst[0].Mem(), tmp);
}
}
}

View file

@ -14,9 +14,9 @@ bool IsFloatingType(const IR::Value& value);
size_t GetRegBytesOfType(const IR::Value& value);
u8 GetNumComponentsOfType(const IR::Value& value);
Xbyak::Reg ResizeRegToType(const Xbyak::Reg& reg, const IR::Value& value);
void MovFloat(EmitContext& ctx, const Xbyak::Operand& dst, const Xbyak::Operand& src);
void MovDouble(EmitContext& ctx, const Xbyak::Operand& dst, const Xbyak::Operand& src);
void MovGP(EmitContext& ctx, const Xbyak::Operand& dst, const Xbyak::Operand& src);
void MovFloat(EmitContext& ctx, const OperandHolder& dst, const OperandHolder& src);
void MovDouble(EmitContext& ctx, const OperandHolder& dst, const OperandHolder& src);
void MovGP(EmitContext& ctx, const OperandHolder& dst, const OperandHolder& src);
void MovValue(EmitContext& ctx, const Operands& dst, const IR::Value& src);
void EmitInlineF16ToF32(EmitContext& ctx, const Xbyak::Operand& dest, const Xbyak::Operand& src);
void EmitInlineF32ToF16(EmitContext& ctx, const Xbyak::Operand& dest, const Xbyak::Operand& src);