blob: 459e3eba968e71ccb316c55b3003c2642ba29b70 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
|
(* TEST
include config
flags = "-w -55"
ocamlc_flags = "config.cmo"
ocamlopt_flags = "-inline 20 config.cmx"
* native
*)
let eliminate_intermediate_float_record () =
let r = ref 0. in
for n = 1 to 1000 do
let open Complex in
let c = { re = float n; im = 0. } in
(* The following line triggers warning 55 twice when compiled without
flambda. It would be better to disable this warning just here but since
this is a backend-warning, this is not currently possible. Hence the use
of the -w-55 command-line flag for this test *)
r := !r +. (norm [@inlined]) ((add [@inlined]) c i);
done;
ignore (Sys.opaque_identity !r)
module PR_6686 = struct
type t =
| A of float
| B of (int * int)
let rec foo = function
| A x -> x
| B (x, y) -> float x +. float y
let (_ : float) = foo (A 4.)
end
module PR_6770 = struct
type t =
| Constant of float
| Exponent of (float * float)
let to_string = function
| Exponent (_b, _e) ->
ignore _b;
ignore _e;
""
| Constant _ -> ""
let _ = to_string (Constant 4.)
end
let check_noalloc name f =
let a0 = Gc.allocated_bytes () in
let a1 = Gc.allocated_bytes () in
let _x = f () in
let a2 = Gc.allocated_bytes () in
let alloc = (a2 -. 2. *. a1 +. a0) in
match Sys.backend_type with
| Sys.Bytecode -> ()
| Sys.Native ->
if alloc > 100. then
failwith (Printf.sprintf "%s; alloc = %.0f" name alloc)
| _ -> assert false
module GPR_109 = struct
let f () =
let r = ref 0. in
for i = 1 to 1000 do
let x = float i in
let y = if i mod 2 = 0 then x else x +. 1. in
r := !r +. y
done;
!r
let () = check_noalloc "gpr 1O9" f
end
let unbox_classify_float () =
let x = ref 100. in
for i = 1 to 1000 do
assert (classify_float !x = FP_normal);
x := !x +. 1.
done;
ignore (Sys.opaque_identity !x)
let unbox_compare_float () =
let module M = struct type sf = { mutable x: float; y: float; } end in
let x = { M.x=100. ; y=1. } in
for i = 1 to 1000 do
assert (compare x.M.x x.M.y >= 0);
x.M.x <- x.M.x +. 1.
done;
ignore (Sys.opaque_identity x.M.x)
let unbox_float_refs () =
let r = ref nan in
for i = 1 to 1000 do r := !r +. float i done;
ignore (Sys.opaque_identity !r)
let unbox_let_float () =
let r = ref 0. in
for i = 1 to 1000 do
let y =
if i mod 2 = 0 then nan else float i
in
r := !r +. (y *. 2.)
done;
ignore (Sys.opaque_identity !r)
type block =
{ mutable float : float;
mutable int32 : int32 }
let make_some_block record =
{ record with int32 = record.int32 }
let unbox_record_1 record =
(* There is some let lifting problem to handle that case with one
round, this currently requires 2 rounds to be correctly
recognized as a mutable variable pattern *)
(* let block = (make_some_block [@inlined]) record in *)
let block = { record with int32 = record.int32 } in
for i = 1 to 1000 do
let y_float =
if i mod 2 = 0 then nan else Stdlib.float i
in
block.float <- block.float +. (y_float *. 2.);
let y_int32 =
if i mod 2 = 0 then Int32.max_int else Int32.of_int i
in
block.int32 <- Int32.(add block.int32 (mul y_int32 2l))
done;
ignore (Sys.opaque_identity block.float);
ignore (Sys.opaque_identity block.int32)
[@@inline never]
(* Prevent inlining to test that the type is effectively used *)
let float_int32_record = { float = 3.14; int32 = 12l }
let unbox_record () =
unbox_record_1 float_int32_record
let r = ref 0.
let unbox_only_if_useful () =
for i = 1 to 1000 do
let x =
if i mod 2 = 0 then 1.
else 0.
in
r := x; (* would force boxing if the let binding above were unboxed *)
r := x (* use [x] twice to avoid elimination of the let-binding *)
done;
ignore (Sys.opaque_identity !r)
let unbox_minor_words () =
for i = 1 to 1000 do
ignore (Gc.minor_words () = 0.)
done
let ignore_useless_args () =
let f x _y = int_of_float (cos x) in
let rec g a n x =
if n = 0
then a
else g (a + (f [@inlined always]) x (x +. 1.)) (n - 1) x
in
ignore (g 0 10 5.)
let () =
check_noalloc "classify float" unbox_classify_float;
check_noalloc "compare float" unbox_compare_float;
check_noalloc "float refs" unbox_float_refs;
check_noalloc "unbox let float" unbox_let_float;
check_noalloc "unbox only if useful" unbox_only_if_useful;
check_noalloc "ignore useless args" ignore_useless_args;
if Config.flambda then begin
check_noalloc "float and int32 record" unbox_record;
check_noalloc "eliminate intermediate immutable float record"
eliminate_intermediate_float_record;
end;
check_noalloc "Gc.minor_words" unbox_minor_words;
()
|