@@ -189,7 +189,7 @@ module ToIR = struct
189
189
else
190
190
Bil. Move (v, Bil. (Var v + (df_to_offset mode df_e * i (bytes_of_width t))))
191
191
192
- let rep_wrap ?check_zf ~mode ~addr ~next stmts =
192
+ let rep_wrap ?check_zf ~mode ~addr : _ ~next : _ stmts =
193
193
let extend = big_int_of_mode mode in
194
194
let zero = extend Word. b0 and one = extend Word. b1 in
195
195
let rcx = match mode with
@@ -273,6 +273,95 @@ module ToIR = struct
273
273
Bil. Move (cf, Bil. (s2 > s1))
274
274
::set_aopszf_sub t s1 s2 r
275
275
276
+ let popcount x ~one ~two ~four ~sh ~m1 ~m2 ~m4 ~h01 = Bil. [
277
+ x := var x - ((var x lsr int one) land int m1);
278
+ x := (var x land int m2) + ((var x lsr int two) land int m2);
279
+ x := (var x + (var x lsr int four)) land int m4;
280
+ x := (var x * int h01) lsr int sh;
281
+ ]
282
+
283
+ let popcnt16 x =
284
+ let one = Word. one 16 in
285
+ let two = Word. succ one in
286
+ let four = Word. of_int ~width: 16 4 in
287
+ let sh = Word. of_int ~width: 16 8 in
288
+ let m1 = Word. of_int ~width: 16 0x5555 in
289
+ let m2 = Word. of_int ~width: 16 0x3333 in
290
+ let m4 = Word. of_int ~width: 16 0x0f0f in
291
+ let h01 = Word. of_int ~width: 16 0x0101 in
292
+ popcount x ~one ~two ~four ~sh ~m1 ~m2 ~m4 ~h01
293
+
294
+ let popcnt32 x =
295
+ let one = Word. one 32 in
296
+ let two = Word. succ one in
297
+ let four = Word. of_int ~width: 32 4 in
298
+ let sh = Word. of_int ~width: 32 24 in
299
+ let m1 = Word. of_int ~width: 32 0x55555555 in
300
+ let m2 = Word. of_int ~width: 32 0x33333333 in
301
+ let m4 = Word. of_int ~width: 32 0x0f0f0f0f in
302
+ let h01 = Word. of_int ~width: 32 0x01010101 in
303
+ popcount x ~one ~two ~four ~sh ~m1 ~m2 ~m4 ~h01
304
+
305
+ let popcnt64 x =
306
+ let one = Word. one 64 in
307
+ let two = Word. succ one in
308
+ let four = Word. of_int ~width: 64 4 in
309
+ let sh = Word. of_int ~width: 64 56 in
310
+ let m1 = Word. of_int64 ~width: 64 0x5555555555555555L in
311
+ let m2 = Word. of_int64 ~width: 64 0x3333333333333333L in
312
+ let m4 = Word. of_int64 ~width: 64 0x0f0f0f0f0f0f0f0fL in
313
+ let h01 = Word. of_int64 ~width: 64 0x0101010101010101L in
314
+ popcount x ~one ~two ~four ~sh ~m1 ~m2 ~m4 ~h01
315
+
316
+ let clz16 x = Bil. [
317
+ x := var x lor (var x lsr int Word. (one 16 ));
318
+ x := var x lor (var x lsr int Word. (of_int 2 ~width: 16 ));
319
+ x := var x lor (var x lsr int Word. (of_int 4 ~width: 16 ));
320
+ x := var x lor (var x lsr int Word. (of_int 8 ~width: 16 ));
321
+ x := lnot (var x);
322
+ ] @ popcnt16 x
323
+
324
+ let clz32 x = Bil. [
325
+ x := var x lor (var x lsr int Word. (one 32 ));
326
+ x := var x lor (var x lsr int Word. (of_int 2 ~width: 32 ));
327
+ x := var x lor (var x lsr int Word. (of_int 4 ~width: 32 ));
328
+ x := var x lor (var x lsr int Word. (of_int 8 ~width: 32 ));
329
+ x := var x lor (var x lsr int Word. (of_int 16 ~width: 32 ));
330
+ x := lnot (var x);
331
+ ] @ popcnt32 x
332
+
333
+ let clz64 x = Bil. [
334
+ x := var x lor (var x lsr int Word. (one 64 ));
335
+ x := var x lor (var x lsr int Word. (of_int 2 ~width: 64 ));
336
+ x := var x lor (var x lsr int Word. (of_int 4 ~width: 64 ));
337
+ x := var x lor (var x lsr int Word. (of_int 8 ~width: 64 ));
338
+ x := var x lor (var x lsr int Word. (of_int 16 ~width: 64 ));
339
+ x := var x lor (var x lsr int Word. (of_int 32 ~width: 64 ));
340
+ x := lnot (var x);
341
+ ] @ popcnt64 x
342
+
343
+ let ctz16 x = Bil. (
344
+ x := (var x land unop NEG (var x)) - int Word. (one 16 )
345
+ ) :: popcnt16 x
346
+
347
+ let ctz32 x = Bil. (
348
+ x := (var x land unop NEG (var x)) - int Word. (one 32 )
349
+ ) :: popcnt32 x
350
+
351
+ let ctz64 x = Bil. (
352
+ x := (var x land unop NEG (var x)) - int Word. (one 64 )
353
+ ) :: popcnt64 x
354
+
355
+ let bitscan_flags is_zero_count =
356
+ let l = Bil. [
357
+ oF := unknown " bits" bool_t;
358
+ sf := unknown " bits" bool_t;
359
+ af := unknown " bits" bool_t;
360
+ pf := unknown " bits" bool_t;
361
+ ] in
362
+ if is_zero_count then l
363
+ else Bil. (cf := unknown " bits" bool_t) :: l
364
+
276
365
let rec to_ir mode addr next ss pref has_rex has_vex =
277
366
let module R = (val (vars_of_mode mode)) in
278
367
let open R in
@@ -1070,31 +1159,43 @@ module ToIR = struct
1070
1159
Bil. Move (pf, Bil. Unknown (" PF undefined after bt" , bool_t))
1071
1160
]
1072
1161
| Bs (t , dst , src , dir ) ->
1073
- let t' = !! t in
1074
- let source_is_zero = tmp bool_t in
1075
- let source_is_zero_v = Bil. Var source_is_zero in
1162
+ let is_zero_count = List. rev pref |> List. exists ~f: Int. ((= ) 0xf3 ) in
1163
+ let width = !! t in
1076
1164
let src_e = op2e t src in
1077
- let bits = !! t in
1078
- let check_bit bitindex next_value =
1079
- Bil. (Ite (Extract (bitindex,bitindex,src_e) = int_exp 1 1 , int_exp bitindex t', next_value))
1080
- in
1081
- let bitlist = List. init ~f: (fun x -> x) bits in
1082
- (* We are folding from right to left *)
1083
- let bitlist = match dir with
1084
- | Forward -> (* least significant first *) bitlist
1085
- | Backward -> (* most significant *) List. rev bitlist
1086
- in
1087
- let first_one = List. fold_right ~f: check_bit bitlist
1088
- ~init: (Bil. Unknown (" bs: destination undefined when source is zero" , t)) in
1089
- [
1090
- Bil. Move (source_is_zero, Bil. (src_e = int_exp 0 t'));
1091
- assn t dst first_one;
1092
- Bil. Move (zf, Bil. Ite (source_is_zero_v, int_exp 1 1 , int_exp 0 1 ));
1093
- ]
1094
- @
1095
- let undef r =
1096
- Bil. Move (r, Bil. Unknown (Var. name r ^ " undefined after bsf" , Var. typ r)) in
1097
- List. map ~f: undef [cf; oF; sf; af; pf]
1165
+ let is_fwd = match dir with
1166
+ | Backward -> false
1167
+ | Forward -> true in
1168
+ let res = tmp t in
1169
+ let assn_res = Bil. (res := src_e) in
1170
+ let scan_bil =
1171
+ if is_fwd then match width with
1172
+ | 16 -> ctz16 res
1173
+ | 32 -> ctz32 res
1174
+ | 64 -> ctz64 res
1175
+ | _ -> disfailwith " Invalid bitscan width"
1176
+ else match width with
1177
+ | 16 -> clz16 res
1178
+ | 32 -> clz32 res
1179
+ | 64 -> clz64 res
1180
+ | _ -> disfailwith " Invalid bitscan width" in
1181
+ let assn_result =
1182
+ let n1 = width - 1 in
1183
+ assn t dst @@ if is_zero_count || is_fwd then Bil. var res
1184
+ else Bil. (var res lxor int Word. (of_int n1 ~width )) in
1185
+ let bil = assn_res :: scan_bil in
1186
+ let bil =
1187
+ if is_zero_count then bil @ Bil. [
1188
+ assn_result;
1189
+ cf := var res = int Word. (of_int ~width width);
1190
+ zf := var res = int Word. (zero width);
1191
+ ]
1192
+ else Bil. [
1193
+ if_ (src_e = int (Word. zero width)) [
1194
+ zf := int Word. b1;
1195
+ assn t dst @@ unknown " bits" t;
1196
+ ] (bil @ Bil. [assn_result; zf := int Word. b0]);
1197
+ ] in
1198
+ bil @ bitscan_flags is_zero_count
1098
1199
| Hlt -> [] (* x86 Hlt is essentially a NOP *)
1099
1200
| Rdtsc ->
1100
1201
let undef reg = assn reg32_t reg (Bil. Unknown (" rdtsc" , reg32_t)) in
@@ -1233,11 +1334,17 @@ module ToIR = struct
1233
1334
| Popcnt (t , s , d ) ->
1234
1335
let width = !! t in
1235
1336
let bits = op2e t s in
1236
- let bitvector = Array. to_list (Array. init width ~f: (fun i -> Bil. (Ite (Extract (i, i, bits), int_exp 1 width, int_exp 0 width)))) in
1237
- let count = List. reduce_exn ~f: Bil. (+ ) bitvector in
1238
- set_zf width bits
1239
- :: assn t d count
1240
- :: List. map ~f: (fun r -> Bil. Move (r, int_exp 0 1 )) [cf; oF; sf; af; pf]
1337
+ let res = tmp t in
1338
+ let assn_src = Bil. (res := bits) in
1339
+ let cnt = match width with
1340
+ | 16 -> popcnt16 res
1341
+ | 32 -> popcnt32 res
1342
+ | 64 -> popcnt64 res
1343
+ | _ -> disfailwith " Invalid popcnt width" in
1344
+ let bil = (assn_src :: cnt) @ Bil. [assn t d (var res)] in
1345
+ let flags = List. map ~f: (fun r ->
1346
+ Bil. Move (r, int_exp 0 1 )) [cf; oF; sf; af; pf] in
1347
+ set_zf width bits :: (bil @ flags)
1241
1348
| Sahf ->
1242
1349
let assnsf = assns_lflags_to_bap in
1243
1350
let tah = tmp ~name: " AH" reg8_t in
0 commit comments