@@ -4,6 +4,7 @@ use ir::node::FunctionRef;
44use crate :: {
55 cfg:: Block ,
66 code_buffer:: { BufferRelocTarget , CodeBuffer , FixupKind , InstrAnchor , InstrSink , Label } ,
7+ constpool:: Constant ,
78 emit:: { EmitContext , EmitInstrData } ,
89 frame:: FrameLayout ,
910 lir:: { Instr , PhysReg , PhysRegSet , StackSlot } ,
@@ -323,6 +324,14 @@ impl MachineEmit for X64Machine {
323324 defs[ 1 ] . as_reg ( ) . unwrap ( ) ,
324325 defs[ 2 ] . as_reg ( ) . unwrap ( ) ,
325326 ) ,
327+ & X64Instr :: PseudoFloatToUint64Rel ( prec) => emit_float_to_uint64_rel (
328+ buffer,
329+ prec,
330+ defs[ 0 ] . as_reg ( ) . unwrap ( ) ,
331+ uses[ 0 ] . as_reg ( ) . unwrap ( ) ,
332+ defs[ 1 ] . as_reg ( ) . unwrap ( ) ,
333+ defs[ 2 ] . as_reg ( ) . unwrap ( ) ,
334+ ) ,
326335 & X64Instr :: MovGprmXmm ( op_size) => emit_mov_gprm_xmm (
327336 buffer,
328337 op_size,
@@ -607,6 +616,63 @@ fn emit_uint64_to_float(
607616 buffer. bind_label ( done) ;
608617}
609618
619+ fn emit_float_to_uint64_rel (
620+ buffer : & mut CodeBuffer < X64Fixup > ,
621+ prec : SseFpuPrecision ,
622+ dest : PhysReg ,
623+ src : PhysReg ,
624+ tmp_xmm1 : PhysReg ,
625+ tmp_xmm2 : PhysReg ,
626+ ) {
627+ // Emit the following:
628+ //
629+ // movsd tmp_xmm1, [rip + C_f_1p63]
630+ // ucomis[sd] src, tmp_xmm1
631+ // jae has_high_bit
632+ // cvts[sd]2si dest, src
633+ // jmp done
634+ // has_high_bit:
635+ // mov tmp_xmm2, src
636+ // subsd tmp_xmm2, tmp_xmm1
637+ // cvts[sd]2si dest, tmp_xmm2
638+ // btc dest
639+ // done:
640+
641+ let high_bit_set = buffer. create_label ( ) ;
642+ let done = buffer. create_label ( ) ;
643+
644+ let f_1p63 = get_f_1p63 ( buffer, prec) ;
645+ emit_movs_r_rm_rip_reloc ( buffer, prec, tmp_xmm1, BufferRelocTarget :: Constant ( f_1p63) ) ;
646+ emit_ucomi ( buffer, prec, src, RegMem :: Reg ( tmp_xmm1) ) ;
647+ emit_jcc ( buffer, CondCode :: Ae , high_bit_set) ;
648+
649+ emit_cvts2si ( buffer, OperandSize :: S64 , prec, dest, RegMem :: Reg ( src) ) ;
650+ emit_jmp ( buffer, done) ;
651+
652+ buffer. bind_label ( high_bit_set) ;
653+ if tmp_xmm2 != src {
654+ emit_movaps_r_rm ( buffer, tmp_xmm2, RegMem :: Reg ( src) ) ;
655+ }
656+ emit_sse_fpu_r_rm (
657+ buffer,
658+ prec,
659+ SseFpuBinOp :: Sub ,
660+ tmp_xmm2,
661+ RegMem :: Reg ( tmp_xmm1) ,
662+ ) ;
663+ emit_cvts2si ( buffer, OperandSize :: S64 , prec, dest, RegMem :: Reg ( tmp_xmm2) ) ;
664+ emit_btc_rm_i ( buffer, OperandSize :: S64 , RegMem :: Reg ( dest) , 63 ) ;
665+
666+ buffer. bind_label ( done) ;
667+ }
668+
669+ fn get_f_1p63 ( buffer : & mut CodeBuffer < X64Fixup > , prec : SseFpuPrecision ) -> Constant {
670+ match prec {
671+ SseFpuPrecision :: Single => buffer. get_constant ( 4 , & 0x5f000000u32 . to_le_bytes ( ) ) ,
672+ SseFpuPrecision :: Double => buffer. get_constant ( 8 , & 0x43e0000000000000u64 . to_le_bytes ( ) ) ,
673+ }
674+ }
675+
610676// Single-instruction emission helpers
611677
612678fn emit_push ( buffer : & mut CodeBuffer < X64Fixup > , reg : PhysReg ) {
@@ -960,6 +1026,19 @@ fn emit_setcc_r(buffer: &mut CodeBuffer<X64Fixup>, code: CondCode, dest: PhysReg
9601026 } ) ;
9611027}
9621028
1029+ fn emit_btc_rm_i ( buffer : & mut CodeBuffer < X64Fixup > , op_size : OperandSize , arg : RegMem , imm : u8 ) {
1030+ let ( rex, modrm_sib) = encode_reg_mem_parts ( arg, |rex| {
1031+ rex. encode_operand_size ( op_size) ;
1032+ 0x7
1033+ } ) ;
1034+ buffer. instr ( |sink| {
1035+ rex. emit ( sink) ;
1036+ sink. emit ( & [ 0xf , 0xba ] ) ;
1037+ modrm_sib. emit ( sink) ;
1038+ sink. emit ( & [ imm] ) ;
1039+ } ) ;
1040+ }
1041+
9631042fn emit_movsx_r_rm ( buffer : & mut CodeBuffer < X64Fixup > , width : ExtWidth , dest : PhysReg , src : RegMem ) {
9641043 let ( opcode, op_size) : ( & [ u8 ] , _ ) = match width {
9651044 ExtWidth :: Ext8_32 => ( & [ 0xf , 0xbe ] , OperandSize :: S32 ) ,
0 commit comments