@@ -35,9 +35,73 @@ fn one_way_jmp(sink: &mut MachBuffer<Inst>, cc: CC, label: MachLabel) {
3535 let cond_start = sink. cur_offset ( ) ;
3636 let cond_disp_off = cond_start + 2 ;
3737 sink. use_label_at_offset ( cond_disp_off, label, LabelUse :: JmpRel32 ) ;
38- sink. put1 ( 0x0F ) ;
39- sink. put1 ( 0x80 + cc. get_enc ( ) ) ;
40- sink. put4 ( 0x0 ) ;
38+ emit_jcc_no_offset ( sink, cc) ;
39+ debug_assert_eq ! ( sink. cur_offset( ) , cond_disp_off + 4 ) ;
40+ }
41+
42+ /// Like `one_way_jmp` above emitting a conditional jump, but also using
43+ /// `MachBuffer::add_cond_branch`.
44+ fn cond_jmp ( sink : & mut MachBuffer < Inst > , cc : CC , label : MachLabel ) {
45+ let cond_start = sink. cur_offset ( ) ;
46+ let cond_disp_off = cond_start + 2 ;
47+ let cond_end = cond_start + 6 ;
48+
49+ sink. use_label_at_offset ( cond_disp_off, label, LabelUse :: JmpRel32 ) ;
50+ // FIXME: ideally this `inverted` calculation would go through the external
51+ // assembler, but for now it's left done manually.
52+ let inverted: [ u8 ; 6 ] = [ 0x0F , 0x80 + ( cc. invert ( ) . get_enc ( ) ) , 0x00 , 0x00 , 0x00 , 0x00 ] ;
53+ sink. add_cond_branch ( cond_start, cond_end, label, & inverted[ ..] ) ;
54+
55+ emit_jcc_no_offset ( sink, cc) ;
56+
57+ debug_assert_eq ! ( sink. cur_offset( ) , cond_disp_off + 4 ) ;
58+ debug_assert_eq ! ( sink. cur_offset( ) , cond_end) ;
59+ }
60+
61+ fn emit_jcc_no_offset ( sink : & mut MachBuffer < Inst > , cc : CC ) {
62+ // Note that the disassembler matches Capstone which doesn't match the `CC`
63+ // enum directly as Intel has multiple mnemonics use the same encoding.
64+ let inst: AsmInst = match cc {
65+ CC :: Z => asm:: inst:: je_d32:: new ( 0 ) . into ( ) , // jz == je
66+ CC :: NZ => asm:: inst:: jne_d32:: new ( 0 ) . into ( ) , // jnz == jne
67+ CC :: B => asm:: inst:: jb_d32:: new ( 0 ) . into ( ) ,
68+ CC :: NB => asm:: inst:: jae_d32:: new ( 0 ) . into ( ) , // jnb == jae
69+ CC :: BE => asm:: inst:: jbe_d32:: new ( 0 ) . into ( ) ,
70+ CC :: NBE => asm:: inst:: ja_d32:: new ( 0 ) . into ( ) , // jnbe == ja
71+ CC :: L => asm:: inst:: jl_d32:: new ( 0 ) . into ( ) ,
72+ CC :: LE => asm:: inst:: jle_d32:: new ( 0 ) . into ( ) ,
73+ CC :: NL => asm:: inst:: jge_d32:: new ( 0 ) . into ( ) , // jnl == jge
74+ CC :: NLE => asm:: inst:: jg_d32:: new ( 0 ) . into ( ) , // jnle == jg
75+ CC :: O => asm:: inst:: jo_d32:: new ( 0 ) . into ( ) ,
76+ CC :: NO => asm:: inst:: jno_d32:: new ( 0 ) . into ( ) ,
77+ CC :: P => asm:: inst:: jp_d32:: new ( 0 ) . into ( ) ,
78+ CC :: NP => asm:: inst:: jnp_d32:: new ( 0 ) . into ( ) ,
79+ CC :: S => asm:: inst:: js_d32:: new ( 0 ) . into ( ) ,
80+ CC :: NS => asm:: inst:: jns_d32:: new ( 0 ) . into ( ) ,
81+ } ;
82+ inst. encode ( & mut external:: AsmCodeSink {
83+ sink,
84+ incoming_arg_offset : 0 ,
85+ slot_offset : 0 ,
86+ } ) ;
87+ }
88+
89+ /// Emits an unconditional branch.
90+ fn uncond_jmp ( sink : & mut MachBuffer < Inst > , label : MachLabel ) {
91+ let uncond_start = sink. cur_offset ( ) ;
92+ let uncond_disp_off = uncond_start + 1 ;
93+ let uncond_end = uncond_start + 5 ;
94+
95+ sink. use_label_at_offset ( uncond_disp_off, label, LabelUse :: JmpRel32 ) ;
96+ sink. add_uncond_branch ( uncond_start, uncond_end, label) ;
97+
98+ asm:: inst:: jmp_d32:: new ( 0 ) . encode ( & mut external:: AsmCodeSink {
99+ sink,
100+ incoming_arg_offset : 0 ,
101+ slot_offset : 0 ,
102+ } ) ;
103+ debug_assert_eq ! ( sink. cur_offset( ) , uncond_disp_off + 4 ) ;
104+ debug_assert_eq ! ( sink. cur_offset( ) , uncond_end) ;
41105}
42106
43107/// Emits a relocation, attaching the current source location as well.
@@ -427,11 +491,11 @@ pub(crate) fn emit(
427491 // Note: this is not `Inst::Jmp { .. }.emit(..)` because we have
428492 // different metadata in this case: we don't have a label for the
429493 // target, but rather a function relocation.
430- sink. put1 ( 0xE9 ) ;
494+ asm:: inst:: jmp_d32:: new ( 0 ) . emit ( sink, info, state) ;
495+ let offset = sink. cur_offset ( ) ;
431496 // The addend adjusts for the difference between the end of the instruction and the
432497 // beginning of the immediate field.
433- emit_reloc ( sink, Reloc :: X86CallPCRel4 , & call_info. dest , -4 ) ;
434- sink. put4 ( 0 ) ;
498+ sink. add_reloc_at_offset ( offset - 4 , Reloc :: X86CallPCRel4 , & call_info. dest , -4 ) ;
435499 sink. add_call_site ( & [ ] ) ;
436500 }
437501
@@ -595,62 +659,17 @@ pub(crate) fn emit(
595659 sink. bind_label ( resume, state. ctrl_plane_mut ( ) ) ;
596660 }
597661
598- Inst :: JmpKnown { dst } => {
599- let br_start = sink. cur_offset ( ) ;
600- let br_disp_off = br_start + 1 ;
601- let br_end = br_start + 5 ;
662+ Inst :: JmpKnown { dst } => uncond_jmp ( sink, * dst) ,
602663
603- sink. use_label_at_offset ( br_disp_off, * dst, LabelUse :: JmpRel32 ) ;
604- sink. add_uncond_branch ( br_start, br_end, * dst) ;
605-
606- sink. put1 ( 0xE9 ) ;
607- // Placeholder for the label value.
608- sink. put4 ( 0x0 ) ;
609- }
610-
611- Inst :: WinchJmpIf { cc, taken } => {
612- let cond_start = sink. cur_offset ( ) ;
613- let cond_disp_off = cond_start + 2 ;
614-
615- sink. use_label_at_offset ( cond_disp_off, * taken, LabelUse :: JmpRel32 ) ;
616- // Since this is not a terminator, don't enroll in the branch inversion mechanism.
617-
618- sink. put1 ( 0x0F ) ;
619- sink. put1 ( 0x80 + cc. get_enc ( ) ) ;
620- // Placeholder for the label value.
621- sink. put4 ( 0x0 ) ;
622- }
664+ Inst :: WinchJmpIf { cc, taken } => one_way_jmp ( sink, * cc, * taken) ,
623665
624666 Inst :: JmpCond {
625667 cc,
626668 taken,
627669 not_taken,
628670 } => {
629- // If taken.
630- let cond_start = sink. cur_offset ( ) ;
631- let cond_disp_off = cond_start + 2 ;
632- let cond_end = cond_start + 6 ;
633-
634- sink. use_label_at_offset ( cond_disp_off, * taken, LabelUse :: JmpRel32 ) ;
635- let inverted: [ u8 ; 6 ] = [ 0x0F , 0x80 + ( cc. invert ( ) . get_enc ( ) ) , 0x00 , 0x00 , 0x00 , 0x00 ] ;
636- sink. add_cond_branch ( cond_start, cond_end, * taken, & inverted[ ..] ) ;
637-
638- sink. put1 ( 0x0F ) ;
639- sink. put1 ( 0x80 + cc. get_enc ( ) ) ;
640- // Placeholder for the label value.
641- sink. put4 ( 0x0 ) ;
642-
643- // If not taken.
644- let uncond_start = sink. cur_offset ( ) ;
645- let uncond_disp_off = uncond_start + 1 ;
646- let uncond_end = uncond_start + 5 ;
647-
648- sink. use_label_at_offset ( uncond_disp_off, * not_taken, LabelUse :: JmpRel32 ) ;
649- sink. add_uncond_branch ( uncond_start, uncond_end, * not_taken) ;
650-
651- sink. put1 ( 0xE9 ) ;
652- // Placeholder for the label value.
653- sink. put4 ( 0x0 ) ;
671+ cond_jmp ( sink, * cc, * taken) ;
672+ uncond_jmp ( sink, * not_taken) ;
654673 }
655674
656675 Inst :: JmpCondOr {
@@ -671,56 +690,9 @@ pub(crate) fn emit(
671690 // not_taken and that one block is the fallthrough block,
672691 // all three branches can disappear.
673692
674- // jcc1 taken
675- let cond_1_start = sink. cur_offset ( ) ;
676- let cond_1_disp_off = cond_1_start + 2 ;
677- let cond_1_end = cond_1_start + 6 ;
678-
679- sink. use_label_at_offset ( cond_1_disp_off, * taken, LabelUse :: JmpRel32 ) ;
680- let inverted: [ u8 ; 6 ] = [
681- 0x0F ,
682- 0x80 + ( cc1. invert ( ) . get_enc ( ) ) ,
683- 0x00 ,
684- 0x00 ,
685- 0x00 ,
686- 0x00 ,
687- ] ;
688- sink. add_cond_branch ( cond_1_start, cond_1_end, * taken, & inverted[ ..] ) ;
689-
690- sink. put1 ( 0x0F ) ;
691- sink. put1 ( 0x80 + cc1. get_enc ( ) ) ;
692- sink. put4 ( 0x0 ) ;
693-
694- // jcc2 taken
695- let cond_2_start = sink. cur_offset ( ) ;
696- let cond_2_disp_off = cond_2_start + 2 ;
697- let cond_2_end = cond_2_start + 6 ;
698-
699- sink. use_label_at_offset ( cond_2_disp_off, * taken, LabelUse :: JmpRel32 ) ;
700- let inverted: [ u8 ; 6 ] = [
701- 0x0F ,
702- 0x80 + ( cc2. invert ( ) . get_enc ( ) ) ,
703- 0x00 ,
704- 0x00 ,
705- 0x00 ,
706- 0x00 ,
707- ] ;
708- sink. add_cond_branch ( cond_2_start, cond_2_end, * taken, & inverted[ ..] ) ;
709-
710- sink. put1 ( 0x0F ) ;
711- sink. put1 ( 0x80 + cc2. get_enc ( ) ) ;
712- sink. put4 ( 0x0 ) ;
713-
714- // jmp not_taken
715- let uncond_start = sink. cur_offset ( ) ;
716- let uncond_disp_off = uncond_start + 1 ;
717- let uncond_end = uncond_start + 5 ;
718-
719- sink. use_label_at_offset ( uncond_disp_off, * not_taken, LabelUse :: JmpRel32 ) ;
720- sink. add_uncond_branch ( uncond_start, uncond_end, * not_taken) ;
721-
722- sink. put1 ( 0xE9 ) ;
723- sink. put4 ( 0x0 ) ;
693+ cond_jmp ( sink, * cc1, * taken) ;
694+ cond_jmp ( sink, * cc2, * taken) ;
695+ uncond_jmp ( sink, * not_taken) ;
724696 }
725697
726698 & Inst :: JmpTableSeq {
0 commit comments