@@ -72,112 +72,68 @@ let remove_useless_mov (cell : Cfg.basic Cfg.instruction DLL.cell) =
72
72
73
73
(* * Logical condition for simplifying the following case:
74
74
{|
75
- <op 1 > const1, r
76
- <op 2 > const2, r
75
+ <op1 > const1, r
76
+ <op2 > const2, r
77
77
|}
78
78
79
79
to:
80
80
{|
81
- <op 1 > (const1 <op 2 > const2), r
81
+ <op1 > (const1 <op2 > const2), r
82
82
|}
83
83
84
- Where <op 1> and <op 2> can be any two binary operators that are associative and commutative
85
- and const1 and const2 are immediate values. *)
84
+ where
85
+ const1 and const2 are immediate values, and
86
+ <op1> and <op2> are associative binary operators such
87
+ that either <op1> is the same as <op2>, or <op1> is the inverse of <op2>,
88
+ or there exists const3 such that <op1 const1> can be expressed as <op2 const3>
89
+ or <op2 const2> can be expressed as <op1 const3> *)
86
90
87
91
let are_compatible op1 op2 imm1 imm2 :
88
92
(Operation. integer_operation * int ) option =
89
93
match
90
94
(op1 : Operation.integer_operation ), (op2 : Operation.integer_operation )
91
95
with
92
- (* Folding two bitwise operations such as (AND, OR, XOR) should never produce
93
- an overflow so we assert this conditon. *)
94
- | Iand , Iand ->
95
- assert (U. amd64_imm32_within_bounds imm1 imm2 ( land ));
96
- Some (Iand , imm1 land imm2)
97
- | Ior , Ior ->
98
- assert (U. amd64_imm32_within_bounds imm1 imm2 ( lor ));
99
- Some (Ior , imm1 lor imm2)
100
- | Ixor , Ixor ->
101
- assert (U. amd64_imm32_within_bounds imm1 imm2 ( lxor ));
102
- Some (Ixor , imm1 lxor imm2)
96
+ | Iand , Iand -> U. bitwise_immediates op1 imm1 imm2 ( land )
97
+ | Ior , Ior -> U. bitwise_immediates op1 imm1 imm2 ( lor )
98
+ | Ixor , Ixor -> U. bitwise_immediates op1 imm1 imm2 ( lxor )
103
99
(* For the following three cases we have the issue that in some situations,
104
100
one or both immediate values could be out of bounds, but the result might
105
101
be within bounds (e.g. imm1 = -4 and imm2 = 65, their sum being 61). This
106
102
should not happen at all since the immediate values should always be within
107
103
the bounds [0, Sys.int_size]. *)
108
- | Ilsl , Ilsl ->
109
- if Misc. no_overflow_add imm1 imm2 && imm1 + imm2 < = Sys. int_size
110
- then (
111
- U. bitwise_shift_assert imm1 imm2;
112
- Some (Ilsl , imm1 + imm2))
113
- else None
114
- | Ilsr , Ilsr ->
115
- if Misc. no_overflow_add imm1 imm2 && imm1 + imm2 < = Sys. int_size
116
- then (
117
- U. bitwise_shift_assert imm1 imm2;
118
- Some (Ilsr , imm1 + imm2))
119
- else None
120
- | Iasr , Iasr ->
121
- if Misc. no_overflow_add imm1 imm2 && imm1 + imm2 < = Sys. int_size
122
- then (
123
- U. bitwise_shift_assert imm1 imm2;
124
- Some (Iasr , imm1 + imm2))
125
- else None
126
- (* for the amd64 instruction set the `ADD` `SUB` `MUL` opperations take at
127
- most an imm32 as the second argument, so we need to check for overflows on
128
- 32-bit signed ints. *)
129
- (* CR-someday gtulba-lecu: This condition is architecture specific and should
130
- either live in amd64 specific code or this module should contain
131
- information about the architecture target. *)
132
- | Iadd , Iadd ->
133
- if Misc. no_overflow_add imm1 imm2
134
- && U. amd64_imm32_within_bounds imm1 imm2 ( + )
135
- then Some (Iadd , imm1 + imm2)
136
- else None
104
+ | Ilsl , Ilsl | Ilsr , Ilsr | Iasr , Iasr | Iadd , Iadd ->
105
+ U. add_immediates op1 imm1 imm2
137
106
| Iadd , Isub ->
107
+ (* The following transformation changes the order of operations on [r] and
108
+ therefore might change the overflow behavior: if [r+c1] overflows, but
109
+ r-[c2-c1] does not overflow. This is fine, other compiler transformations
110
+ may also do it. The code below only ensures that immediates that the
111
+ compiler emits do not overflow. *)
138
112
if imm1 > = imm2
139
- then
140
- if Misc. no_overflow_sub imm1 imm2
141
- && U. amd64_imm32_within_bounds imm1 imm2 ( - )
142
- then Some (Iadd , imm1 - imm2)
143
- else None
144
- else if Misc. no_overflow_sub imm2 imm1
145
- && U. amd64_imm32_within_bounds imm2 imm1 ( - )
146
- then Some (Isub , imm2 - imm1)
147
- else None
148
- | Isub , Isub ->
149
- if Misc. no_overflow_add imm1 imm2
150
- && U. amd64_imm32_within_bounds imm1 imm2 ( + )
151
- then Some (Isub , imm1 + imm2)
152
- else None
113
+ then U. sub_immediates Iadd imm1 imm2
114
+ else U. sub_immediates Isub imm2 imm1
115
+ | Isub , Isub (* r - (imm1 + imm2 *) -> U. add_immediates Isub imm1 imm2
153
116
| Isub , Iadd ->
154
117
if imm1 > = imm2
155
- then
156
- if Misc. no_overflow_sub imm1 imm2
157
- && U. amd64_imm32_within_bounds imm1 imm2 ( - )
158
- then Some (Isub , imm1 - imm2)
159
- else None
160
- else if Misc. no_overflow_sub imm2 imm1
161
- && U. amd64_imm32_within_bounds imm2 imm1 ( - )
162
- then Some (Iadd , imm2 - imm1)
163
- else None
118
+ then U. sub_immediates Isub imm1 imm2
119
+ else U. sub_immediates Iadd imm2 imm1
164
120
| Ilsl , Imul ->
165
- if imm1 > = 0 && imm1 < 31
166
- && Misc. no_overflow_mul (1 lsl imm1) imm2
167
- && U. amd64_imm32_within_bounds (1 lsl imm1) imm2 ( * )
168
- then Some (Imul , (1 lsl imm1) * imm2)
121
+ (* [imm1] is guaranteed to be within bounds for [Ilsl], but [1 lsl imm1] may
122
+ not be within bounds for [Imul]. *)
123
+ U. assert_within_range Ilsl imm1;
124
+ let imm1 = 1 lsl imm1 in
125
+ if U. is_immediate_for_intop Imul imm1
126
+ then U. mul_immediates Imul imm1 imm2
169
127
else None
170
128
| Imul , Ilsl ->
171
- if imm2 > = 0 && imm2 < 31
172
- && Misc. no_overflow_mul imm1 (1 lsl imm2)
173
- && U. amd64_imm32_within_bounds imm1 (1 lsl imm2) ( * )
174
- then Some (Imul , imm1 * (1 lsl imm2))
175
- else None
176
- | Imul , Imul ->
177
- if Misc. no_overflow_mul imm1 imm2
178
- && U. amd64_imm32_within_bounds imm1 imm2 ( * )
179
- then Some (Imul , imm1 * imm2)
129
+ (* [imm2] is guaranteed to be within bounds for [Ilsl], but [1 lsl imm2] may
130
+ not be within bounds for [Imul]. *)
131
+ U. assert_within_range Ilsl imm2;
132
+ let imm2 = 1 lsl imm2 in
133
+ if U. is_immediate_for_intop Imul imm2
134
+ then U. mul_immediates Imul imm1 imm2
180
135
else None
136
+ | Imul , Imul -> U. mul_immediates op1 imm1 imm2
181
137
(* CR-soon gtulba-lecu: check this last case | Imod, Imod -> if imm1 mod imm2
182
138
= 0 then Some (Imod, imm2) else None
183
139
@@ -199,11 +155,8 @@ let fold_intop_imm (cell : Cfg.basic Cfg.instruction DLL.cell) =
199
155
let snd_val = DLL. value snd in
200
156
(* The following check does the following: 1. Ensures that both instructions
201
157
use the same source register; 2. Ensures that both instructions output
202
- the result to the source register, this is redundant for amd64 since
203
- there are no instructions that invalidate this condition. *)
204
- (* CR-someday gtulba-lecu: This condition is architecture specific and
205
- should either live in amd64 specific code or this module should contain
206
- information about the architecture target. *)
158
+ the result to the source register. This is currently redundant for amd64
159
+ since there are no instructions that invalidate this condition. *)
207
160
if Array. length fst_val.arg = 1
208
161
&& Array. length snd_val.arg = 1
209
162
&& Array. length fst_val.res = 1
@@ -235,9 +188,10 @@ let fold_intop_imm (cell : Cfg.basic Cfg.instruction DLL.cell) =
235
188
| _ -> None
236
189
237
190
let apply cell =
238
- match remove_overwritten_mov cell with
239
- | None -> (
240
- match remove_useless_mov cell with
241
- | None -> ( match fold_intop_imm cell with None -> None | res -> res)
242
- | res -> res)
243
- | res -> res
191
+ let [@ inline always] if_none_do f o =
192
+ match o with Some _ -> o | None -> f cell
193
+ in
194
+ None
195
+ |> if_none_do remove_overwritten_mov
196
+ |> if_none_do remove_useless_mov
197
+ |> if_none_do fold_intop_imm
0 commit comments