Skip to content

Commit 790a103

Browse files
committed
Fix bigarray kinds + prim translation
Add boxing/unboxing when translating bigarray loads/sets since the rpimitives take unboxed/untagged arguments, and returns untagged/unboxed results. This uncovered another bug, which was that the kinds for bigarray elements in flambda_primitives.ml were wrong.
1 parent edbc19a commit 790a103

File tree

2 files changed

+148
-38
lines changed

2 files changed

+148
-38
lines changed

middle_end/flambda2.0/from_lambda/lambda_to_flambda_primitives.ml

Lines changed: 145 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -52,38 +52,127 @@ let bint_shift bi prim arg1 arg2 =
5252
(Binary (Int_shift (C.standard_int_of_boxed_integer bi, prim),
5353
unbox_bint bi arg1, untag_int arg2))
5454

55-
let string_or_bytes_access_validity_condition str kind index : H.expr_primitive =
55+
(* offset to substract to a string length depending
56+
on the size of the read/write *)
57+
let length_offset_of_size size =
58+
let offset =
59+
match (size : Flambda_primitive.string_accessor_width) with
60+
| Eight -> 0
61+
| Sixteen -> 1
62+
| Thirty_two -> 3
63+
| Sixty_four -> 7
64+
in
65+
Immediate.int (Targetint.OCaml.of_int offset)
66+
67+
(* equivalent to the one in `cmm_helpers.ml` *)
68+
let max_or_zero size_int x =
69+
let register_bitsize_minus_one =
70+
H.Simple (Simple.const (Naked_immediate (
71+
Immediate.int (Targetint.OCaml.of_int (size_int * 8 - 1)))))
72+
in
73+
let sign =
74+
H.Prim (Binary (Int_shift (Naked_nativeint, Asr),
75+
x, register_bitsize_minus_one)) in
76+
let minus_one =
77+
H.Simple (Simple.const (Naked_nativeint (Targetint.of_int (-1))))
78+
in
79+
let sign_negation =
80+
H.Prim (Binary (Int_arith (Naked_nativeint, Xor),
81+
sign, minus_one)) in
82+
let ret =
83+
H.Prim (Binary (Int_arith (Naked_nativeint, And),
84+
sign_negation, x)) in
85+
ret
86+
87+
(* actual (strict) upper bound for an index in a string read/write *)
88+
let actual_max_length size_int size length =
89+
if size = (Eight : Flambda_primitive.string_accessor_width) then
90+
length (* micro-optimization *)
91+
else begin
92+
let offset = length_offset_of_size size in
93+
let reduced_length =
94+
H.Prim (Binary (Int_arith (Naked_immediate, Sub),
95+
length, Simple (Simple.const (Naked_immediate offset))))
96+
in
97+
let reduced_length_nativeint =
98+
H.Prim (Unary (Num_conv { src = Naked_immediate; dst = Naked_nativeint },
99+
reduced_length))
100+
in
101+
let nativeint_res = max_or_zero size_int reduced_length_nativeint in
102+
H.Prim (Unary (Num_conv { src = Naked_nativeint; dst = Naked_immediate },
103+
nativeint_res))
104+
end
105+
106+
let string_or_bytes_access_validity_condition
107+
size_int str kind size index : H.expr_primitive =
56108
Binary (Int_comp (I.Naked_immediate, Unsigned, Lt),
57109
untag_int index,
58-
(Prim (Unary (String_length kind, str))))
110+
actual_max_length size_int size (Prim (Unary (String_length kind, str))))
59111

60-
let string_or_bytes_ref kind arg1 arg2 dbg : H.expr_primitive =
112+
let string_or_bytes_ref size_int kind arg1 arg2 dbg : H.expr_primitive =
61113
Checked {
62114
primitive =
63115
tag_int (Binary (String_or_bigstring_load (kind, Eight), arg1, arg2));
64116
validity_conditions = [
65-
string_or_bytes_access_validity_condition arg1 String arg2;
117+
string_or_bytes_access_validity_condition size_int arg1 String Eight arg2;
66118
];
67119
failure = Index_out_of_bounds;
68120
dbg;
69121
}
70122

71-
let bigstring_access_validity_condition bstr index : H.expr_primitive =
123+
let bigstring_access_validity_condition size_int bstr size index : H.expr_primitive =
72124
Binary (Int_comp (I.Naked_immediate, Unsigned, Lt),
73125
untag_int index,
74-
(Prim (Unary (Bigarray_length { dimension = 1; }, bstr))))
126+
actual_max_length size_int size
127+
(Prim (Unary (Bigarray_length { dimension = 1; }, bstr))))
75128

76129
(* CR mshinwell: Same problems as previous function *)
77-
let bigstring_ref size arg1 arg2 dbg : H.expr_primitive =
130+
let bigstring_ref size_int size arg1 arg2 dbg : H.expr_primitive =
131+
let wrap =
132+
match (size : Flambda_primitive.string_accessor_width) with
133+
| Eight | Sixteen -> tag_int
134+
| Thirty_two -> box_bint Pint32
135+
| Sixty_four -> box_bint Pint64
136+
in
78137
Checked {
79-
primitive = Binary (String_or_bigstring_load (Bigstring, size), arg1, arg2);
138+
primitive =
139+
wrap (Binary (String_or_bigstring_load (Bigstring, size), arg1, arg2));
80140
validity_conditions = [
81-
bigstring_access_validity_condition arg1 arg2;
141+
bigstring_access_validity_condition size_int arg1 size arg2;
82142
];
83143
failure = Index_out_of_bounds;
84144
dbg;
85145
}
86146

147+
let boxable_number_of_naked_number_kind k : K.Boxable_number.t =
148+
match (k : K.Naked_number_kind.t) with
149+
| Naked_immediate -> Untagged_immediate
150+
| Naked_float -> Naked_float
151+
| Naked_int32 -> Naked_int32
152+
| Naked_int64 -> Naked_int64
153+
| Naked_nativeint -> Naked_nativeint
154+
155+
let bigarray_wrap_of_kind kind =
156+
match P.element_kind_of_bigarray_kind kind with
157+
| Value -> Fun.id
158+
| Fabricated -> assert false
159+
| Naked_number k ->
160+
let bi = boxable_number_of_naked_number_kind k in
161+
(fun arg -> H.Unary (Box_number bi, Prim arg))
162+
163+
let bigarray_unwrap_of_kind kind =
164+
match P.element_kind_of_bigarray_kind kind with
165+
| Value -> Fun.id
166+
| Fabricated -> assert false
167+
| Naked_number k ->
168+
let bi = boxable_number_of_naked_number_kind k in
169+
(fun arg -> H.Prim (Unary (Unbox_number bi, arg)))
170+
171+
let bigarray_map_last f l =
172+
match List.rev l with
173+
| [] -> assert false
174+
| h :: r -> List.rev (f h :: r)
175+
87176
let convert_lprim ~backend (prim : L.primitive) (args : Simple.t list)
88177
(dbg : Debuginfo.t) : H.expr_primitive =
89178
let args = List.map (fun arg : H.simple_or_prim -> Simple arg) args in
@@ -215,9 +304,11 @@ let convert_lprim ~backend (prim : L.primitive) (args : Simple.t list)
215304
| Pbytesrefu, [arg1; arg2] ->
216305
tag_int (Binary (String_or_bigstring_load (Bytes, Eight), arg1, arg2))
217306
| Pbytesrefs, [arg1; arg2] ->
218-
string_or_bytes_ref Bytes arg1 arg2 dbg
307+
let module B = (val backend : Flambda2_backend_intf.S) in
308+
string_or_bytes_ref B.size_int Bytes arg1 arg2 dbg
219309
| Pstringrefs, [arg1; arg2] ->
220-
string_or_bytes_ref String arg1 arg2 dbg
310+
let module B = (val backend : Flambda2_backend_intf.S) in
311+
string_or_bytes_ref B.size_int String arg1 arg2 dbg
221312
| Pstring_load_16 true (* unsafe *), [arg1; arg2]
222313
| Pbytes_load_16 true (* unsafe *), [arg1; arg2] ->
223314
tag_int (Binary (String_or_bigstring_load (String, Sixteen), arg1, arg2))
@@ -232,72 +323,78 @@ let convert_lprim ~backend (prim : L.primitive) (args : Simple.t list)
232323
Prim (Binary (String_or_bigstring_load (String, Sixty_four),
233324
arg1, arg2)))
234325
| Pstring_load_16 false, [str; index] ->
326+
let module B = (val backend : Flambda2_backend_intf.S) in
235327
Checked {
236328
primitive =
237329
tag_int
238330
(Binary (String_or_bigstring_load (String, Sixteen), str, index));
239331
validity_conditions = [
240-
string_or_bytes_access_validity_condition str String index;
332+
string_or_bytes_access_validity_condition B.size_int str String Sixteen index;
241333
];
242334
failure = Index_out_of_bounds;
243335
dbg;
244336
}
245337
| Pstring_load_32 false, [str; index] ->
338+
let module B = (val backend : Flambda2_backend_intf.S) in
246339
Checked {
247340
primitive =
248341
Unary (Box_number Naked_int32,
249342
Prim (Binary (String_or_bigstring_load (String, Thirty_two),
250343
str, index)));
251344
validity_conditions = [
252-
string_or_bytes_access_validity_condition str String index;
345+
string_or_bytes_access_validity_condition B.size_int str String Thirty_two index;
253346
];
254347
failure = Index_out_of_bounds;
255348
dbg;
256349
}
257350
| Pstring_load_64 false, [str; index] ->
351+
let module B = (val backend : Flambda2_backend_intf.S) in
258352
Checked {
259353
primitive =
260354
Unary (Box_number Naked_int64,
261355
Prim (Binary (String_or_bigstring_load (String, Sixty_four),
262356
str, index)));
263357
validity_conditions = [
264-
string_or_bytes_access_validity_condition str String index;
358+
string_or_bytes_access_validity_condition B.size_int str String Sixty_four index;
265359
];
266360
failure = Index_out_of_bounds;
267361
dbg;
268362
}
269363
(* CR mshinwell: factor out *)
270364
| Pbytes_load_16 false, [bytes; index] ->
365+
let module B = (val backend : Flambda2_backend_intf.S) in
271366
Checked {
272367
primitive =
273368
tag_int
274369
(Binary (String_or_bigstring_load (Bytes, Sixteen), bytes, index));
275370
validity_conditions = [
276-
string_or_bytes_access_validity_condition bytes Bytes index;
371+
string_or_bytes_access_validity_condition B.size_int bytes Bytes Sixteen index;
277372
];
278373
failure = Index_out_of_bounds;
279374
dbg;
280375
}
281376
| Pbytes_load_32 false, [bytes; index] ->
377+
let module B = (val backend : Flambda2_backend_intf.S) in
282378
Checked {
283379
primitive =
284380
Unary (Box_number Naked_int32,
285381
Prim (Binary (String_or_bigstring_load (Bytes, Thirty_two),
286382
bytes, index)));
287383
validity_conditions = [
288-
string_or_bytes_access_validity_condition bytes Bytes index;
384+
string_or_bytes_access_validity_condition B.size_int bytes Bytes Thirty_two index;
289385
];
290386
failure = Index_out_of_bounds;
291387
dbg;
292388
}
293389
| Pbytes_load_64 false, [bytes; index] ->
390+
let module B = (val backend : Flambda2_backend_intf.S) in
294391
Checked {
295392
primitive =
296393
Unary (Box_number Naked_int64,
297394
Prim (Binary (String_or_bigstring_load (Bytes, Sixty_four),
298395
bytes, index)));
299396
validity_conditions = [
300-
string_or_bytes_access_validity_condition bytes Bytes index;
397+
string_or_bytes_access_validity_condition B.size_int bytes Bytes Sixty_four index;
301398
];
302399
failure = Index_out_of_bounds;
303400
dbg;
@@ -313,34 +410,37 @@ let convert_lprim ~backend (prim : L.primitive) (args : Simple.t list)
313410
Ternary (Bytes_or_bigstring_set (Bytes, Sixty_four),
314411
bytes, index, Prim (Unary (Unbox_number Naked_int64, new_value)))
315412
| Pbytes_set_16 false, [bytes; index; new_value] ->
413+
let module B = (val backend : Flambda2_backend_intf.S) in
316414
Checked {
317415
primitive =
318416
Ternary (Bytes_or_bigstring_set (Bytes, Sixteen),
319417
bytes, index, untag_int new_value);
320418
validity_conditions = [
321-
string_or_bytes_access_validity_condition bytes Bytes index;
419+
string_or_bytes_access_validity_condition B.size_int bytes Bytes Sixteen index;
322420
];
323421
failure = Index_out_of_bounds;
324422
dbg;
325423
}
326424
| Pbytes_set_32 false, [bytes; index; new_value] ->
425+
let module B = (val backend : Flambda2_backend_intf.S) in
327426
Checked {
328427
primitive =
329428
Ternary (Bytes_or_bigstring_set (Bytes, Thirty_two),
330429
bytes, index, Prim (Unary (Unbox_number Naked_int32, new_value)));
331430
validity_conditions = [
332-
string_or_bytes_access_validity_condition bytes Bytes index;
431+
string_or_bytes_access_validity_condition B.size_int bytes Bytes Thirty_two index;
333432
];
334433
failure = Index_out_of_bounds;
335434
dbg;
336435
}
337436
| Pbytes_set_64 false, [bytes; index; new_value] ->
437+
let module B = (val backend : Flambda2_backend_intf.S) in
338438
Checked {
339439
primitive =
340440
Ternary (Bytes_or_bigstring_set (Bytes, Sixty_four),
341441
bytes, index, Prim (Unary (Unbox_number Naked_int64, new_value)));
342442
validity_conditions = [
343-
string_or_bytes_access_validity_condition bytes Bytes index;
443+
string_or_bytes_access_validity_condition B.size_int bytes Bytes Sixty_four index;
344444
];
345445
failure = Index_out_of_bounds;
346446
dbg;
@@ -631,12 +731,13 @@ let convert_lprim ~backend (prim : L.primitive) (args : Simple.t list)
631731
Ternary (Bytes_or_bigstring_set (Bytes, Eight), bytes, index,
632732
untag_int new_value)
633733
| Pbytessets, [bytes; index; new_value] ->
734+
let module B = (val backend : Flambda2_backend_intf.S) in
634735
Checked {
635736
primitive =
636737
Ternary (Bytes_or_bigstring_set (Bytes, Eight),
637738
bytes, index, untag_int new_value);
638739
validity_conditions = [
639-
string_or_bytes_access_validity_condition bytes Bytes index;
740+
string_or_bytes_access_validity_condition B.size_int bytes Bytes Eight index;
640741
];
641742
failure = Index_out_of_bounds;
642743
dbg;
@@ -694,64 +795,73 @@ let convert_lprim ~backend (prim : L.primitive) (args : Simple.t list)
694795
let is_safe : P.is_safe = if unsafe then Unsafe else Safe in
695796
let kind = C.convert_bigarray_kind kind in
696797
let layout = C.convert_bigarray_layout layout in
697-
Variadic (Bigarray_load (is_safe, num_dimensions, kind, layout), args)
798+
let wrap = bigarray_wrap_of_kind kind in
799+
wrap (Variadic (Bigarray_load (is_safe, num_dimensions, kind, layout), args))
698800
| Pbigarrayset (unsafe, num_dimensions, kind, layout), args ->
699801
let is_safe : P.is_safe = if unsafe then Unsafe else Safe in
700802
let kind = C.convert_bigarray_kind kind in
701803
let layout = C.convert_bigarray_layout layout in
702-
Variadic (Bigarray_set (is_safe, num_dimensions, kind, layout), args)
804+
let unwrap = bigarray_unwrap_of_kind kind in
805+
let new_args = bigarray_map_last unwrap args in
806+
Variadic (Bigarray_set (is_safe, num_dimensions, kind, layout), new_args)
703807
| Pbigarraydim dimension, [arg] ->
704808
tag_int (Unary (Bigarray_length { dimension; }, arg))
705809
| Pbigstring_load_16 true, [arg1; arg2] ->
706810
Binary (String_or_bigstring_load (Bigstring, Sixteen), arg1, arg2)
707811
| Pbigstring_load_16 false, [arg1; arg2] ->
708-
bigstring_ref Sixteen arg1 arg2 dbg
812+
let module B = (val backend : Flambda2_backend_intf.S) in
813+
bigstring_ref B.size_int Sixteen arg1 arg2 dbg
709814
| Pbigstring_load_32 true, [arg1; arg2] ->
710815
Binary (String_or_bigstring_load (Bigstring, Thirty_two), arg1, arg2)
711816
| Pbigstring_load_32 false, [arg1; arg2] ->
712-
bigstring_ref Thirty_two arg1 arg2 dbg
817+
let module B = (val backend : Flambda2_backend_intf.S) in
818+
bigstring_ref B.size_int Thirty_two arg1 arg2 dbg
713819
| Pbigstring_load_64 true, [arg1; arg2] ->
714820
Binary (String_or_bigstring_load (Bigstring, Sixty_four), arg1, arg2)
715821
| Pbigstring_load_64 false, [arg1; arg2] ->
716-
bigstring_ref Sixty_four arg1 arg2 dbg
822+
let module B = (val backend : Flambda2_backend_intf.S) in
823+
bigstring_ref B.size_int Sixty_four arg1 arg2 dbg
717824
| Pbigstring_set_16 true, [bigstring; index; new_value] ->
718825
Ternary (Bytes_or_bigstring_set (Bigstring, Sixteen),
719-
bigstring, index, new_value)
826+
bigstring, index, untag_int new_value)
720827
| Pbigstring_set_32 true, [bigstring; index; new_value] ->
721828
Ternary (Bytes_or_bigstring_set (Bigstring, Thirty_two),
722-
bigstring, index, new_value)
829+
bigstring, index, Prim (Unary (Unbox_number Naked_int32, new_value)))
723830
| Pbigstring_set_64 true, [bigstring; index; new_value] ->
724831
Ternary (Bytes_or_bigstring_set (Bigstring, Sixty_four),
725-
bigstring, index, new_value)
832+
bigstring, index, Prim (Unary (Unbox_number Naked_int64, new_value)))
726833
| Pbigstring_set_16 false, [bigstring; index; new_value] ->
834+
let module B = (val backend : Flambda2_backend_intf.S) in
727835
Checked {
728836
primitive =
729837
Ternary (Bytes_or_bigstring_set (Bigstring, Sixteen),
730-
bigstring, index, new_value);
838+
bigstring, index, untag_int new_value);
731839
validity_conditions = [
732-
bigstring_access_validity_condition bigstring index;
840+
bigstring_access_validity_condition B.size_int bigstring Sixteen index;
733841
];
734842
failure = Index_out_of_bounds;
735843
dbg;
736844
}
737845
| Pbigstring_set_32 false, [bigstring; index; new_value] ->
846+
let module B = (val backend : Flambda2_backend_intf.S) in
738847
Checked {
739848
primitive =
740849
Ternary (Bytes_or_bigstring_set (Bigstring, Thirty_two),
741-
bigstring, index, new_value);
850+
bigstring, index, Prim (Unary (Unbox_number Naked_int32, new_value)));
742851
validity_conditions = [
743-
bigstring_access_validity_condition bigstring index;
852+
bigstring_access_validity_condition B.size_int bigstring Thirty_two index;
744853
];
745854
failure = Index_out_of_bounds;
746855
dbg;
747856
}
748857
| Pbigstring_set_64 false, [bigstring; index; new_value] ->
858+
let module B = (val backend : Flambda2_backend_intf.S) in
749859
Checked {
750860
primitive =
751861
Ternary (Bytes_or_bigstring_set (Bigstring, Sixty_four),
752-
bigstring, index, new_value);
862+
bigstring, index, Prim (Unary (Unbox_number Naked_int64, new_value)));
753863
validity_conditions = [
754-
bigstring_access_validity_condition bigstring index;
864+
bigstring_access_validity_condition B.size_int bigstring Sixty_four index;
755865
];
756866
failure = Index_out_of_bounds;
757867
dbg;

0 commit comments

Comments
 (0)