@@ -565,64 +565,42 @@ impl Assembler
565
565
fn emit_conditional_jump < const CONDITION : u8 > ( cb : & mut CodeBlock , target : Target ) {
566
566
match target {
567
567
Target :: CodePtr ( dst_ptr) => {
568
- let dst_addr = dst_ptr. into_u64 ( ) ;
569
- //let src_addr = cb.get_write_ptr().into_i64() + 4;
570
- //let offset = dst_addr - src_addr;
571
-
572
- // If the condition is met, then we'll skip past the
573
- // next instruction, put the address in a register, and
574
- // jump to it.
575
- bcond ( cb, CONDITION , A64Opnd :: new_imm ( 8 ) ) ;
576
-
577
- // If we get to this instruction, then the condition
578
- // wasn't met, in which case we'll jump past the
579
- // next instruction that perform the direct jump.
580
-
581
- b ( cb, A64Opnd :: new_imm ( 2i64 + emit_load_size ( dst_addr) as i64 ) ) ;
582
- let num_insns = emit_load_value ( cb, Assembler :: SCRATCH0 , dst_addr) ;
583
- br ( cb, Assembler :: SCRATCH0 ) ;
584
- for _ in num_insns..4 {
585
- nop ( cb) ;
586
- }
568
+ let dst_addr = dst_ptr. into_i64 ( ) ;
569
+ let src_addr = cb. get_write_ptr ( ) . into_i64 ( ) ;
570
+ let offset = dst_addr - src_addr;
587
571
588
- /*
589
- // If the jump offset fits into the conditional jump as an
590
- // immediate value and it's properly aligned, then we can
591
- // use the b.cond instruction directly. Otherwise, we need
592
- // to load the address into a register and use the branch
593
- // register instruction.
594
- if bcond_offset_fits_bits(offset) {
595
- bcond(cb, CONDITION, A64Opnd::new_imm(dst_addr - src_addr));
572
+ let num_insns = if bcond_offset_fits_bits ( offset) {
573
+ // If the jump offset fits into the conditional jump as
574
+ // an immediate value and it's properly aligned, then we
575
+ // can use the b.cond instruction directly.
576
+ bcond ( cb, CONDITION , A64Opnd :: new_imm ( offset) ) ;
577
+
578
+ // Here we're going to return 1 because we've only
579
+ // written out 1 instruction.
580
+ 1
596
581
} else {
597
- // If the condition is met, then we'll skip past the
598
- // next instruction, put the address in a register, and
599
- // jump to it.
600
- bcond(cb, CONDITION, A64Opnd::new_imm(8));
601
-
602
- // If the offset fits into a direct jump, then we'll use
603
- // that and the number of instructions will be shorter.
604
- // Otherwise we'll use the branch register instruction.
605
- if b_offset_fits_bits(offset) {
606
- // If we get to this instruction, then the condition
607
- // wasn't met, in which case we'll jump past the
608
- // next instruction that performs the direct jump.
609
- b(cb, A64Opnd::new_imm(1));
610
-
611
- // Here we'll perform the direct jump to the target.
612
- let offset = dst_addr - cb.get_write_ptr().into_i64() + 4;
613
- b(cb, A64Opnd::new_imm(offset / 4));
614
- } else {
615
- // If we get to this instruction, then the condition
616
- // wasn't met, in which case we'll jump past the
617
- // next instruction that perform the direct jump.
618
- let value = dst_addr as u64;
619
-
620
- b(cb, A64Opnd::new_imm(emit_load_size(value).into()));
621
- emit_load_value(cb, Assembler::SCRATCH0, value);
622
- br(cb, Assembler::SCRATCH0);
623
- }
624
- }
625
- */
582
+ // Otherwise, we need to load the address into a
583
+ // register and use the branch register instruction.
584
+ let dst_addr = dst_ptr. into_u64 ( ) ;
585
+ let load_insns: i64 = emit_load_size ( dst_addr) . into ( ) ;
586
+
587
+ // We're going to write out the inverse condition so
588
+ // that if it doesn't match it will skip over the
589
+ // instructions used for branching.
590
+ bcond ( cb, Condition :: inverse ( CONDITION ) , A64Opnd :: new_imm ( ( load_insns + 2 ) * 4 ) ) ;
591
+ emit_load_value ( cb, Assembler :: SCRATCH0 , dst_addr) ;
592
+ br ( cb, Assembler :: SCRATCH0 ) ;
593
+
594
+ // Here we'll return the number of instructions that it
595
+ // took to write out the destination address + 1 for the
596
+ // b.cond and 1 for the br.
597
+ load_insns + 2
598
+ } ;
599
+
600
+ // We need to make sure we have at least 6 instructions for
601
+ // every kind of jump for invalidation purposes, so we're
602
+ // going to write out padding nop instructions here.
603
+ for _ in num_insns..6 { nop ( cb) ; }
626
604
} ,
627
605
Target :: Label ( label_idx) => {
628
606
// Here we're going to save enough space for ourselves and
@@ -904,10 +882,10 @@ impl Assembler
904
882
_ => unreachable ! ( )
905
883
} ;
906
884
} ,
907
- Insn :: Je ( target) => {
885
+ Insn :: Je ( target) | Insn :: Jz ( target ) => {
908
886
emit_conditional_jump :: < { Condition :: EQ } > ( cb, * target) ;
909
887
} ,
910
- Insn :: Jne ( target) => {
888
+ Insn :: Jne ( target) | Insn :: Jnz ( target ) => {
911
889
emit_conditional_jump :: < { Condition :: NE } > ( cb, * target) ;
912
890
} ,
913
891
Insn :: Jl ( target) => {
@@ -916,12 +894,6 @@ impl Assembler
916
894
Insn :: Jbe ( target) => {
917
895
emit_conditional_jump :: < { Condition :: LS } > ( cb, * target) ;
918
896
} ,
919
- Insn :: Jz ( target) => {
920
- emit_conditional_jump :: < { Condition :: EQ } > ( cb, * target) ;
921
- } ,
922
- Insn :: Jnz ( target) => {
923
- emit_conditional_jump :: < { Condition :: NE } > ( cb, * target) ;
924
- } ,
925
897
Insn :: Jo ( target) => {
926
898
emit_conditional_jump :: < { Condition :: VS } > ( cb, * target) ;
927
899
} ,
@@ -1053,6 +1025,28 @@ mod tests {
1053
1025
asm. compile_with_num_regs ( & mut cb, 0 ) ;
1054
1026
}
1055
1027
1028
+ #[ test]
1029
+ fn test_emit_je_fits_into_bcond ( ) {
1030
+ let ( mut asm, mut cb) = setup_asm ( ) ;
1031
+
1032
+ let offset = 80 ;
1033
+ let target: CodePtr = ( ( cb. get_write_ptr ( ) . into_u64 ( ) + offset) as * mut u8 ) . into ( ) ;
1034
+
1035
+ asm. je ( Target :: CodePtr ( target) ) ;
1036
+ asm. compile_with_num_regs ( & mut cb, 0 ) ;
1037
+ }
1038
+
1039
+ #[ test]
1040
+ fn test_emit_je_does_not_fit_into_bcond ( ) {
1041
+ let ( mut asm, mut cb) = setup_asm ( ) ;
1042
+
1043
+ let offset = 1 << 21 ;
1044
+ let target: CodePtr = ( ( cb. get_write_ptr ( ) . into_u64 ( ) + offset) as * mut u8 ) . into ( ) ;
1045
+
1046
+ asm. je ( Target :: CodePtr ( target) ) ;
1047
+ asm. compile_with_num_regs ( & mut cb, 0 ) ;
1048
+ }
1049
+
1056
1050
#[ test]
1057
1051
fn test_emit_lea_label ( ) {
1058
1052
let ( mut asm, mut cb) = setup_asm ( ) ;
0 commit comments