1
1
use crate :: codegen:: Instruction ;
2
+ use std:: cmp:: { max, min} ;
2
3
3
4
fn get_instruction_length ( istr : & Instruction ) -> u16 {
4
5
match istr {
@@ -21,73 +22,62 @@ fn get_instructions_length(instructions: &[Instruction]) -> u16 {
21
22
pub ( crate ) fn convert_to_absolute_jumps ( instructions : Vec < Instruction > ) -> Vec < Instruction > {
22
23
let mut result = vec ! [ ] ;
23
24
for ( j, istr) in instructions. iter ( ) . enumerate ( ) {
25
+ let current_offset = get_instructions_length ( & instructions[ ..j] ) ;
24
26
match istr {
27
+ Instruction :: relgoto( target) => {
28
+ let absolute_addr =
29
+ calculate_absolute_addr ( * target, current_offset, j, & instructions) ;
30
+ result. push ( Instruction :: goto ( absolute_addr, * target) ) ;
31
+ }
25
32
Instruction :: reljumpifeq( target) => {
26
- let modifier: i32 = if * target < 0 { -1 } else { 1 } ;
27
- result. push ( Instruction :: ifeq (
28
- ( get_instructions_length (
29
- & instructions[ j..j. saturating_add_signed ( * target as isize ) ] ,
30
- ) as i32
31
- * modifier
32
- + j as i32
33
- - 1 ) as u16 ,
34
- * target,
35
- ) )
33
+ let absolute_addr =
34
+ calculate_absolute_addr ( * target, current_offset, j, & instructions) ;
35
+ result. push ( Instruction :: ifeq ( absolute_addr, * target) ) ;
36
36
}
37
37
Instruction :: reljumpifge( target) => {
38
- let modifier: i32 = if * target < 0 { -1 } else { 1 } ;
39
- result. push ( Instruction :: ifge (
40
- ( get_instructions_length (
41
- & instructions[ j..j. saturating_add_signed ( * target as isize ) ] ,
42
- ) as i32
43
- * modifier
44
- + j as i32
45
- - 1 ) as u16 ,
46
- * target,
47
- ) )
48
- }
49
- Instruction :: relgoto( target) => {
50
- let modifier: i32 = if * target < 0 { -1 } else { 1 } ;
51
- result. push ( Instruction :: goto (
52
- ( get_instructions_length (
53
- & instructions[ j..j. saturating_add_signed ( * target as isize ) ] ,
54
- ) as i32
55
- * modifier
56
- + j as i32
57
- - 1 ) as u16 ,
58
- * target,
59
- ) )
38
+ let absolute_addr =
39
+ calculate_absolute_addr ( * target, current_offset, j, & instructions) ;
40
+ result. push ( Instruction :: ifge ( absolute_addr, * target) ) ;
60
41
}
61
42
Instruction :: reljumpiflt( target) => {
62
- let modifier: i32 = if * target < 0 { -1 } else { 1 } ;
63
- result. push ( Instruction :: iflt (
64
- ( get_instructions_length (
65
- & instructions[ j..j. saturating_add_signed ( * target as isize ) ] ,
66
- ) as i32
67
- * modifier
68
- + j as i32
69
- - 1 ) as u16 ,
70
- * target,
71
- ) )
43
+ let absolute_addr =
44
+ calculate_absolute_addr ( * target, current_offset, j, & instructions) ;
45
+ result. push ( Instruction :: iflt ( absolute_addr, * target) ) ;
72
46
}
73
47
Instruction :: reljumpifne( target) => {
74
- let modifier: i32 = if * target < 0 { -1 } else { 1 } ;
75
- result. push ( Instruction :: ifne (
76
- ( get_instructions_length (
77
- & instructions[ j..j. saturating_add_signed ( * target as isize ) ] ,
78
- ) as i32
79
- * modifier
80
- + j as i32
81
- - 1 ) as u16 ,
82
- * target,
83
- ) )
48
+ let absolute_addr =
49
+ calculate_absolute_addr ( * target, current_offset, j, & instructions) ;
50
+ result. push ( Instruction :: ifne ( absolute_addr, * target) ) ;
84
51
}
85
52
_ => result. push ( * istr) ,
86
53
}
87
54
}
88
55
result
89
56
}
90
57
58
+ fn calculate_absolute_addr (
59
+ target : i16 ,
60
+ current_offset : u16 ,
61
+ j : usize ,
62
+ instructions : & [ Instruction ] ,
63
+ ) -> u16 {
64
+ let modifier: i32 = if target < 0 { -1 } else { 1 } ;
65
+ // Too dumb to figure out the formula for this so here is an ugly if statement
66
+ if modifier > 0 {
67
+ let min = min ( j + 1 , j. saturating_add_signed ( target as isize ) ) ;
68
+ let max = max ( j + 1 , j. saturating_add_signed ( target as isize ) ) ;
69
+ let instructions_to_jump_over = & instructions[ min..max] ;
70
+ let offset = get_instructions_length ( instructions_to_jump_over) ;
71
+ ( offset as i32 * modifier + current_offset as i32 ) as u16
72
+ } else {
73
+ let min = min ( j + 1 , j. saturating_add_signed ( target as isize ) ) ;
74
+ let max = max ( j + 1 , j. saturating_add_signed ( target as isize ) ) - 1 ;
75
+ let instructions_to_jump_over = & instructions[ min..max] ;
76
+ let offset = get_instructions_length ( instructions_to_jump_over) ;
77
+ ( offset as i32 * modifier + current_offset as i32 ) as u16
78
+ }
79
+ }
80
+
91
81
#[ cfg( test) ]
92
82
mod tests {
93
83
use super :: * ;
@@ -140,4 +130,9 @@ mod tests {
140
130
] ;
141
131
assert_eq ! ( convert_to_absolute_jumps( instructions) , expected) ;
142
132
}
133
+ #[ test]
134
+ fn test_calculate_instruction_size ( ) {
135
+ let instructions = vec ! [ Instruction :: reljumpifge( 1 ) , Instruction :: relgoto( 2 ) ] ;
136
+ assert_eq ! ( get_instructions_length( & instructions) , 6 ) ;
137
+ }
143
138
}
0 commit comments