Skip to content

Commit 9650034

Browse files
authored
flambda-backend: Right-to-left evaluation of arguments of String.get and friends (#354)
* Fix argument evaluation order in the following functions in Cmm_helpers: mk_compare_ints mk_compare_floats safe_divmod_bi stringref_safe string_load bigstring_load arrayref_unsafe bytesset_safe bytes_set bigstring_set * Apply the fix to asmcomp * Add tests for all the above * Add tests for bigarray_get/set and send that are not yet fixed
1 parent f7d3775 commit 9650034

File tree

5 files changed

+173
-21
lines changed

5 files changed

+173
-21
lines changed

asmcomp/cmm_helpers.ml

Lines changed: 22 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -291,16 +291,16 @@ let mk_compare_ints dbg a1 a2 =
291291
| Cconst_natint (c1, _), Cconst_int (c2, _) ->
292292
int_const dbg Nativeint.(compare c1 (of_int c2))
293293
| a1, a2 -> begin
294-
bind "int_cmp" a1 (fun a1 ->
295-
bind "int_cmp" a2 (fun a2 ->
294+
bind "int_cmp" a2 (fun a2 ->
295+
bind "int_cmp" a1 (fun a1 ->
296296
let op1 = Cop(Ccmpi(Cgt), [a1; a2], dbg) in
297297
let op2 = Cop(Ccmpi(Clt), [a1; a2], dbg) in
298298
tag_int(sub_int op1 op2 dbg) dbg))
299299
end
300300

301301
let mk_compare_floats dbg a1 a2 =
302-
bind "float_cmp" a1 (fun a1 ->
303-
bind "float_cmp" a2 (fun a2 ->
302+
bind "float_cmp" a2 (fun a2 ->
303+
bind "float_cmp" a1 (fun a1 ->
304304
let op1 = Cop(Ccmpf(CFgt), [a1; a2], dbg) in
305305
let op2 = Cop(Ccmpf(CFlt), [a1; a2], dbg) in
306306
let op3 = Cop(Ccmpf(CFeq), [a1; a1], dbg) in
@@ -522,8 +522,8 @@ let is_different_from x = function
522522
| _ -> false
523523

524524
let safe_divmod_bi mkop is_safe mkm1 c1 c2 bi dbg =
525-
bind "dividend" c1 (fun c1 ->
526525
bind "divisor" c2 (fun c2 ->
526+
bind "dividend" c1 (fun c1 ->
527527
let c = mkop c1 c2 is_safe dbg in
528528
if Arch.division_crashes_on_overflow
529529
&& (size_int = 4 || bi <> Primitive.Pint32)
@@ -2277,26 +2277,26 @@ let stringref_unsafe arg1 arg2 dbg =
22772277

22782278
let stringref_safe arg1 arg2 dbg =
22792279
tag_int
2280-
(bind "str" arg1 (fun str ->
2281-
bind "index" (untag_int arg2 dbg) (fun idx ->
2280+
(bind "index" (untag_int arg2 dbg) (fun idx ->
2281+
bind "str" arg1 (fun str ->
22822282
Csequence(
22832283
make_checkbound dbg [string_length str dbg; idx],
22842284
Cop(Cload (Byte_unsigned, Mutable),
22852285
[add_int str idx dbg], dbg))))) dbg
22862286

22872287
let string_load size unsafe arg1 arg2 dbg =
22882288
box_sized size dbg
2289-
(bind "str" arg1 (fun str ->
2290-
bind "index" (untag_int arg2 dbg) (fun idx ->
2289+
(bind "index" (untag_int arg2 dbg) (fun idx ->
2290+
bind "str" arg1 (fun str ->
22912291
check_bound unsafe size dbg
22922292
(string_length str dbg)
22932293
idx (unaligned_load size str idx dbg))))
22942294

22952295
let bigstring_load size unsafe arg1 arg2 dbg =
22962296
box_sized size dbg
2297-
(bind "ba" arg1 (fun ba ->
2298-
bind "index" (untag_int arg2 dbg) (fun idx ->
2299-
bind "ba_data"
2297+
(bind "index" (untag_int arg2 dbg) (fun idx ->
2298+
bind "ba" arg1 (fun ba ->
2299+
bind "ba_data"
23002300
(Cop(Cload (Word_int, Mutable), [field_address ba 1 dbg], dbg))
23012301
(fun ba_data ->
23022302
check_bound unsafe size dbg
@@ -2307,8 +2307,8 @@ let bigstring_load size unsafe arg1 arg2 dbg =
23072307
let arrayref_unsafe kind arg1 arg2 dbg =
23082308
match (kind : Lambda.array_kind) with
23092309
| Pgenarray ->
2310-
bind "arr" arg1 (fun arr ->
2311-
bind "index" arg2 (fun idx ->
2310+
bind "index" arg2 (fun idx ->
2311+
bind "arr" arg1 (fun arr ->
23122312
Cifthenelse(is_addr_array_ptr arr dbg,
23132313
dbg,
23142314
addr_array_ref arr idx dbg,
@@ -2395,14 +2395,15 @@ let bytesset_unsafe arg1 arg2 arg3 dbg =
23952395

23962396
let bytesset_safe arg1 arg2 arg3 dbg =
23972397
return_unit dbg
2398-
(bind "str" arg1 (fun str ->
2398+
(bind "newval" (untag_int arg3 dbg) (fun newval ->
23992399
bind "index" (untag_int arg2 dbg) (fun idx ->
2400+
bind "str" arg1 (fun str ->
24002401
Csequence(
24012402
make_checkbound dbg [string_length str dbg; idx],
24022403
Cop(Cstore (Byte_unsigned, Assignment),
24032404
[add_int str idx dbg;
2404-
ignore_high_bit_int (untag_int arg3 dbg)],
2405-
dbg)))))
2405+
ignore_high_bit_int newval],
2406+
dbg))))))
24062407

24072408
let arrayset_unsafe kind arg1 arg2 arg3 dbg =
24082409
return_unit dbg (match (kind: Lambda.array_kind) with
@@ -2490,17 +2491,17 @@ let arrayset_safe kind arg1 arg2 arg3 dbg =
24902491

24912492
let bytes_set size unsafe arg1 arg2 arg3 dbg =
24922493
return_unit dbg
2493-
(bind "str" arg1 (fun str ->
2494+
(bind "newval" arg3 (fun newval ->
24942495
bind "index" (untag_int arg2 dbg) (fun idx ->
2495-
bind "newval" arg3 (fun newval ->
2496+
bind "str" arg1 (fun str ->
24962497
check_bound unsafe size dbg (string_length str dbg)
24972498
idx (unaligned_set size str idx newval dbg)))))
24982499

24992500
let bigstring_set size unsafe arg1 arg2 arg3 dbg =
25002501
return_unit dbg
2501-
(bind "ba" arg1 (fun ba ->
2502+
(bind "newval" arg3 (fun newval ->
25022503
bind "index" (untag_int arg2 dbg) (fun idx ->
2503-
bind "newval" arg3 (fun newval ->
2504+
bind "ba" arg1 (fun ba ->
25042505
bind "ba_data"
25052506
(Cop(Cload (Word_int, Mutable), [field_address ba 1 dbg], dbg))
25062507
(fun ba_data ->
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
(* TEST
2+
*)
3+
external unsafe_get : 'a array -> int -> 'a = "%array_unsafe_get"
4+
external caml_bytes_get_16 : bytes -> int -> int = "%caml_bytes_get16"
5+
external caml_bytes_set_16 : bytes -> int -> int -> unit = "%caml_bytes_set16"
6+
7+
open Bigarray
8+
type bigstring = (char, int8_unsigned_elt, c_layout) Array1.t
9+
10+
external caml_bigstring_get_16 :
11+
bigstring -> int -> int = "%caml_bigstring_get16"
12+
13+
external caml_bigstring_set_16 :
14+
bigstring -> int -> int -> unit = "%caml_bigstring_set16"
15+
16+
let bigstring_of_string s =
17+
let a = Array1.create char c_layout (String.length s) in
18+
for i = 0 to String.length s - 1 do
19+
a.{i} <- s.[i]
20+
done;
21+
a
22+
23+
let () =
24+
(* stringref_safe *)
25+
String.get (print_endline "hello"; "foo") (print_endline "world"; 0)
26+
|> Printf.printf "%c\n";
27+
28+
(* string_load *)
29+
caml_bytes_get_16 (print_endline "hello"; Bytes.make 10 '\x00')
30+
(print_endline "world"; 0)
31+
|> Printf.printf "%x\n";
32+
33+
(* bigstring_load *)
34+
caml_bigstring_get_16 (print_endline "hello";
35+
bigstring_of_string (String.make 10 '\x00'))
36+
(print_endline "world"; 0)
37+
|> Printf.printf "%x\n";
38+
39+
(* bytes_set *)
40+
caml_bytes_set_16 (print_endline "a"; Bytes.make 10 '\x00')
41+
(print_endline "b"; 0)
42+
(print_endline "c"; 0xFF);
43+
44+
(* bigstring_set *)
45+
caml_bigstring_set_16 (print_endline "a";
46+
bigstring_of_string (String.make 10 '\x00'))
47+
(print_endline "b"; 0)
48+
(print_endline "c"; 0xFF);
49+
50+
(* mk_compare_ints_untagged *)
51+
print_int (compare (print_endline "A"; Sys.opaque_identity (2))
52+
(print_endline "B"; Sys.opaque_identity (3)));
53+
print_newline ();
54+
55+
(* mk_compare_floats *)
56+
print_int (compare (print_endline "A"; Sys.opaque_identity (2.0))
57+
(print_endline "B"; Sys.opaque_identity (3.5)));
58+
print_newline ();
59+
60+
(* bytesset_safe *)
61+
Bytes.set (print_endline "a"; Bytes.make 10 '\x00')
62+
(print_endline "b"; 0)
63+
(print_endline "c"; 'c');
64+
65+
(* safe_div_bi *)
66+
Printf.printf "%nd\n"
67+
(Nativeint.div (print_endline "A"; Sys.opaque_identity (6n))
68+
(print_endline "B"; Sys.opaque_identity (3n)));
69+
70+
(* arrayref_unsafe *)
71+
let[@inline never] test_arrayref_unsafe
72+
: type t . t array -> int -> (t -> string) -> unit =
73+
fun a i c ->
74+
print_endline (c (Array.unsafe_get (print_endline "A"; a) (print_endline "B"; i)))
75+
in
76+
test_arrayref_unsafe [| "1";"2";"3" |] 0 Fun.id;
77+
78+
()
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
world
2+
hello
3+
f
4+
world
5+
hello
6+
0
7+
world
8+
hello
9+
0
10+
c
11+
b
12+
a
13+
c
14+
b
15+
a
16+
B
17+
A
18+
-1
19+
B
20+
A
21+
-1
22+
c
23+
b
24+
a
25+
B
26+
A
27+
2
28+
B
29+
A
30+
1
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
(* TEST
2+
* bytecode
3+
*)
4+
5+
(* The following examples have different output on bytecode and native.
6+
The order of evaluation of arguments in cmm_helpers needs to be fixed. *)
7+
open Bigarray
8+
let () =
9+
(* CR gyorsh: fix bigarray_get *)
10+
let[@inline never] test_bigarray_get
11+
(a : (Complex.t, complex32_elt, c_layout) Array1.t)
12+
(i : int) =
13+
print_float (Array1.unsafe_get (print_endline "A"; a)
14+
(print_endline "B"; i)).Complex.re;
15+
print_newline ()
16+
in
17+
test_bigarray_get (Array1.init complex32 c_layout 3 (fun _ -> Complex.one)) 0;
18+
19+
(* CR gyorsh: fix bigarray_set *)
20+
let[@inline never] test_bigarray_set
21+
(a : (Complex.t, complex32_elt, c_layout) Array1.t)
22+
(i : int) =
23+
Array1.unsafe_set (print_endline "A"; a) (print_endline "B"; i)
24+
(print_endline "C"; Complex.i);
25+
print_endline "?"
26+
in
27+
test_bigarray_set (Array1.create complex32 c_layout 3) 0;
28+
29+
(* CR gyorsh: fix send *)
30+
let[@inline never] test_send o x =
31+
(print_endline "A"; o)#m (print_endline "B"; x)
32+
in
33+
test_send (object method m (_ : int) = print_endline "m" end) 1
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
B
2+
A
3+
1.
4+
C
5+
B
6+
A
7+
?
8+
B
9+
A
10+
m

0 commit comments

Comments
 (0)