machinst x64: implement float-to-int and int-to-float conversions;
This commit is contained in:
@@ -220,18 +220,60 @@ pub enum Inst {
|
||||
srcloc: Option<SourceLoc>,
|
||||
},
|
||||
|
||||
/// XMM (scalar) unary op (from xmm to integer reg): movd, movq
|
||||
/// XMM (scalar) unary op (from xmm to integer reg): movd, movq, cvtts{s,d}2si
|
||||
XmmToGpr {
|
||||
op: SseOpcode,
|
||||
src: Reg,
|
||||
dst: Writable<Reg>,
|
||||
dst_size: OperandSize,
|
||||
},
|
||||
|
||||
/// XMM (scalar) unary op (from integer to float reg): movd, movq
|
||||
/// XMM (scalar) unary op (from integer to float reg): movd, movq, cvtsi2s{s,d}
|
||||
GprToXmm {
|
||||
op: SseOpcode,
|
||||
src: RegMem,
|
||||
dst: Writable<Reg>,
|
||||
src_size: OperandSize,
|
||||
},
|
||||
|
||||
/// Converts an unsigned int64 to a float64.
|
||||
CvtUint64ToFloatSeq {
|
||||
/// Is the target a 64-bits or 32-bits register?
|
||||
to_f64: bool,
|
||||
src: Reg,
|
||||
dst: Writable<Reg>,
|
||||
tmp_gpr1: Writable<Reg>,
|
||||
tmp_gpr2: Writable<Reg>,
|
||||
},
|
||||
|
||||
/// Converts a scalar xmm to a signed int32/int64.
|
||||
CvtFloatToSintSeq {
|
||||
dst_size: OperandSize,
|
||||
src_size: OperandSize,
|
||||
/// A copy of the source register, fed by lowering. It is marked as modified during
|
||||
/// register allocation to make sure that the temporary xmm register differs from the src
|
||||
/// register, since both registers are live at the same time in the generated code
|
||||
/// sequence.
|
||||
src: Writable<Reg>,
|
||||
dst: Writable<Reg>,
|
||||
tmp_gpr: Writable<Reg>,
|
||||
tmp_xmm: Writable<Reg>,
|
||||
srcloc: SourceLoc,
|
||||
},
|
||||
|
||||
/// Converts a scalar xmm to an unsigned int32/int64.
|
||||
CvtFloatToUintSeq {
|
||||
src_size: OperandSize,
|
||||
dst_size: OperandSize,
|
||||
/// A copy of the source register, fed by lowering, reused as a temporary. It is marked as
|
||||
/// modified during register allocation to make sure that the temporary xmm register
|
||||
/// differs from the src register, since both registers are live at the same time in the
|
||||
/// generated code sequence.
|
||||
src: Writable<Reg>,
|
||||
dst: Writable<Reg>,
|
||||
tmp_gpr: Writable<Reg>,
|
||||
tmp_xmm: Writable<Reg>,
|
||||
srcloc: SourceLoc,
|
||||
},
|
||||
|
||||
/// XMM (scalar) conditional move.
|
||||
@@ -475,24 +517,111 @@ impl Inst {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn xmm_to_gpr(op: SseOpcode, src: Reg, dst: Writable<Reg>) -> Inst {
|
||||
pub(crate) fn xmm_to_gpr(
|
||||
op: SseOpcode,
|
||||
src: Reg,
|
||||
dst: Writable<Reg>,
|
||||
dst_size: OperandSize,
|
||||
) -> Inst {
|
||||
debug_assert!(src.get_class() == RegClass::V128);
|
||||
debug_assert!(dst.to_reg().get_class() == RegClass::I64);
|
||||
Inst::XmmToGpr { op, src, dst }
|
||||
Inst::XmmToGpr {
|
||||
op,
|
||||
src,
|
||||
dst,
|
||||
dst_size,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn gpr_to_xmm(op: SseOpcode, src: RegMem, dst: Writable<Reg>) -> Inst {
|
||||
pub(crate) fn gpr_to_xmm(
|
||||
op: SseOpcode,
|
||||
src: RegMem,
|
||||
src_size: OperandSize,
|
||||
dst: Writable<Reg>,
|
||||
) -> Inst {
|
||||
src.assert_regclass_is(RegClass::I64);
|
||||
debug_assert!(dst.to_reg().get_class() == RegClass::V128);
|
||||
Inst::GprToXmm { op, src, dst }
|
||||
Inst::GprToXmm {
|
||||
op,
|
||||
src,
|
||||
dst,
|
||||
src_size,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn xmm_cmp_rm_r(op: SseOpcode, src: RegMem, dst: Reg) -> Inst {
|
||||
//TODO:: Add assert_reg_type helper
|
||||
src.assert_regclass_is(RegClass::V128);
|
||||
debug_assert!(dst.get_class() == RegClass::V128);
|
||||
Inst::XMM_Cmp_RM_R { op, src, dst }
|
||||
}
|
||||
|
||||
pub(crate) fn cvt_u64_to_float_seq(
|
||||
to_f64: bool,
|
||||
src: Reg,
|
||||
tmp_gpr1: Writable<Reg>,
|
||||
tmp_gpr2: Writable<Reg>,
|
||||
dst: Writable<Reg>,
|
||||
) -> Inst {
|
||||
debug_assert!(src.get_class() == RegClass::I64);
|
||||
debug_assert!(tmp_gpr1.to_reg().get_class() == RegClass::I64);
|
||||
debug_assert!(tmp_gpr2.to_reg().get_class() == RegClass::I64);
|
||||
debug_assert!(dst.to_reg().get_class() == RegClass::V128);
|
||||
Inst::CvtUint64ToFloatSeq {
|
||||
src,
|
||||
dst,
|
||||
tmp_gpr1,
|
||||
tmp_gpr2,
|
||||
to_f64,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn cvt_float_to_sint_seq(
|
||||
src_size: OperandSize,
|
||||
dst_size: OperandSize,
|
||||
src: Writable<Reg>,
|
||||
dst: Writable<Reg>,
|
||||
tmp_xmm: Writable<Reg>,
|
||||
tmp_gpr: Writable<Reg>,
|
||||
srcloc: SourceLoc,
|
||||
) -> Inst {
|
||||
debug_assert!(src.to_reg().get_class() == RegClass::V128);
|
||||
debug_assert!(tmp_xmm.to_reg().get_class() == RegClass::V128);
|
||||
debug_assert!(tmp_gpr.to_reg().get_class() == RegClass::I64);
|
||||
debug_assert!(dst.to_reg().get_class() == RegClass::I64);
|
||||
Inst::CvtFloatToSintSeq {
|
||||
src,
|
||||
dst,
|
||||
src_size,
|
||||
dst_size,
|
||||
tmp_gpr,
|
||||
tmp_xmm,
|
||||
srcloc,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn cvt_float_to_uint_seq(
|
||||
src_size: OperandSize,
|
||||
dst_size: OperandSize,
|
||||
src: Writable<Reg>,
|
||||
dst: Writable<Reg>,
|
||||
tmp_gpr: Writable<Reg>,
|
||||
tmp_xmm: Writable<Reg>,
|
||||
srcloc: SourceLoc,
|
||||
) -> Inst {
|
||||
debug_assert!(src.to_reg().get_class() == RegClass::V128);
|
||||
debug_assert!(tmp_xmm.to_reg().get_class() == RegClass::V128);
|
||||
debug_assert!(dst.to_reg().get_class() == RegClass::I64);
|
||||
Inst::CvtFloatToUintSeq {
|
||||
src,
|
||||
dst,
|
||||
src_size,
|
||||
dst_size,
|
||||
tmp_gpr,
|
||||
tmp_xmm,
|
||||
srcloc,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn movzx_rm_r(
|
||||
ext_mode: ExtMode,
|
||||
src: RegMem,
|
||||
@@ -844,11 +973,15 @@ impl ShowWithRRU for Inst {
|
||||
show_ireg_sized(dst.to_reg(), mb_rru, 8),
|
||||
),
|
||||
|
||||
Inst::XmmToGpr { op, src, dst } => {
|
||||
let dst_size = match op {
|
||||
SseOpcode::Movd => 4,
|
||||
SseOpcode::Movq => 8,
|
||||
_ => panic!("unexpected sse opcode"),
|
||||
Inst::XmmToGpr {
|
||||
op,
|
||||
src,
|
||||
dst,
|
||||
dst_size,
|
||||
} => {
|
||||
let dst_size = match dst_size {
|
||||
OperandSize::Size32 => 4,
|
||||
OperandSize::Size64 => 8,
|
||||
};
|
||||
format!(
|
||||
"{} {}, {}",
|
||||
@@ -858,19 +991,17 @@ impl ShowWithRRU for Inst {
|
||||
)
|
||||
}
|
||||
|
||||
Inst::GprToXmm { op, src, dst } => {
|
||||
let src_size = match op {
|
||||
SseOpcode::Movd => 4,
|
||||
SseOpcode::Movq => 8,
|
||||
_ => panic!("unexpected sse opcode"),
|
||||
};
|
||||
format!(
|
||||
"{} {}, {}",
|
||||
ljustify(op.to_string()),
|
||||
src.show_rru_sized(mb_rru, src_size),
|
||||
dst.show_rru(mb_rru)
|
||||
)
|
||||
}
|
||||
Inst::GprToXmm {
|
||||
op,
|
||||
src,
|
||||
src_size,
|
||||
dst,
|
||||
} => format!(
|
||||
"{} {}, {}",
|
||||
ljustify(op.to_string()),
|
||||
src.show_rru_sized(mb_rru, src_size.to_bytes()),
|
||||
dst.show_rru(mb_rru)
|
||||
),
|
||||
|
||||
Inst::XMM_Cmp_RM_R { op, src, dst } => format!(
|
||||
"{} {}, {}",
|
||||
@@ -878,6 +1009,69 @@ impl ShowWithRRU for Inst {
|
||||
src.show_rru_sized(mb_rru, 8),
|
||||
show_ireg_sized(*dst, mb_rru, 8),
|
||||
),
|
||||
|
||||
Inst::CvtUint64ToFloatSeq {
|
||||
src, dst, to_f64, ..
|
||||
} => format!(
|
||||
"{} {}, {}",
|
||||
ljustify(format!(
|
||||
"u64_to_{}_seq",
|
||||
if *to_f64 { "f64" } else { "f32" }
|
||||
)),
|
||||
show_ireg_sized(*src, mb_rru, 8),
|
||||
dst.show_rru(mb_rru),
|
||||
),
|
||||
|
||||
Inst::CvtFloatToSintSeq {
|
||||
src,
|
||||
dst,
|
||||
src_size,
|
||||
dst_size,
|
||||
..
|
||||
} => format!(
|
||||
"{} {}, {}",
|
||||
ljustify(format!(
|
||||
"cvt_float{}_to_sint{}_seq",
|
||||
if *src_size == OperandSize::Size64 {
|
||||
"64"
|
||||
} else {
|
||||
"32"
|
||||
},
|
||||
if *dst_size == OperandSize::Size64 {
|
||||
"64"
|
||||
} else {
|
||||
"32"
|
||||
}
|
||||
)),
|
||||
show_ireg_sized(src.to_reg(), mb_rru, 8),
|
||||
show_ireg_sized(dst.to_reg(), mb_rru, dst_size.to_bytes()),
|
||||
),
|
||||
|
||||
Inst::CvtFloatToUintSeq {
|
||||
src,
|
||||
dst,
|
||||
src_size,
|
||||
dst_size,
|
||||
..
|
||||
} => format!(
|
||||
"{} {}, {}",
|
||||
ljustify(format!(
|
||||
"cvt_float{}_to_uint{}_seq",
|
||||
if *src_size == OperandSize::Size64 {
|
||||
"64"
|
||||
} else {
|
||||
"32"
|
||||
},
|
||||
if *dst_size == OperandSize::Size64 {
|
||||
"64"
|
||||
} else {
|
||||
"32"
|
||||
}
|
||||
)),
|
||||
show_ireg_sized(src.to_reg(), mb_rru, 8),
|
||||
show_ireg_sized(dst.to_reg(), mb_rru, dst_size.to_bytes()),
|
||||
),
|
||||
|
||||
Inst::Imm_R {
|
||||
dst_is_64,
|
||||
simm64,
|
||||
@@ -1151,6 +1345,42 @@ fn x64_get_regs(inst: &Inst, collector: &mut RegUsageCollector) {
|
||||
src.get_regs_as_uses(collector);
|
||||
collector.add_def(*dst);
|
||||
}
|
||||
Inst::CvtUint64ToFloatSeq {
|
||||
src,
|
||||
dst,
|
||||
tmp_gpr1,
|
||||
tmp_gpr2,
|
||||
..
|
||||
} => {
|
||||
collector.add_use(*src);
|
||||
collector.add_def(*dst);
|
||||
collector.add_def(*tmp_gpr1);
|
||||
collector.add_def(*tmp_gpr2);
|
||||
}
|
||||
Inst::CvtFloatToSintSeq {
|
||||
src,
|
||||
dst,
|
||||
tmp_xmm,
|
||||
tmp_gpr,
|
||||
..
|
||||
} => {
|
||||
collector.add_mod(*src);
|
||||
collector.add_def(*dst);
|
||||
collector.add_def(*tmp_xmm);
|
||||
collector.add_def(*tmp_gpr);
|
||||
}
|
||||
Inst::CvtFloatToUintSeq {
|
||||
src,
|
||||
dst,
|
||||
tmp_gpr,
|
||||
tmp_xmm,
|
||||
..
|
||||
} => {
|
||||
collector.add_mod(*src);
|
||||
collector.add_def(*dst);
|
||||
collector.add_def(*tmp_gpr);
|
||||
collector.add_def(*tmp_xmm);
|
||||
}
|
||||
Inst::MovZX_RM_R { src, dst, .. } => {
|
||||
src.get_regs_as_uses(collector);
|
||||
collector.add_def(*dst);
|
||||
@@ -1385,6 +1615,42 @@ fn x64_map_regs<RUM: RegUsageMapper>(inst: &mut Inst, mapper: &RUM) {
|
||||
src.map_uses(mapper);
|
||||
map_def(mapper, dst);
|
||||
}
|
||||
Inst::CvtUint64ToFloatSeq {
|
||||
ref mut src,
|
||||
ref mut dst,
|
||||
ref mut tmp_gpr1,
|
||||
ref mut tmp_gpr2,
|
||||
..
|
||||
} => {
|
||||
map_use(mapper, src);
|
||||
map_def(mapper, dst);
|
||||
map_def(mapper, tmp_gpr1);
|
||||
map_def(mapper, tmp_gpr2);
|
||||
}
|
||||
Inst::CvtFloatToSintSeq {
|
||||
ref mut src,
|
||||
ref mut dst,
|
||||
ref mut tmp_xmm,
|
||||
ref mut tmp_gpr,
|
||||
..
|
||||
} => {
|
||||
map_mod(mapper, src);
|
||||
map_def(mapper, dst);
|
||||
map_def(mapper, tmp_xmm);
|
||||
map_def(mapper, tmp_gpr);
|
||||
}
|
||||
Inst::CvtFloatToUintSeq {
|
||||
ref mut src,
|
||||
ref mut dst,
|
||||
ref mut tmp_gpr,
|
||||
ref mut tmp_xmm,
|
||||
..
|
||||
} => {
|
||||
map_mod(mapper, src);
|
||||
map_def(mapper, dst);
|
||||
map_def(mapper, tmp_gpr);
|
||||
map_def(mapper, tmp_xmm);
|
||||
}
|
||||
Inst::MovZX_RM_R {
|
||||
ref mut src,
|
||||
ref mut dst,
|
||||
@@ -1571,7 +1837,7 @@ impl MachInst for Inst {
|
||||
RegClass::V128 => match ty {
|
||||
F32 => Inst::xmm_mov(SseOpcode::Movss, RegMem::reg(src_reg), dst_reg, None),
|
||||
F64 => Inst::xmm_mov(SseOpcode::Movsd, RegMem::reg(src_reg), dst_reg, None),
|
||||
_ => panic!("unexpected V128 type in gen_move"),
|
||||
_ => panic!("unexpected type {:?} in gen_move of regclass V128", ty),
|
||||
},
|
||||
_ => panic!("gen_move(x64): unhandled regclass"),
|
||||
}
|
||||
@@ -1624,6 +1890,7 @@ impl MachInst for Inst {
|
||||
ret.push(Inst::gpr_to_xmm(
|
||||
SseOpcode::Movd,
|
||||
RegMem::reg(tmp.to_reg()),
|
||||
OperandSize::Size32,
|
||||
to_reg,
|
||||
));
|
||||
}
|
||||
@@ -1635,6 +1902,7 @@ impl MachInst for Inst {
|
||||
ret.push(Inst::gpr_to_xmm(
|
||||
SseOpcode::Movq,
|
||||
RegMem::reg(tmp.to_reg()),
|
||||
OperandSize::Size64,
|
||||
to_reg,
|
||||
));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user