1(**************************************************************************)
2(*                                                                        *)
3(*                                 OCaml                                  *)
4(*                                                                        *)
5(*             Xavier Leroy, projet Cristal, INRIA Rocquencourt           *)
6(*                                                                        *)
7(*   Copyright 1996 Institut National de Recherche en Informatique et     *)
8(*     en Automatique.                                                    *)
9(*                                                                        *)
10(*   All rights reserved.  This file is distributed under the terms of    *)
11(*   the GNU Lesser General Public License version 2.1, with the          *)
12(*   special exception on linking described in the file LICENSE.          *)
13(*                                                                        *)
14(**************************************************************************)
15
16(* Translation from closed lambda to C-- *)
17
18open Misc
19open Arch
20open Asttypes
21open Primitive
22open Types
23open Lambda
24open Clambda
25open Cmm
26open Cmx_format
27
28(* Environments used for translation to Cmm. *)
29
30type boxed_number =
31  | Boxed_float of Debuginfo.t
32  | Boxed_integer of boxed_integer * Debuginfo.t
33
34type env = {
35  unboxed_ids : (Ident.t * boxed_number) Ident.tbl;
36  environment_param : Ident.t option;
37}
38
39let empty_env =
40  {
41    unboxed_ids =Ident.empty;
42    environment_param = None;
43  }
44
45let create_env ~environment_param =
46  { unboxed_ids = Ident.empty;
47    environment_param;
48  }
49
50let is_unboxed_id id env =
51  try Some (Ident.find_same id env.unboxed_ids)
52  with Not_found -> None
53
54let add_unboxed_id id unboxed_id bn env =
55  { env with
56    unboxed_ids = Ident.add id (unboxed_id, bn) env.unboxed_ids;
57  }
58
59(* Local binding of complex expressions *)
60
61let bind name arg fn =
62  match arg with
63    Cvar _ | Cconst_int _ | Cconst_natint _ | Cconst_symbol _
64  | Cconst_pointer _ | Cconst_natpointer _
65  | Cblockheader _ -> fn arg
66  | _ -> let id = Ident.create name in Clet(id, arg, fn (Cvar id))
67
68let bind_load name arg fn =
69  match arg with
70  | Cop(Cload _, [Cvar _], _) -> fn arg
71  | _ -> bind name arg fn
72
73let bind_nonvar name arg fn =
74  match arg with
75    Cconst_int _ | Cconst_natint _ | Cconst_symbol _
76  | Cconst_pointer _ | Cconst_natpointer _
77  | Cblockheader _ -> fn arg
78  | _ -> let id = Ident.create name in Clet(id, arg, fn (Cvar id))
79
80let caml_black = Nativeint.shift_left (Nativeint.of_int 3) 8
81    (* cf. byterun/gc.h *)
82
83(* Block headers. Meaning of the tag field: see stdlib/obj.ml *)
84
85let floatarray_tag = Cconst_int Obj.double_array_tag
86
87let block_header tag sz =
88  Nativeint.add (Nativeint.shift_left (Nativeint.of_int sz) 10)
89                (Nativeint.of_int tag)
90(* Static data corresponding to "value"s must be marked black in case we are
91   in no-naked-pointers mode.  See [caml_darken] and the code below that emits
92   structured constants and static module definitions. *)
93let black_block_header tag sz = Nativeint.logor (block_header tag sz) caml_black
94let white_closure_header sz = block_header Obj.closure_tag sz
95let black_closure_header sz = black_block_header Obj.closure_tag sz
96let infix_header ofs = block_header Obj.infix_tag ofs
97let float_header = block_header Obj.double_tag (size_float / size_addr)
98let floatarray_header len =
99  (* Zero-sized float arrays have tag zero for consistency with
100     [caml_alloc_float_array]. *)
101  assert (len >= 0);
102  if len = 0 then block_header 0 0
103  else block_header Obj.double_array_tag (len * size_float / size_addr)
104let string_header len =
105      block_header Obj.string_tag ((len + size_addr) / size_addr)
106let boxedint32_header = block_header Obj.custom_tag 2
107let boxedint64_header = block_header Obj.custom_tag (1 + 8 / size_addr)
108let boxedintnat_header = block_header Obj.custom_tag 2
109
110let alloc_float_header dbg = Cblockheader (float_header, dbg)
111let alloc_floatarray_header len dbg = Cblockheader (floatarray_header len, dbg)
112let alloc_closure_header sz dbg = Cblockheader (white_closure_header sz, dbg)
113let alloc_infix_header ofs dbg = Cblockheader (infix_header ofs, dbg)
114let alloc_boxedint32_header dbg = Cblockheader (boxedint32_header, dbg)
115let alloc_boxedint64_header dbg = Cblockheader (boxedint64_header, dbg)
116let alloc_boxedintnat_header dbg = Cblockheader (boxedintnat_header, dbg)
117
118(* Integers *)
119
120let max_repr_int = max_int asr 1
121let min_repr_int = min_int asr 1
122
123let int_const n =
124  if n <= max_repr_int && n >= min_repr_int
125  then Cconst_int((n lsl 1) + 1)
126  else Cconst_natint
127          (Nativeint.add (Nativeint.shift_left (Nativeint.of_int n) 1) 1n)
128
129let cint_const n =
130  Cint(Nativeint.add (Nativeint.shift_left (Nativeint.of_int n) 1) 1n)
131
132let add_no_overflow n x c dbg =
133  let d = n + x in
134  if d = 0 then c else Cop(Caddi, [c; Cconst_int d], dbg)
135
136let rec add_const c n dbg =
137  if n = 0 then c
138  else match c with
139  | Cconst_int x when no_overflow_add x n -> Cconst_int (x + n)
140  | Cop(Caddi, [Cconst_int x; c], _)
141    when no_overflow_add n x ->
142      add_no_overflow n x c dbg
143  | Cop(Caddi, [c; Cconst_int x], _)
144    when no_overflow_add n x ->
145      add_no_overflow n x c dbg
146  | Cop(Csubi, [Cconst_int x; c], _) when no_overflow_add n x ->
147      Cop(Csubi, [Cconst_int (n + x); c], dbg)
148  | Cop(Csubi, [c; Cconst_int x], _) when no_overflow_sub n x ->
149      add_const c (n - x) dbg
150  | c -> Cop(Caddi, [c; Cconst_int n], dbg)
151
152let incr_int c dbg = add_const c 1 dbg
153let decr_int c dbg = add_const c (-1) dbg
154
155let rec add_int c1 c2 dbg =
156  match (c1, c2) with
157  | (Cconst_int n, c) | (c, Cconst_int n) ->
158      add_const c n dbg
159  | (Cop(Caddi, [c1; Cconst_int n1], _), c2) ->
160      add_const (add_int c1 c2 dbg) n1 dbg
161  | (c1, Cop(Caddi, [c2; Cconst_int n2], _)) ->
162      add_const (add_int c1 c2 dbg) n2 dbg
163  | (_, _) ->
164      Cop(Caddi, [c1; c2], dbg)
165
166let rec sub_int c1 c2 dbg =
167  match (c1, c2) with
168  | (c1, Cconst_int n2) when n2 <> min_int ->
169      add_const c1 (-n2) dbg
170  | (c1, Cop(Caddi, [c2; Cconst_int n2], _)) when n2 <> min_int ->
171      add_const (sub_int c1 c2 dbg) (-n2) dbg
172  | (Cop(Caddi, [c1; Cconst_int n1], _), c2) ->
173      add_const (sub_int c1 c2 dbg) n1 dbg
174  | (c1, c2) ->
175      Cop(Csubi, [c1; c2], dbg)
176
177let rec lsl_int c1 c2 dbg =
178  match (c1, c2) with
179  | (Cop(Clsl, [c; Cconst_int n1], _), Cconst_int n2)
180    when n1 > 0 && n2 > 0 && n1 + n2 < size_int * 8 ->
181      Cop(Clsl, [c; Cconst_int (n1 + n2)], dbg)
182  | (Cop(Caddi, [c1; Cconst_int n1], _), Cconst_int n2)
183    when no_overflow_lsl n1 n2 ->
184      add_const (lsl_int c1 c2 dbg) (n1 lsl n2) dbg
185  | (_, _) ->
186      Cop(Clsl, [c1; c2], dbg)
187
188let is_power2 n = n = 1 lsl Misc.log2 n
189
190and mult_power2 c n dbg = lsl_int c (Cconst_int (Misc.log2 n)) dbg
191
192let rec mul_int c1 c2 dbg =
193  match (c1, c2) with
194  | (c, Cconst_int 0) | (Cconst_int 0, c) -> Csequence (c, Cconst_int 0)
195  | (c, Cconst_int 1) | (Cconst_int 1, c) ->
196      c
197  | (c, Cconst_int(-1)) | (Cconst_int(-1), c) ->
198      sub_int (Cconst_int 0) c dbg
199  | (c, Cconst_int n) when is_power2 n -> mult_power2 c n dbg
200  | (Cconst_int n, c) when is_power2 n -> mult_power2 c n dbg
201  | (Cop(Caddi, [c; Cconst_int n], _), Cconst_int k) |
202    (Cconst_int k, Cop(Caddi, [c; Cconst_int n], _))
203    when no_overflow_mul n k ->
204      add_const (mul_int c (Cconst_int k) dbg) (n * k) dbg
205  | (c1, c2) ->
206      Cop(Cmuli, [c1; c2], dbg)
207
208
209let ignore_low_bit_int = function
210    Cop(Caddi, [(Cop(Clsl, [_; Cconst_int n], _) as c); Cconst_int 1], _)
211      when n > 0
212      -> c
213  | Cop(Cor, [c; Cconst_int 1], _) -> c
214  | c -> c
215
216let lsr_int c1 c2 dbg =
217  match c2 with
218    Cconst_int 0 ->
219      c1
220  | Cconst_int n when n > 0 ->
221      Cop(Clsr, [ignore_low_bit_int c1; c2], dbg)
222  | _ ->
223      Cop(Clsr, [c1; c2], dbg)
224
225let asr_int c1 c2 dbg =
226  match c2 with
227    Cconst_int 0 ->
228      c1
229  | Cconst_int n when n > 0 ->
230      Cop(Casr, [ignore_low_bit_int c1; c2], dbg)
231  | _ ->
232      Cop(Casr, [c1; c2], dbg)
233
234let tag_int i dbg =
235  match i with
236    Cconst_int n ->
237      int_const n
238  | Cop(Casr, [c; Cconst_int n], _) when n > 0 ->
239      Cop(Cor, [asr_int c (Cconst_int (n - 1)) dbg; Cconst_int 1], dbg)
240  | c ->
241      incr_int (lsl_int c (Cconst_int 1) dbg) dbg
242
243let force_tag_int i dbg =
244  match i with
245    Cconst_int n ->
246      int_const n
247  | Cop(Casr, [c; Cconst_int n], dbg) when n > 0 ->
248      Cop(Cor, [asr_int c (Cconst_int (n - 1)) dbg; Cconst_int 1], dbg)
249  | c ->
250      Cop(Cor, [lsl_int c (Cconst_int 1) dbg; Cconst_int 1], dbg)
251
252let untag_int i dbg =
253  match i with
254    Cconst_int n -> Cconst_int(n asr 1)
255  | Cop(Caddi, [Cop(Clsl, [c; Cconst_int 1], _); Cconst_int 1], _) -> c
256  | Cop(Cor, [Cop(Casr, [c; Cconst_int n], _); Cconst_int 1], _)
257    when n > 0 && n < size_int * 8 ->
258      Cop(Casr, [c; Cconst_int (n+1)], dbg)
259  | Cop(Cor, [Cop(Clsr, [c; Cconst_int n], _); Cconst_int 1], _)
260    when n > 0 && n < size_int * 8 ->
261      Cop(Clsr, [c; Cconst_int (n+1)], dbg)
262  | Cop(Cor, [c; Cconst_int 1], _) -> Cop(Casr, [c; Cconst_int 1], dbg)
263  | c -> Cop(Casr, [c; Cconst_int 1], dbg)
264
265let if_then_else (cond, ifso, ifnot) =
266  match cond with
267  | Cconst_int 0 -> ifnot
268  | Cconst_int 1 -> ifso
269  | _ ->
270    Cifthenelse(cond, ifso, ifnot)
271
272(* Turning integer divisions into multiply-high then shift.
273   The [division_parameters] function is used in module Emit for
274   those target platforms that support this optimization. *)
275
276(* Unsigned comparison between native integers. *)
277
278let ucompare x y = Nativeint.(compare (add x min_int) (add y min_int))
279
280(* Unsigned division and modulus at type nativeint.
281   Algorithm: Hacker's Delight section 9.3 *)
282
283let udivmod n d = Nativeint.(
284  if d < 0n then
285    if ucompare n d < 0 then (0n, n) else (1n, sub n d)
286  else begin
287    let q = shift_left (div (shift_right_logical n 1) d) 1 in
288    let r = sub n (mul q d) in
289    if ucompare r d >= 0 then (succ q, sub r d) else (q, r)
290  end)
291
292(* Compute division parameters.
293   Algorithm: Hacker's Delight chapter 10, fig 10-1. *)
294
295let divimm_parameters d = Nativeint.(
296  assert (d > 0n);
297  let twopsm1 = min_int in (* 2^31 for 32-bit archs, 2^63 for 64-bit archs *)
298  let nc = sub (pred twopsm1) (snd (udivmod twopsm1 d)) in
299  let rec loop p (q1, r1) (q2, r2) =
300    let p = p + 1 in
301    let q1 = shift_left q1 1 and r1 = shift_left r1 1 in
302    let (q1, r1) =
303      if ucompare r1 nc >= 0 then (succ q1, sub r1 nc) else (q1, r1) in
304    let q2 = shift_left q2 1 and r2 = shift_left r2 1 in
305    let (q2, r2) =
306      if ucompare r2 d >= 0 then (succ q2, sub r2 d) else (q2, r2) in
307    let delta = sub d r2 in
308    if ucompare q1 delta < 0 || (q1 = delta && r1 = 0n)
309    then loop p (q1, r1) (q2, r2)
310    else (succ q2, p - size)
311  in loop (size - 1) (udivmod twopsm1 nc) (udivmod twopsm1 d))
312
313(* The result [(m, p)] of [divimm_parameters d] satisfies the following
314   inequality:
315
316      2^(wordsize + p) < m * d <= 2^(wordsize + p) + 2^(p + 1)    (i)
317
318   from which it follows that
319
320      floor(n / d) = floor(n * m / 2^(wordsize+p))
321                              if 0 <= n < 2^(wordsize-1)
322      ceil(n / d) = floor(n * m / 2^(wordsize+p)) + 1
323                              if -2^(wordsize-1) <= n < 0
324
325   The correctness condition (i) above can be checked by the code below.
326   It was exhaustively tested for values of d from 2 to 10^9 in the
327   wordsize = 64 case.
328
329let add2 (xh, xl) (yh, yl) =
330  let zl = add xl yl and zh = add xh yh in
331  ((if ucompare zl xl < 0 then succ zh else zh), zl)
332
333let shl2 (xh, xl) n =
334  assert (0 < n && n < size + size);
335  if n < size
336  then (logor (shift_left xh n) (shift_right_logical xl (size - n)),
337        shift_left xl n)
338  else (shift_left xl (n - size), 0n)
339
340let mul2 x y =
341  let halfsize = size / 2 in
342  let halfmask = pred (shift_left 1n halfsize) in
343  let xl = logand x halfmask and xh = shift_right_logical x halfsize in
344  let yl = logand y halfmask and yh = shift_right_logical y halfsize in
345  add2 (mul xh yh, 0n)
346    (add2 (shl2 (0n, mul xl yh) halfsize)
347       (add2 (shl2 (0n, mul xh yl) halfsize)
348          (0n, mul xl yl)))
349
350let ucompare2 (xh, xl) (yh, yl) =
351  let c = ucompare xh yh in if c = 0 then ucompare xl yl else c
352
353let validate d m p =
354  let md = mul2 m d in
355  let one2 = (0n, 1n) in
356  let twoszp = shl2 one2 (size + p) in
357  let twop1 = shl2 one2 (p + 1) in
358  ucompare2 twoszp md < 0 && ucompare2 md (add2 twoszp twop1) <= 0
359*)
360
361let raise_regular dbg exc =
362  Csequence(
363    Cop(Cstore (Thirtytwo_signed, Assignment),
364        [(Cconst_symbol "caml_backtrace_pos"); Cconst_int 0], dbg),
365      Cop(Craise Raise_withtrace,[exc], dbg))
366
367let raise_symbol dbg symb =
368  raise_regular dbg (Cconst_symbol symb)
369
370let rec div_int c1 c2 is_safe dbg =
371  match (c1, c2) with
372    (c1, Cconst_int 0) ->
373      Csequence(c1, raise_symbol dbg "caml_exn_Division_by_zero")
374  | (c1, Cconst_int 1) ->
375      c1
376  | (Cconst_int n1, Cconst_int n2) ->
377      Cconst_int (n1 / n2)
378  | (c1, Cconst_int n) when n <> min_int ->
379      let l = Misc.log2 n in
380      if n = 1 lsl l then
381        (* Algorithm:
382              t = shift-right-signed(c1, l - 1)
383              t = shift-right(t, W - l)
384              t = c1 + t
385              res = shift-right-signed(c1 + t, l)
386        *)
387        Cop(Casr, [bind "dividend" c1 (fun c1 ->
388                     let t = asr_int c1 (Cconst_int (l - 1)) dbg in
389                     let t = lsr_int t (Cconst_int (Nativeint.size - l)) dbg in
390                     add_int c1 t dbg);
391                   Cconst_int l], dbg)
392      else if n < 0 then
393        sub_int (Cconst_int 0) (div_int c1 (Cconst_int (-n)) is_safe dbg) dbg
394      else begin
395        let (m, p) = divimm_parameters (Nativeint.of_int n) in
396        (* Algorithm:
397              t = multiply-high-signed(c1, m)
398              if m < 0, t = t + c1
399              if p > 0, t = shift-right-signed(t, p)
400              res = t + sign-bit(c1)
401        *)
402        bind "dividend" c1 (fun c1 ->
403          let t = Cop(Cmulhi, [c1; Cconst_natint m], dbg) in
404          let t = if m < 0n then Cop(Caddi, [t; c1], dbg) else t in
405          let t = if p > 0 then Cop(Casr, [t; Cconst_int p], dbg) else t in
406          add_int t (lsr_int c1 (Cconst_int (Nativeint.size - 1)) dbg) dbg)
407      end
408  | (c1, c2) when !Clflags.fast || is_safe = Lambda.Unsafe ->
409      Cop(Cdivi, [c1; c2], dbg)
410  | (c1, c2) ->
411      bind "divisor" c2 (fun c2 ->
412        bind "dividend" c1 (fun c1 ->
413          Cifthenelse(c2,
414                      Cop(Cdivi, [c1; c2], dbg),
415                      raise_symbol dbg "caml_exn_Division_by_zero")))
416
417let mod_int c1 c2 is_safe dbg =
418  match (c1, c2) with
419    (c1, Cconst_int 0) ->
420      Csequence(c1, raise_symbol dbg "caml_exn_Division_by_zero")
421  | (c1, Cconst_int (1 | (-1))) ->
422      Csequence(c1, Cconst_int 0)
423  | (Cconst_int n1, Cconst_int n2) ->
424      Cconst_int (n1 mod n2)
425  | (c1, (Cconst_int n as c2)) when n <> min_int ->
426      let l = Misc.log2 n in
427      if n = 1 lsl l then
428        (* Algorithm:
429              t = shift-right-signed(c1, l - 1)
430              t = shift-right(t, W - l)
431              t = c1 + t
432              t = bit-and(t, -n)
433              res = c1 - t
434         *)
435        bind "dividend" c1 (fun c1 ->
436          let t = asr_int c1 (Cconst_int (l - 1)) dbg in
437          let t = lsr_int t (Cconst_int (Nativeint.size - l)) dbg in
438          let t = add_int c1 t dbg in
439          let t = Cop(Cand, [t; Cconst_int (-n)], dbg) in
440          sub_int c1 t dbg)
441      else
442        bind "dividend" c1 (fun c1 ->
443          sub_int c1 (mul_int (div_int c1 c2 is_safe dbg) c2 dbg) dbg)
444  | (c1, c2) when !Clflags.fast || is_safe = Lambda.Unsafe ->
445      (* Flambda already generates that test *)
446      Cop(Cmodi, [c1; c2], dbg)
447  | (c1, c2) ->
448      bind "divisor" c2 (fun c2 ->
449        bind "dividend" c1 (fun c1 ->
450          Cifthenelse(c2,
451                      Cop(Cmodi, [c1; c2], dbg),
452                      raise_symbol dbg "caml_exn_Division_by_zero")))
453
454(* Division or modulo on boxed integers.  The overflow case min_int / -1
455   can occur, in which case we force x / -1 = -x and x mod -1 = 0. (PR#5513). *)
456
457let is_different_from x = function
458    Cconst_int n -> n <> x
459  | Cconst_natint n -> n <> Nativeint.of_int x
460  | _ -> false
461
462let safe_divmod_bi mkop is_safe mkm1 c1 c2 bi dbg =
463  bind "dividend" c1 (fun c1 ->
464  bind "divisor" c2 (fun c2 ->
465    let c = mkop c1 c2 is_safe dbg in
466    if Arch.division_crashes_on_overflow
467    && (size_int = 4 || bi <> Pint32)
468    && not (is_different_from (-1) c2)
469    then Cifthenelse(Cop(Ccmpi Cne, [c2; Cconst_int(-1)], dbg), c, mkm1 c1 dbg)
470    else c))
471
472let safe_div_bi is_safe =
473  safe_divmod_bi div_int is_safe
474    (fun c1 dbg -> Cop(Csubi, [Cconst_int 0; c1], dbg))
475
476let safe_mod_bi is_safe =
477  safe_divmod_bi mod_int is_safe (fun _ _ -> Cconst_int 0)
478
479(* Bool *)
480
481let test_bool dbg cmm =
482  match cmm with
483  | Cop(Caddi, [Cop(Clsl, [c; Cconst_int 1], _); Cconst_int 1], _) -> c
484  | Cconst_int n ->
485      if n = 1 then
486        Cconst_int 0
487      else
488        Cconst_int 1
489  | c -> Cop(Ccmpi Cne, [c; Cconst_int 1], dbg)
490
491(* Float *)
492
493let box_float dbg c = Cop(Calloc, [alloc_float_header dbg; c], dbg)
494
495let map_ccatch f rec_flag handlers body =
496  let handlers = List.map
497      (fun (n, ids, handler) -> (n, ids, f handler))
498      handlers in
499  Ccatch(rec_flag, handlers, f body)
500
501let rec unbox_float dbg cmm =
502  match cmm with
503  | Cop(Calloc, [_header; c], _) -> c
504  | Clet(id, exp, body) -> Clet(id, exp, unbox_float dbg body)
505  | Cifthenelse(cond, e1, e2) ->
506      Cifthenelse(cond, unbox_float dbg e1, unbox_float dbg e2)
507  | Csequence(e1, e2) -> Csequence(e1, unbox_float dbg e2)
508  | Cswitch(e, tbl, el, dbg) ->
509    Cswitch(e, tbl, Array.map (unbox_float dbg) el, dbg)
510  | Ccatch(rec_flag, handlers, body) ->
511    map_ccatch (unbox_float dbg) rec_flag handlers body
512  | Ctrywith(e1, id, e2) -> Ctrywith(unbox_float dbg e1, id, unbox_float dbg e2)
513  | c -> Cop(Cload (Double_u, Immutable), [c], dbg)
514
515(* Complex *)
516
517let box_complex dbg c_re c_im =
518  Cop(Calloc, [alloc_floatarray_header 2 dbg; c_re; c_im], dbg)
519
520let complex_re c dbg = Cop(Cload (Double_u, Immutable), [c], dbg)
521let complex_im c dbg = Cop(Cload (Double_u, Immutable),
522                        [Cop(Cadda, [c; Cconst_int size_float], dbg)], dbg)
523
524(* Unit *)
525
526let return_unit c = Csequence(c, Cconst_pointer 1)
527
528let rec remove_unit = function
529    Cconst_pointer 1 -> Ctuple []
530  | Csequence(c, Cconst_pointer 1) -> c
531  | Csequence(c1, c2) ->
532      Csequence(c1, remove_unit c2)
533  | Cifthenelse(cond, ifso, ifnot) ->
534      Cifthenelse(cond, remove_unit ifso, remove_unit ifnot)
535  | Cswitch(sel, index, cases, dbg) ->
536      Cswitch(sel, index, Array.map remove_unit cases, dbg)
537  | Ccatch(rec_flag, handlers, body) ->
538      map_ccatch remove_unit rec_flag handlers body
539  | Ctrywith(body, exn, handler) ->
540      Ctrywith(remove_unit body, exn, remove_unit handler)
541  | Clet(id, c1, c2) ->
542      Clet(id, c1, remove_unit c2)
543  | Cop(Capply _mty, args, dbg) ->
544      Cop(Capply typ_void, args, dbg)
545  | Cop(Cextcall(proc, _mty, alloc, label_after), args, dbg) ->
546      Cop(Cextcall(proc, typ_void, alloc, label_after), args, dbg)
547  | Cexit (_,_) as c -> c
548  | Ctuple [] as c -> c
549  | c -> Csequence(c, Ctuple [])
550
551(* Access to block fields *)
552
553let field_address ptr n dbg =
554  if n = 0
555  then ptr
556  else Cop(Cadda, [ptr; Cconst_int(n * size_addr)], dbg)
557
558let get_field env ptr n dbg =
559  let mut =
560    match env.environment_param with
561    | None -> Mutable
562    | Some environment_param ->
563      match ptr with
564      | Cvar ptr ->
565        (* Loads from the current function's closure are immutable. *)
566        if Ident.same environment_param ptr then Immutable
567        else Mutable
568      | _ -> Mutable
569  in
570  Cop(Cload (Word_val, mut), [field_address ptr n dbg], dbg)
571
572let set_field ptr n newval init dbg =
573  Cop(Cstore (Word_val, init), [field_address ptr n dbg; newval], dbg)
574
575let non_profinfo_mask = (1 lsl (64 - Config.profinfo_width)) - 1
576
577let get_header ptr dbg =
578  (* We cannot deem this as [Immutable] due to the presence of [Obj.truncate]
579     and [Obj.set_tag]. *)
580  Cop(Cload (Word_int, Mutable),
581    [Cop(Cadda, [ptr; Cconst_int(-size_int)], dbg)], dbg)
582
583let get_header_without_profinfo ptr dbg =
584  if Config.profinfo then
585    Cop(Cand, [get_header ptr dbg; Cconst_int non_profinfo_mask], dbg)
586  else
587    get_header ptr dbg
588
589let tag_offset =
590  if big_endian then -1 else -size_int
591
592let get_tag ptr dbg =
593  if Proc.word_addressed then           (* If byte loads are slow *)
594    Cop(Cand, [get_header ptr dbg; Cconst_int 255], dbg)
595  else                                  (* If byte loads are efficient *)
596    Cop(Cload (Byte_unsigned, Mutable), (* Same comment as [get_header] above *)
597        [Cop(Cadda, [ptr; Cconst_int(tag_offset)], dbg)], dbg)
598
599let get_size ptr dbg =
600  Cop(Clsr, [get_header_without_profinfo ptr dbg; Cconst_int 10], dbg)
601
602(* Array indexing *)
603
604let log2_size_addr = Misc.log2 size_addr
605let log2_size_float = Misc.log2 size_float
606
607let wordsize_shift = 9
608let numfloat_shift = 9 + log2_size_float - log2_size_addr
609
610let is_addr_array_hdr hdr dbg =
611  Cop(Ccmpi Cne, [Cop(Cand, [hdr; Cconst_int 255], dbg); floatarray_tag], dbg)
612
613let is_addr_array_ptr ptr dbg =
614  Cop(Ccmpi Cne, [get_tag ptr dbg; floatarray_tag], dbg)
615
616let addr_array_length hdr dbg =
617  Cop(Clsr, [hdr; Cconst_int wordsize_shift], dbg)
618let float_array_length hdr dbg =
619  Cop(Clsr, [hdr; Cconst_int numfloat_shift], dbg)
620
621let lsl_const c n dbg =
622  if n = 0 then c
623  else Cop(Clsl, [c; Cconst_int n], dbg)
624
625(* Produces a pointer to the element of the array [ptr] on the position [ofs]
626   with the given element [log2size] log2 element size. [ofs] is given as a
627   tagged int expression.
628   The optional ?typ argument is the C-- type of the result.
629   By default, it is Addr, meaning we are constructing a derived pointer
630   into the heap.  If we know the pointer is outside the heap
631   (this is the case for bigarray indexing), we give type Int instead. *)
632
633let array_indexing ?typ log2size ptr ofs dbg =
634  let add =
635    match typ with
636    | None | Some Addr -> Cadda
637    | Some Int -> Caddi
638    | _ -> assert false in
639  match ofs with
640  | Cconst_int n ->
641      let i = n asr 1 in
642      if i = 0 then ptr else Cop(add, [ptr; Cconst_int(i lsl log2size)], dbg)
643  | Cop(Caddi, [Cop(Clsl, [c; Cconst_int 1], _); Cconst_int 1], _) ->
644      Cop(add, [ptr; lsl_const c log2size dbg], dbg)
645  | Cop(Caddi, [c; Cconst_int n], _) when log2size = 0 ->
646      Cop(add, [Cop(add, [ptr; untag_int c dbg], dbg); Cconst_int (n asr 1)],
647        dbg)
648  | Cop(Caddi, [c; Cconst_int n], _) ->
649      Cop(add, [Cop(add, [ptr; lsl_const c (log2size - 1) dbg], dbg);
650                    Cconst_int((n-1) lsl (log2size - 1))], dbg)
651  | _ when log2size = 0 ->
652      Cop(add, [ptr; untag_int ofs dbg], dbg)
653  | _ ->
654      Cop(add, [Cop(add, [ptr; lsl_const ofs (log2size - 1) dbg], dbg);
655                    Cconst_int((-1) lsl (log2size - 1))], dbg)
656
657let addr_array_ref arr ofs dbg =
658  Cop(Cload (Word_val, Mutable),
659    [array_indexing log2_size_addr arr ofs dbg], dbg)
660let int_array_ref arr ofs dbg =
661  Cop(Cload (Word_int, Mutable),
662    [array_indexing log2_size_addr arr ofs dbg], dbg)
663let unboxed_float_array_ref arr ofs dbg =
664  Cop(Cload (Double_u, Mutable),
665    [array_indexing log2_size_float arr ofs dbg], dbg)
666let float_array_ref dbg arr ofs =
667  box_float dbg (unboxed_float_array_ref arr ofs dbg)
668
669let addr_array_set arr ofs newval dbg =
670  Cop(Cextcall("caml_modify", typ_void, false, None),
671      [array_indexing log2_size_addr arr ofs dbg; newval], dbg)
672let addr_array_initialize arr ofs newval dbg =
673  Cop(Cextcall("caml_initialize", typ_void, false, None),
674      [array_indexing log2_size_addr arr ofs dbg; newval], dbg)
675let int_array_set arr ofs newval dbg =
676  Cop(Cstore (Word_int, Assignment),
677    [array_indexing log2_size_addr arr ofs dbg; newval], dbg)
678let float_array_set arr ofs newval dbg =
679  Cop(Cstore (Double_u, Assignment),
680    [array_indexing log2_size_float arr ofs dbg; newval], dbg)
681
682(* String length *)
683
684(* Length of string block *)
685
686let string_length exp dbg =
687  bind "str" exp (fun str ->
688    let tmp_var = Ident.create "tmp" in
689    Clet(tmp_var,
690         Cop(Csubi,
691             [Cop(Clsl,
692                   [get_size str dbg;
693                     Cconst_int log2_size_addr],
694                   dbg);
695              Cconst_int 1],
696             dbg),
697         Cop(Csubi,
698             [Cvar tmp_var;
699               Cop(Cload (Byte_unsigned, Mutable),
700                     [Cop(Cadda, [str; Cvar tmp_var], dbg)], dbg)], dbg)))
701
702(* Message sending *)
703
704let lookup_tag obj tag dbg =
705  bind "tag" tag (fun tag ->
706    Cop(Cextcall("caml_get_public_method", typ_val, false, None),
707        [obj; tag],
708        dbg))
709
710let lookup_label obj lab dbg =
711  bind "lab" lab (fun lab ->
712    let table = Cop (Cload (Word_val, Mutable), [obj], dbg) in
713    addr_array_ref table lab dbg)
714
715let call_cached_method obj tag cache pos args dbg =
716  let arity = List.length args in
717  let cache = array_indexing log2_size_addr cache pos dbg in
718  Compilenv.need_send_fun arity;
719  Cop(Capply typ_val,
720      Cconst_symbol("caml_send" ^ string_of_int arity) ::
721        obj :: tag :: cache :: args,
722      dbg)
723
724(* Allocation *)
725
726let make_alloc_generic set_fn dbg tag wordsize args =
727  if wordsize <= Config.max_young_wosize then
728    Cop(Calloc, Cblockheader(block_header tag wordsize, dbg) :: args, dbg)
729  else begin
730    let id = Ident.create "alloc" in
731    let rec fill_fields idx = function
732      [] -> Cvar id
733    | e1::el -> Csequence(set_fn (Cvar id) (Cconst_int idx) e1 dbg,
734                          fill_fields (idx + 2) el) in
735    Clet(id,
736         Cop(Cextcall("caml_alloc", typ_val, true, None),
737                 [Cconst_int wordsize; Cconst_int tag], dbg),
738         fill_fields 1 args)
739  end
740
741let make_alloc dbg tag args =
742  let addr_array_init arr ofs newval dbg =
743    Cop(Cextcall("caml_initialize", typ_void, false, None),
744        [array_indexing log2_size_addr arr ofs dbg; newval], dbg)
745  in
746  make_alloc_generic addr_array_init dbg tag (List.length args) args
747
748let make_float_alloc dbg tag args =
749  make_alloc_generic float_array_set dbg tag
750                     (List.length args * size_float / size_addr) args
751
752(* Bounds checking *)
753
754let make_checkbound dbg = function
755  | [Cop(Clsr, [a1; Cconst_int n], _); Cconst_int m] when (m lsl n) > n ->
756      Cop(Ccheckbound, [a1; Cconst_int(m lsl n + 1 lsl n - 1)], dbg)
757  | args ->
758      Cop(Ccheckbound, args, dbg)
759
760(* To compile "let rec" over values *)
761
762let fundecls_size fundecls =
763  let sz = ref (-1) in
764  List.iter
765    (fun f ->
766       let indirect_call_code_pointer_size =
767         match f.arity with
768         | 0 | 1 -> 0
769           (* arity 1 does not need an indirect call handler.
770              arity 0 cannot be indirect called *)
771         | _ -> 1
772           (* For other arities there is an indirect call handler.
773              if arity >= 2 it is caml_curry...
774              if arity < 0 it is caml_tuplify... *)
775       in
776       sz := !sz + 1 + 2 + indirect_call_code_pointer_size)
777    fundecls;
778  !sz
779
780type rhs_kind =
781  | RHS_block of int
782  | RHS_floatblock of int
783  | RHS_nonrec
784;;
785let rec expr_size env = function
786  | Uvar id ->
787      begin try Ident.find_same id env with Not_found -> RHS_nonrec end
788  | Uclosure(fundecls, clos_vars) ->
789      RHS_block (fundecls_size fundecls + List.length clos_vars)
790  | Ulet(_str, _kind, id, exp, body) ->
791      expr_size (Ident.add id (expr_size env exp) env) body
792  | Uletrec(_bindings, body) ->
793      expr_size env body
794  | Uprim(Pmakeblock _, args, _) ->
795      RHS_block (List.length args)
796  | Uprim(Pmakearray((Paddrarray | Pintarray), _), args, _) ->
797      RHS_block (List.length args)
798  | Uprim(Pmakearray(Pfloatarray, _), args, _) ->
799      RHS_floatblock (List.length args)
800  | Uprim (Pduprecord ((Record_regular | Record_inlined _), sz), _, _) ->
801      RHS_block sz
802  | Uprim (Pduprecord (Record_unboxed _, _), _, _) ->
803      assert false
804  | Uprim (Pduprecord (Record_extension, sz), _, _) ->
805      RHS_block (sz + 1)
806  | Uprim (Pduprecord (Record_float, sz), _, _) ->
807      RHS_floatblock sz
808  | Uprim (Pccall { prim_name; _ }, closure::_, _)
809        when prim_name = "caml_check_value_is_closure" ->
810      (* Used for "-clambda-checks". *)
811      expr_size env closure
812  | Usequence(_exp, exp') ->
813      expr_size env exp'
814  | _ -> RHS_nonrec
815
816(* Record application and currying functions *)
817
818let apply_function n =
819  Compilenv.need_apply_fun n; "caml_apply" ^ string_of_int n
820let curry_function n =
821  Compilenv.need_curry_fun n;
822  if n >= 0
823  then "caml_curry" ^ string_of_int n
824  else "caml_tuplify" ^ string_of_int (-n)
825
826(* Comparisons *)
827
828let transl_comparison = function
829    Lambda.Ceq -> Ceq
830  | Lambda.Cneq -> Cne
831  | Lambda.Cge -> Cge
832  | Lambda.Cgt -> Cgt
833  | Lambda.Cle -> Cle
834  | Lambda.Clt -> Clt
835
836(* Translate structured constants *)
837
838let transl_constant = function
839  | Uconst_int n ->
840      int_const n
841  | Uconst_ptr n ->
842      if n <= max_repr_int && n >= min_repr_int
843      then Cconst_pointer((n lsl 1) + 1)
844      else Cconst_natpointer
845              (Nativeint.add (Nativeint.shift_left (Nativeint.of_int n) 1) 1n)
846  | Uconst_ref (label, _) ->
847      Cconst_symbol label
848
849let transl_structured_constant cst =
850  let label = Compilenv.new_structured_constant cst ~shared:true in
851  Cconst_symbol label
852
853(* Translate constant closures *)
854
855type is_global = Global | Not_global
856
857type symbol_defn = string * is_global
858
859type cmm_constant =
860  | Const_closure of symbol_defn * ufunction list * uconstant list
861  | Const_table of symbol_defn * data_item list
862
863let cmm_constants =
864  ref ([] : cmm_constant list)
865
866let add_cmm_constant c =
867  cmm_constants := c :: !cmm_constants
868
869(* Boxed integers *)
870
871let box_int_constant bi n =
872  match bi with
873    Pnativeint -> Uconst_nativeint n
874  | Pint32 -> Uconst_int32 (Nativeint.to_int32 n)
875  | Pint64 -> Uconst_int64 (Int64.of_nativeint n)
876
877let operations_boxed_int bi =
878  match bi with
879    Pnativeint -> "caml_nativeint_ops"
880  | Pint32 -> "caml_int32_ops"
881  | Pint64 -> "caml_int64_ops"
882
883let alloc_header_boxed_int bi =
884  match bi with
885    Pnativeint -> alloc_boxedintnat_header
886  | Pint32 -> alloc_boxedint32_header
887  | Pint64 -> alloc_boxedint64_header
888
889let box_int dbg bi arg =
890  match arg with
891    Cconst_int n ->
892      transl_structured_constant (box_int_constant bi (Nativeint.of_int n))
893  | Cconst_natint n ->
894      transl_structured_constant (box_int_constant bi n)
895  | _ ->
896      let arg' =
897        if bi = Pint32 && size_int = 8 && big_endian
898        then Cop(Clsl, [arg; Cconst_int 32], dbg)
899        else arg in
900      Cop(Calloc, [alloc_header_boxed_int bi dbg;
901                   Cconst_symbol(operations_boxed_int bi);
902                   arg'], dbg)
903
904let split_int64_for_32bit_target arg dbg =
905  bind "split_int64" arg (fun arg ->
906    let first = Cop (Cadda, [Cconst_int size_int; arg], dbg) in
907    let second = Cop (Cadda, [Cconst_int (2 * size_int); arg], dbg) in
908    Ctuple [Cop (Cload (Thirtytwo_unsigned, Mutable), [first], dbg);
909            Cop (Cload (Thirtytwo_unsigned, Mutable), [second], dbg)])
910
911let rec unbox_int bi arg dbg =
912  match arg with
913    Cop(Calloc, [_hdr; _ops; Cop(Clsl, [contents; Cconst_int 32], dbg')], dbg)
914    when bi = Pint32 && size_int = 8 && big_endian ->
915      (* Force sign-extension of low 32 bits *)
916      Cop(Casr, [Cop(Clsl, [contents; Cconst_int 32], dbg'); Cconst_int 32],
917        dbg)
918  | Cop(Calloc, [_hdr; _ops; contents], dbg)
919    when bi = Pint32 && size_int = 8 && not big_endian ->
920      (* Force sign-extension of low 32 bits *)
921      Cop(Casr, [Cop(Clsl, [contents; Cconst_int 32], dbg); Cconst_int 32], dbg)
922  | Cop(Calloc, [_hdr; _ops; contents], _dbg) ->
923      contents
924  | Clet(id, exp, body) -> Clet(id, exp, unbox_int bi body dbg)
925  | Cifthenelse(cond, e1, e2) ->
926      Cifthenelse(cond, unbox_int bi e1 dbg, unbox_int bi e2 dbg)
927  | Csequence(e1, e2) -> Csequence(e1, unbox_int bi e2 dbg)
928  | Cswitch(e, tbl, el, dbg) ->
929      Cswitch(e, tbl, Array.map (fun e -> unbox_int bi e dbg) el, dbg)
930  | Ccatch(rec_flag, handlers, body) ->
931      map_ccatch (fun e -> unbox_int bi e dbg) rec_flag handlers body
932  | Ctrywith(e1, id, e2) ->
933      Ctrywith(unbox_int bi e1 dbg, id, unbox_int bi e2 dbg)
934  | _ ->
935      if size_int = 4 && bi = Pint64 then
936        split_int64_for_32bit_target arg dbg
937      else
938        Cop(
939          Cload((if bi = Pint32 then Thirtytwo_signed else Word_int), Mutable),
940          [Cop(Cadda, [arg; Cconst_int size_addr], dbg)], dbg)
941
942let make_unsigned_int bi arg dbg =
943  if bi = Pint32 && size_int = 8
944  then Cop(Cand, [arg; Cconst_natint 0xFFFFFFFFn], dbg)
945  else arg
946
947(* Boxed numbers *)
948
949let equal_unboxed_integer ui1 ui2 =
950  match ui1, ui2 with
951  | Pnativeint, Pnativeint -> true
952  | Pint32, Pint32 -> true
953  | Pint64, Pint64 -> true
954  | _, _ -> false
955
956let equal_boxed_number bn1 bn2 =
957  match bn1, bn2 with
958  | Boxed_float _, Boxed_float _ -> true
959  | Boxed_integer(ui1, _), Boxed_integer(ui2, _) ->
960    equal_unboxed_integer ui1 ui2
961  | _, _ -> false
962
963let box_number bn arg =
964  match bn with
965  | Boxed_float dbg -> box_float dbg arg
966  | Boxed_integer (bi, dbg) -> box_int dbg bi arg
967
968(* Big arrays *)
969
970let bigarray_elt_size = function
971    Pbigarray_unknown -> assert false
972  | Pbigarray_float32 -> 4
973  | Pbigarray_float64 -> 8
974  | Pbigarray_sint8 -> 1
975  | Pbigarray_uint8 -> 1
976  | Pbigarray_sint16 -> 2
977  | Pbigarray_uint16 -> 2
978  | Pbigarray_int32 -> 4
979  | Pbigarray_int64 -> 8
980  | Pbigarray_caml_int -> size_int
981  | Pbigarray_native_int -> size_int
982  | Pbigarray_complex32 -> 8
983  | Pbigarray_complex64 -> 16
984
985(* Produces a pointer to the element of the bigarray [b] on the position
986   [args].  [args] is given as a list of tagged int expressions, one per array
987   dimension. *)
988let bigarray_indexing unsafe elt_kind layout b args dbg =
989  let check_ba_bound bound idx v =
990    Csequence(make_checkbound dbg [bound;idx], v) in
991  (* Validates the given multidimensional offset against the array bounds and
992     transforms it into a one dimensional offset.  The offsets are expressions
993     evaluating to tagged int. *)
994  let rec ba_indexing dim_ofs delta_ofs = function
995    [] -> assert false
996  | [arg] ->
997      if unsafe then arg
998      else
999        bind "idx" arg (fun idx ->
1000          (* Load the untagged int bound for the given dimension *)
1001          let bound =
1002            Cop(Cload (Word_int, Mutable),[field_address b dim_ofs dbg], dbg)
1003          in
1004          let idxn = untag_int idx dbg in
1005          check_ba_bound bound idxn idx)
1006  | arg1 :: argl ->
1007      (* The remainder of the list is transformed into a one dimensional offset
1008         *)
1009      let rem = ba_indexing (dim_ofs + delta_ofs) delta_ofs argl in
1010      (* Load the untagged int bound for the given dimension *)
1011      let bound =
1012        Cop(Cload (Word_int, Mutable), [field_address b dim_ofs dbg], dbg)
1013      in
1014      if unsafe then add_int (mul_int (decr_int rem dbg) bound dbg) arg1 dbg
1015      else
1016        bind "idx" arg1 (fun idx ->
1017          bind "bound" bound (fun bound ->
1018            let idxn = untag_int idx dbg in
1019            (* [offset = rem * (tag_int bound) + idx] *)
1020            let offset =
1021              add_int (mul_int (decr_int rem dbg) bound dbg) idx dbg
1022            in
1023            check_ba_bound bound idxn offset)) in
1024  (* The offset as an expression evaluating to int *)
1025  let offset =
1026    match layout with
1027      Pbigarray_unknown_layout ->
1028        assert false
1029    | Pbigarray_c_layout ->
1030        ba_indexing (4 + List.length args) (-1) (List.rev args)
1031    | Pbigarray_fortran_layout ->
1032        ba_indexing 5 1
1033          (List.map (fun idx -> sub_int idx (Cconst_int 2) dbg) args)
1034  and elt_size =
1035    bigarray_elt_size elt_kind in
1036  (* [array_indexing] can simplify the given expressions *)
1037  array_indexing ~typ:Int (log2 elt_size)
1038                 (Cop(Cload (Word_int, Mutable),
1039                    [field_address b 1 dbg], dbg)) offset dbg
1040
1041let bigarray_word_kind = function
1042    Pbigarray_unknown -> assert false
1043  | Pbigarray_float32 -> Single
1044  | Pbigarray_float64 -> Double
1045  | Pbigarray_sint8 -> Byte_signed
1046  | Pbigarray_uint8 -> Byte_unsigned
1047  | Pbigarray_sint16 -> Sixteen_signed
1048  | Pbigarray_uint16 -> Sixteen_unsigned
1049  | Pbigarray_int32 -> Thirtytwo_signed
1050  | Pbigarray_int64 -> Word_int
1051  | Pbigarray_caml_int -> Word_int
1052  | Pbigarray_native_int -> Word_int
1053  | Pbigarray_complex32 -> Single
1054  | Pbigarray_complex64 -> Double
1055
1056let bigarray_get unsafe elt_kind layout b args dbg =
1057  bind "ba" b (fun b ->
1058    match elt_kind with
1059      Pbigarray_complex32 | Pbigarray_complex64 ->
1060        let kind = bigarray_word_kind elt_kind in
1061        let sz = bigarray_elt_size elt_kind / 2 in
1062        bind "addr" (bigarray_indexing unsafe elt_kind layout b args dbg)
1063          (fun addr ->
1064          box_complex dbg
1065            (Cop(Cload (kind, Mutable), [addr], dbg))
1066            (Cop(Cload (kind, Mutable),
1067              [Cop(Cadda, [addr; Cconst_int sz], dbg)], dbg)))
1068    | _ ->
1069        Cop(Cload (bigarray_word_kind elt_kind, Mutable),
1070            [bigarray_indexing unsafe elt_kind layout b args dbg],
1071            dbg))
1072
1073let bigarray_set unsafe elt_kind layout b args newval dbg =
1074  bind "ba" b (fun b ->
1075    match elt_kind with
1076      Pbigarray_complex32 | Pbigarray_complex64 ->
1077        let kind = bigarray_word_kind elt_kind in
1078        let sz = bigarray_elt_size elt_kind / 2 in
1079        bind "newval" newval (fun newv ->
1080        bind "addr" (bigarray_indexing unsafe elt_kind layout b args dbg)
1081          (fun addr ->
1082          Csequence(
1083            Cop(Cstore (kind, Assignment), [addr; complex_re newv dbg], dbg),
1084            Cop(Cstore (kind, Assignment),
1085                [Cop(Cadda, [addr; Cconst_int sz], dbg); complex_im newv dbg],
1086                dbg))))
1087    | _ ->
1088        Cop(Cstore (bigarray_word_kind elt_kind, Assignment),
1089            [bigarray_indexing unsafe elt_kind layout b args dbg; newval],
1090            dbg))
1091
1092let unaligned_load_16 ptr idx dbg =
1093  if Arch.allow_unaligned_access
1094  then Cop(Cload (Sixteen_unsigned, Mutable), [add_int ptr idx dbg], dbg)
1095  else
1096    let v1 = Cop(Cload (Byte_unsigned, Mutable), [add_int ptr idx dbg], dbg) in
1097    let v2 = Cop(Cload (Byte_unsigned, Mutable),
1098                 [add_int (add_int ptr idx dbg) (Cconst_int 1) dbg], dbg) in
1099    let b1, b2 = if Arch.big_endian then v1, v2 else v2, v1 in
1100    Cop(Cor, [lsl_int b1 (Cconst_int 8) dbg; b2], dbg)
1101
1102let unaligned_set_16 ptr idx newval dbg =
1103  if Arch.allow_unaligned_access
1104  then
1105    Cop(Cstore (Sixteen_unsigned, Assignment),
1106      [add_int ptr idx dbg; newval], dbg)
1107  else
1108    let v1 =
1109      Cop(Cand, [Cop(Clsr, [newval; Cconst_int 8], dbg); Cconst_int 0xFF], dbg)
1110    in
1111    let v2 = Cop(Cand, [newval; Cconst_int 0xFF], dbg) in
1112    let b1, b2 = if Arch.big_endian then v1, v2 else v2, v1 in
1113    Csequence(
1114        Cop(Cstore (Byte_unsigned, Assignment), [add_int ptr idx dbg; b1], dbg),
1115        Cop(Cstore (Byte_unsigned, Assignment),
1116            [add_int (add_int ptr idx dbg) (Cconst_int 1) dbg; b2], dbg))
1117
1118let unaligned_load_32 ptr idx dbg =
1119  if Arch.allow_unaligned_access
1120  then Cop(Cload (Thirtytwo_unsigned, Mutable), [add_int ptr idx dbg], dbg)
1121  else
1122    let v1 = Cop(Cload (Byte_unsigned, Mutable), [add_int ptr idx dbg], dbg) in
1123    let v2 = Cop(Cload (Byte_unsigned, Mutable),
1124                 [add_int (add_int ptr idx dbg) (Cconst_int 1) dbg], dbg) in
1125    let v3 = Cop(Cload (Byte_unsigned, Mutable),
1126                 [add_int (add_int ptr idx dbg) (Cconst_int 2) dbg], dbg) in
1127    let v4 = Cop(Cload (Byte_unsigned, Mutable),
1128                 [add_int (add_int ptr idx dbg) (Cconst_int 3) dbg], dbg) in
1129    let b1, b2, b3, b4 =
1130      if Arch.big_endian
1131      then v1, v2, v3, v4
1132      else v4, v3, v2, v1 in
1133    Cop(Cor,
1134      [Cop(Cor, [lsl_int b1 (Cconst_int 24) dbg;
1135         lsl_int b2 (Cconst_int 16) dbg], dbg);
1136       Cop(Cor, [lsl_int b3 (Cconst_int 8) dbg; b4], dbg)],
1137      dbg)
1138
1139let unaligned_set_32 ptr idx newval dbg =
1140  if Arch.allow_unaligned_access
1141  then
1142    Cop(Cstore (Thirtytwo_unsigned, Assignment), [add_int ptr idx dbg; newval],
1143      dbg)
1144  else
1145    let v1 =
1146      Cop(Cand, [Cop(Clsr, [newval; Cconst_int 24], dbg); Cconst_int 0xFF], dbg)
1147    in
1148    let v2 =
1149      Cop(Cand, [Cop(Clsr, [newval; Cconst_int 16], dbg); Cconst_int 0xFF], dbg)
1150    in
1151    let v3 =
1152      Cop(Cand, [Cop(Clsr, [newval; Cconst_int 8], dbg); Cconst_int 0xFF], dbg)
1153    in
1154    let v4 = Cop(Cand, [newval; Cconst_int 0xFF], dbg) in
1155    let b1, b2, b3, b4 =
1156      if Arch.big_endian
1157      then v1, v2, v3, v4
1158      else v4, v3, v2, v1 in
1159    Csequence(
1160        Csequence(
1161            Cop(Cstore (Byte_unsigned, Assignment),
1162                [add_int ptr idx dbg; b1], dbg),
1163            Cop(Cstore (Byte_unsigned, Assignment),
1164                [add_int (add_int ptr idx dbg) (Cconst_int 1) dbg; b2], dbg)),
1165        Csequence(
1166            Cop(Cstore (Byte_unsigned, Assignment),
1167                [add_int (add_int ptr idx dbg) (Cconst_int 2) dbg; b3], dbg),
1168            Cop(Cstore (Byte_unsigned, Assignment),
1169                [add_int (add_int ptr idx dbg) (Cconst_int 3) dbg; b4], dbg)))
1170
1171let unaligned_load_64 ptr idx dbg =
1172  assert(size_int = 8);
1173  if Arch.allow_unaligned_access
1174  then Cop(Cload (Word_int, Mutable), [add_int ptr idx dbg], dbg)
1175  else
1176    let v1 = Cop(Cload (Byte_unsigned, Mutable), [add_int ptr idx dbg], dbg) in
1177    let v2 = Cop(Cload (Byte_unsigned, Mutable),
1178                 [add_int (add_int ptr idx dbg) (Cconst_int 1) dbg], dbg) in
1179    let v3 = Cop(Cload (Byte_unsigned, Mutable),
1180                 [add_int (add_int ptr idx dbg) (Cconst_int 2) dbg], dbg) in
1181    let v4 = Cop(Cload (Byte_unsigned, Mutable),
1182                 [add_int (add_int ptr idx dbg) (Cconst_int 3) dbg], dbg) in
1183    let v5 = Cop(Cload (Byte_unsigned, Mutable),
1184                 [add_int (add_int ptr idx dbg) (Cconst_int 4) dbg], dbg) in
1185    let v6 = Cop(Cload (Byte_unsigned, Mutable),
1186                 [add_int (add_int ptr idx dbg) (Cconst_int 5) dbg], dbg) in
1187    let v7 = Cop(Cload (Byte_unsigned, Mutable),
1188                 [add_int (add_int ptr idx dbg) (Cconst_int 6) dbg], dbg) in
1189    let v8 = Cop(Cload (Byte_unsigned, Mutable),
1190                 [add_int (add_int ptr idx dbg) (Cconst_int 7) dbg], dbg) in
1191    let b1, b2, b3, b4, b5, b6, b7, b8 =
1192      if Arch.big_endian
1193      then v1, v2, v3, v4, v5, v6, v7, v8
1194      else v8, v7, v6, v5, v4, v3, v2, v1 in
1195    Cop(Cor,
1196        [Cop(Cor,
1197             [Cop(Cor, [lsl_int b1 (Cconst_int (8*7)) dbg;
1198                        lsl_int b2 (Cconst_int (8*6)) dbg], dbg);
1199              Cop(Cor, [lsl_int b3 (Cconst_int (8*5)) dbg;
1200                        lsl_int b4 (Cconst_int (8*4)) dbg], dbg)],
1201             dbg);
1202         Cop(Cor,
1203             [Cop(Cor, [lsl_int b5 (Cconst_int (8*3)) dbg;
1204                        lsl_int b6 (Cconst_int (8*2)) dbg], dbg);
1205              Cop(Cor, [lsl_int b7 (Cconst_int 8) dbg;
1206                        b8], dbg)],
1207             dbg)], dbg)
1208
1209let unaligned_set_64 ptr idx newval dbg =
1210  assert(size_int = 8);
1211  if Arch.allow_unaligned_access
1212  then Cop(Cstore (Word_int, Assignment), [add_int ptr idx dbg; newval], dbg)
1213  else
1214    let v1 =
1215      Cop(Cand, [Cop(Clsr, [newval; Cconst_int (8*7)], dbg); Cconst_int 0xFF],
1216        dbg)
1217    in
1218    let v2 =
1219      Cop(Cand, [Cop(Clsr, [newval; Cconst_int (8*6)], dbg); Cconst_int 0xFF],
1220        dbg)
1221    in
1222    let v3 =
1223      Cop(Cand, [Cop(Clsr, [newval; Cconst_int (8*5)], dbg); Cconst_int 0xFF],
1224        dbg)
1225    in
1226    let v4 =
1227      Cop(Cand, [Cop(Clsr, [newval; Cconst_int (8*4)], dbg); Cconst_int 0xFF],
1228        dbg)
1229    in
1230    let v5 =
1231      Cop(Cand, [Cop(Clsr, [newval; Cconst_int (8*3)], dbg); Cconst_int 0xFF],
1232        dbg)
1233    in
1234    let v6 =
1235      Cop(Cand, [Cop(Clsr, [newval; Cconst_int (8*2)], dbg); Cconst_int 0xFF],
1236        dbg)
1237    in
1238    let v7 =
1239      Cop(Cand, [Cop(Clsr, [newval; Cconst_int 8], dbg); Cconst_int 0xFF],
1240        dbg)
1241    in
1242    let v8 = Cop(Cand, [newval; Cconst_int 0xFF], dbg) in
1243    let b1, b2, b3, b4, b5, b6, b7, b8 =
1244      if Arch.big_endian
1245      then v1, v2, v3, v4, v5, v6, v7, v8
1246      else v8, v7, v6, v5, v4, v3, v2, v1 in
1247    Csequence(
1248        Csequence(
1249            Csequence(
1250                Cop(Cstore (Byte_unsigned, Assignment),
1251                    [add_int ptr idx dbg; b1],
1252                    dbg),
1253                Cop(Cstore (Byte_unsigned, Assignment),
1254                    [add_int (add_int ptr idx dbg) (Cconst_int 1) dbg; b2],
1255                    dbg)),
1256            Csequence(
1257                Cop(Cstore (Byte_unsigned, Assignment),
1258                    [add_int (add_int ptr idx dbg) (Cconst_int 2) dbg; b3],
1259                    dbg),
1260                Cop(Cstore (Byte_unsigned, Assignment),
1261                    [add_int (add_int ptr idx dbg) (Cconst_int 3) dbg; b4],
1262                    dbg))),
1263        Csequence(
1264            Csequence(
1265                Cop(Cstore (Byte_unsigned, Assignment),
1266                    [add_int (add_int ptr idx dbg) (Cconst_int 4) dbg; b5],
1267                    dbg),
1268                Cop(Cstore (Byte_unsigned, Assignment),
1269                    [add_int (add_int ptr idx dbg) (Cconst_int 5) dbg; b6],
1270                    dbg)),
1271            Csequence(
1272                Cop(Cstore (Byte_unsigned, Assignment),
1273                    [add_int (add_int ptr idx dbg) (Cconst_int 6) dbg; b7],
1274                    dbg),
1275                Cop(Cstore (Byte_unsigned, Assignment),
1276                    [add_int (add_int ptr idx dbg) (Cconst_int 7) dbg; b8],
1277                    dbg))))
1278
1279let max_or_zero a dbg =
1280  bind "size" a (fun a ->
1281    (* equivalent to
1282       Cifthenelse(Cop(Ccmpi Cle, [a; Cconst_int 0]), Cconst_int 0, a)
1283
1284       if a is positive, sign is 0 hence sign_negation is full of 1
1285                         so sign_negation&a = a
1286       if a is negative, sign is full of 1 hence sign_negation is 0
1287                         so sign_negation&a = 0 *)
1288    let sign = Cop(Casr, [a; Cconst_int (size_int * 8 - 1)], dbg) in
1289    let sign_negation = Cop(Cxor, [sign; Cconst_int (-1)], dbg) in
1290    Cop(Cand, [sign_negation; a], dbg))
1291
1292let check_bound unsafe dbg a1 a2 k =
1293  if unsafe then k
1294  else Csequence(make_checkbound dbg [max_or_zero a1 dbg; a2], k)
1295
1296(* Simplification of some primitives into C calls *)
1297
1298let default_prim name =
1299  Primitive.simple ~name ~arity:0(*ignored*) ~alloc:true
1300
1301let simplif_primitive_32bits = function
1302    Pbintofint Pint64 -> Pccall (default_prim "caml_int64_of_int")
1303  | Pintofbint Pint64 -> Pccall (default_prim "caml_int64_to_int")
1304  | Pcvtbint(Pint32, Pint64) -> Pccall (default_prim "caml_int64_of_int32")
1305  | Pcvtbint(Pint64, Pint32) -> Pccall (default_prim "caml_int64_to_int32")
1306  | Pcvtbint(Pnativeint, Pint64) ->
1307      Pccall (default_prim "caml_int64_of_nativeint")
1308  | Pcvtbint(Pint64, Pnativeint) ->
1309      Pccall (default_prim "caml_int64_to_nativeint")
1310  | Pnegbint Pint64 -> Pccall (default_prim "caml_int64_neg")
1311  | Paddbint Pint64 -> Pccall (default_prim "caml_int64_add")
1312  | Psubbint Pint64 -> Pccall (default_prim "caml_int64_sub")
1313  | Pmulbint Pint64 -> Pccall (default_prim "caml_int64_mul")
1314  | Pdivbint {size=Pint64} -> Pccall (default_prim "caml_int64_div")
1315  | Pmodbint {size=Pint64} -> Pccall (default_prim "caml_int64_mod")
1316  | Pandbint Pint64 -> Pccall (default_prim "caml_int64_and")
1317  | Porbint Pint64 ->  Pccall (default_prim "caml_int64_or")
1318  | Pxorbint Pint64 -> Pccall (default_prim "caml_int64_xor")
1319  | Plslbint Pint64 -> Pccall (default_prim "caml_int64_shift_left")
1320  | Plsrbint Pint64 -> Pccall (default_prim "caml_int64_shift_right_unsigned")
1321  | Pasrbint Pint64 -> Pccall (default_prim "caml_int64_shift_right")
1322  | Pbintcomp(Pint64, Lambda.Ceq) -> Pccall (default_prim "caml_equal")
1323  | Pbintcomp(Pint64, Lambda.Cneq) -> Pccall (default_prim "caml_notequal")
1324  | Pbintcomp(Pint64, Lambda.Clt) -> Pccall (default_prim "caml_lessthan")
1325  | Pbintcomp(Pint64, Lambda.Cgt) -> Pccall (default_prim "caml_greaterthan")
1326  | Pbintcomp(Pint64, Lambda.Cle) -> Pccall (default_prim "caml_lessequal")
1327  | Pbintcomp(Pint64, Lambda.Cge) -> Pccall (default_prim "caml_greaterequal")
1328  | Pbigarrayref(_unsafe, n, Pbigarray_int64, _layout) ->
1329      Pccall (default_prim ("caml_ba_get_" ^ string_of_int n))
1330  | Pbigarrayset(_unsafe, n, Pbigarray_int64, _layout) ->
1331      Pccall (default_prim ("caml_ba_set_" ^ string_of_int n))
1332  | Pstring_load_64(_) -> Pccall (default_prim "caml_string_get64")
1333  | Pstring_set_64(_) -> Pccall (default_prim "caml_string_set64")
1334  | Pbigstring_load_64(_) -> Pccall (default_prim "caml_ba_uint8_get64")
1335  | Pbigstring_set_64(_) -> Pccall (default_prim "caml_ba_uint8_set64")
1336  | Pbbswap Pint64 -> Pccall (default_prim "caml_int64_bswap")
1337  | p -> p
1338
1339let simplif_primitive p =
1340  match p with
1341  | Pduprecord _ ->
1342      Pccall (default_prim "caml_obj_dup")
1343  | Pbigarrayref(_unsafe, n, Pbigarray_unknown, _layout) ->
1344      Pccall (default_prim ("caml_ba_get_" ^ string_of_int n))
1345  | Pbigarrayset(_unsafe, n, Pbigarray_unknown, _layout) ->
1346      Pccall (default_prim ("caml_ba_set_" ^ string_of_int n))
1347  | Pbigarrayref(_unsafe, n, _kind, Pbigarray_unknown_layout) ->
1348      Pccall (default_prim ("caml_ba_get_" ^ string_of_int n))
1349  | Pbigarrayset(_unsafe, n, _kind, Pbigarray_unknown_layout) ->
1350      Pccall (default_prim ("caml_ba_set_" ^ string_of_int n))
1351  | p ->
1352      if size_int = 8 then p else simplif_primitive_32bits p
1353
1354(* Build switchers both for constants and blocks *)
1355
1356let transl_isout h arg dbg = tag_int (Cop(Ccmpa Clt, [h ; arg], dbg)) dbg
1357
1358(* Build an actual switch (ie jump table) *)
1359
1360let make_switch arg cases actions dbg =
1361  let is_const = function
1362    (* Constant integers loaded from a table should end in 1,
1363       so that Cload never produces untagged integers *)
1364    | Cconst_int n
1365    | Cconst_pointer n -> (n land 1) = 1
1366    | Cconst_natint n
1367    | Cconst_natpointer n -> (Nativeint.(to_int (logand n one) = 1))
1368    | Cconst_symbol _ -> true
1369    | _ -> false in
1370  if Array.for_all is_const actions then
1371    let to_data_item = function
1372      | Cconst_int n
1373      | Cconst_pointer n -> Cint (Nativeint.of_int n)
1374      | Cconst_natint n
1375      | Cconst_natpointer n -> Cint n
1376      | Cconst_symbol s -> Csymbol_address s
1377      | _ -> assert false in
1378    let const_actions = Array.map to_data_item actions in
1379    let table = Compilenv.new_const_symbol () in
1380    add_cmm_constant (Const_table ((table, Not_global),
1381        Array.to_list (Array.map (fun act ->
1382          const_actions.(act)) cases)));
1383    addr_array_ref (Cconst_symbol table) (tag_int arg dbg) dbg
1384  else
1385    Cswitch (arg,cases,actions,dbg)
1386
1387module SArgBlocks =
1388struct
1389  type primitive = operation
1390
1391  let eqint = Ccmpi Ceq
1392  let neint = Ccmpi Cne
1393  let leint = Ccmpi Cle
1394  let ltint = Ccmpi Clt
1395  let geint = Ccmpi Cge
1396  let gtint = Ccmpi Cgt
1397
1398  type act = expression
1399
1400  let make_const i =  Cconst_int i
1401  (* CR mshinwell: fix debuginfo *)
1402  let make_prim p args = Cop (p,args, Debuginfo.none)
1403  let make_offset arg n = add_const arg n Debuginfo.none
1404  let make_isout h arg = Cop (Ccmpa Clt, [h ; arg], Debuginfo.none)
1405  let make_isin h arg = Cop (Ccmpa Cge, [h ; arg], Debuginfo.none)
1406  let make_if cond ifso ifnot = Cifthenelse (cond, ifso, ifnot)
1407  let make_switch arg cases actions =
1408    make_switch arg cases actions Debuginfo.none
1409  let bind arg body = bind "switcher" arg body
1410
1411  let make_catch handler = match handler with
1412  | Cexit (i,[]) -> i,fun e -> e
1413  | _ ->
1414      let i = next_raise_count () in
1415(*
1416      Printf.eprintf  "SHARE CMM: %i\n" i ;
1417      Printcmm.expression Format.str_formatter handler ;
1418      Printf.eprintf "%s\n" (Format.flush_str_formatter ()) ;
1419*)
1420      i,
1421      (fun body -> match body with
1422      | Cexit (j,_) ->
1423          if i=j then handler
1424          else body
1425      | _ ->  ccatch (i,[],body,handler))
1426
1427  let make_exit i = Cexit (i,[])
1428
1429end
1430
1431(* cmm store, as sharing as normally been detected in previous
1432   phases, we only share exits *)
1433module StoreExp =
1434  Switch.Store
1435    (struct
1436      type t = expression
1437      type key = int
1438      let make_key = function
1439        | Cexit (i,[]) -> Some i
1440        | _ -> None
1441    end)
1442
1443module SwitcherBlocks = Switch.Make(SArgBlocks)
1444
1445(* Int switcher, arg in [low..high],
1446   cases is list of individual cases, and is sorted by first component *)
1447
1448let transl_int_switch arg low high cases default = match cases with
1449| [] -> assert false
1450| _::_ ->
1451    let store = StoreExp.mk_store () in
1452    assert (store.Switch.act_store default = 0) ;
1453    let cases =
1454      List.map
1455        (fun (i,act) -> i,store.Switch.act_store act)
1456        cases in
1457    let rec inters plow phigh pact = function
1458      | [] ->
1459          if phigh = high then [plow,phigh,pact]
1460          else [(plow,phigh,pact); (phigh+1,high,0) ]
1461      | (i,act)::rem ->
1462          if i = phigh+1 then
1463            if pact = act then
1464              inters plow i pact rem
1465            else
1466              (plow,phigh,pact)::inters i i act rem
1467          else (* insert default *)
1468            if pact = 0 then
1469              if act = 0 then
1470                inters plow i 0 rem
1471              else
1472                (plow,i-1,pact)::
1473                inters i i act rem
1474            else (* pact <> 0 *)
1475              (plow,phigh,pact)::
1476              begin
1477                if act = 0 then inters (phigh+1) i 0 rem
1478                else (phigh+1,i-1,0)::inters i i act rem
1479              end in
1480    let inters = match cases with
1481    | [] -> assert false
1482    | (k0,act0)::rem ->
1483        if k0 = low then inters k0 k0 act0 rem
1484        else inters low (k0-1) 0 cases in
1485    bind "switcher" arg
1486      (fun a ->
1487        SwitcherBlocks.zyva
1488          (low,high)
1489          a
1490          (Array.of_list inters) store)
1491
1492
1493(* Auxiliary functions for optimizing "let" of boxed numbers (floats and
1494   boxed integers *)
1495
1496type unboxed_number_kind =
1497    No_unboxing
1498  | Boxed of boxed_number * bool (* true: boxed form available at no cost *)
1499  | No_result (* expression never returns a result *)
1500
1501let unboxed_number_kind_of_unbox dbg = function
1502  | Same_as_ocaml_repr -> No_unboxing
1503  | Unboxed_float -> Boxed (Boxed_float dbg, false)
1504  | Unboxed_integer bi -> Boxed (Boxed_integer (bi, dbg), false)
1505  | Untagged_int -> No_unboxing
1506
1507let rec is_unboxed_number ~strict env e =
1508  (* Given unboxed_number_kind from two branches of the code, returns the
1509     resulting unboxed_number_kind.
1510
1511     If [strict=false], one knows that the type of the expression
1512     is an unboxable number, and we decide to return an unboxed value
1513     if this indeed eliminates at least one allocation.
1514
1515     If [strict=true], we need to ensure that all possible branches
1516     return an unboxable number (of the same kind).  This could not
1517     be the case in presence of GADTs.
1518 *)
1519  let join k1 e =
1520    match k1, is_unboxed_number ~strict env e with
1521    | Boxed (b1, c1), Boxed (b2, c2) when equal_boxed_number b1 b2 ->
1522        Boxed (b1, c1 && c2)
1523    | No_result, k | k, No_result ->
1524        k (* if a branch never returns, it is safe to unbox it *)
1525    | No_unboxing, k | k, No_unboxing when not strict ->
1526        k
1527    | _, _ -> No_unboxing
1528  in
1529  match e with
1530  | Uvar id ->
1531      begin match is_unboxed_id id env with
1532      | None -> No_unboxing
1533      | Some (_, bn) -> Boxed (bn, false)
1534      end
1535
1536  | Uconst(Uconst_ref(_, Some (Uconst_float _))) ->
1537      Boxed (Boxed_float Debuginfo.none, true)
1538  | Uconst(Uconst_ref(_, Some (Uconst_int32 _))) ->
1539      Boxed (Boxed_integer (Pint32, Debuginfo.none), true)
1540  | Uconst(Uconst_ref(_, Some (Uconst_int64 _))) ->
1541      Boxed (Boxed_integer (Pint64, Debuginfo.none), true)
1542  | Uconst(Uconst_ref(_, Some (Uconst_nativeint _))) ->
1543      Boxed (Boxed_integer (Pnativeint, Debuginfo.none), true)
1544  | Uprim(p, _, dbg) ->
1545      begin match simplif_primitive p with
1546        | Pccall p -> unboxed_number_kind_of_unbox dbg p.prim_native_repr_res
1547        | Pfloatfield _
1548        | Pfloatofint
1549        | Pnegfloat
1550        | Pabsfloat
1551        | Paddfloat
1552        | Psubfloat
1553        | Pmulfloat
1554        | Pdivfloat
1555        | Parrayrefu Pfloatarray
1556        | Parrayrefs Pfloatarray -> Boxed (Boxed_float dbg, false)
1557        | Pbintofint bi
1558        | Pcvtbint(_, bi)
1559        | Pnegbint bi
1560        | Paddbint bi
1561        | Psubbint bi
1562        | Pmulbint bi
1563        | Pdivbint {size=bi}
1564        | Pmodbint {size=bi}
1565        | Pandbint bi
1566        | Porbint bi
1567        | Pxorbint bi
1568        | Plslbint bi
1569        | Plsrbint bi
1570        | Pasrbint bi
1571        | Pbbswap bi -> Boxed (Boxed_integer (bi, dbg), false)
1572        | Pbigarrayref(_, _, (Pbigarray_float32 | Pbigarray_float64), _) ->
1573            Boxed (Boxed_float dbg, false)
1574        | Pbigarrayref(_, _, Pbigarray_int32, _) ->
1575            Boxed (Boxed_integer (Pint32, dbg), false)
1576        | Pbigarrayref(_, _, Pbigarray_int64, _) ->
1577            Boxed (Boxed_integer (Pint64, dbg), false)
1578        | Pbigarrayref(_, _, Pbigarray_native_int,_) ->
1579            Boxed (Boxed_integer (Pnativeint, dbg), false)
1580        | Pstring_load_32(_) -> Boxed (Boxed_integer (Pint32, dbg), false)
1581        | Pstring_load_64(_) -> Boxed (Boxed_integer (Pint64, dbg), false)
1582        | Pbigstring_load_32(_) -> Boxed (Boxed_integer (Pint32, dbg), false)
1583        | Pbigstring_load_64(_) -> Boxed (Boxed_integer (Pint64, dbg), false)
1584        | Praise _ -> No_result
1585        | _ -> No_unboxing
1586      end
1587  | Ulet (_, _, _, _, e) | Uletrec (_, e) | Usequence (_, e) ->
1588      is_unboxed_number ~strict env e
1589  | Uswitch (_, switch) ->
1590      let k = Array.fold_left join No_result switch.us_actions_consts in
1591      Array.fold_left join k switch.us_actions_blocks
1592  | Ustringswitch (_, actions, default_opt) ->
1593      let k = List.fold_left (fun k (_, e) -> join k e) No_result actions in
1594      begin match default_opt with
1595        None -> k
1596      | Some default -> join k default
1597      end
1598  | Ustaticfail _ -> No_result
1599  | Uifthenelse (_, e1, e2) | Ucatch (_, _, e1, e2) | Utrywith (e1, _, e2) ->
1600      join (is_unboxed_number ~strict env e1) e2
1601  | _ -> No_unboxing
1602
1603(* Helper for compilation of initialization and assignment operations *)
1604
1605type assignment_kind = Caml_modify | Caml_initialize | Simple
1606
1607let assignment_kind ptr init =
1608  match init, ptr with
1609  | Assignment, Pointer -> Caml_modify
1610  | Heap_initialization, Pointer -> Caml_initialize
1611  | Assignment, Immediate
1612  | Heap_initialization, Immediate
1613  | Root_initialization, (Immediate | Pointer) -> Simple
1614
1615(* Translate an expression *)
1616
1617let functions = (Queue.create() : ufunction Queue.t)
1618
1619let strmatch_compile =
1620  let module S =
1621    Strmatch.Make
1622      (struct
1623        let string_block_length ptr = get_size ptr Debuginfo.none
1624        let transl_switch = transl_int_switch
1625      end) in
1626  S.compile
1627
1628let rec transl env e =
1629  match e with
1630    Uvar id ->
1631      begin match is_unboxed_id id env with
1632      | None -> Cvar id
1633      | Some (unboxed_id, bn) -> box_number bn (Cvar unboxed_id)
1634      end
1635  | Uconst sc ->
1636      transl_constant sc
1637  | Uclosure(fundecls, []) ->
1638      let lbl = Compilenv.new_const_symbol() in
1639      add_cmm_constant (
1640        Const_closure ((lbl, Not_global), fundecls, []));
1641      List.iter (fun f -> Queue.add f functions) fundecls;
1642      Cconst_symbol lbl
1643  | Uclosure(fundecls, clos_vars) ->
1644      let block_size =
1645        fundecls_size fundecls + List.length clos_vars in
1646      let rec transl_fundecls pos = function
1647          [] ->
1648            List.map (transl env) clos_vars
1649        | f :: rem ->
1650            Queue.add f functions;
1651            let header =
1652              if pos = 0
1653              then alloc_closure_header block_size f.dbg
1654              else alloc_infix_header pos f.dbg in
1655            if f.arity = 1 || f.arity = 0 then
1656              header ::
1657              Cconst_symbol f.label ::
1658              int_const f.arity ::
1659              transl_fundecls (pos + 3) rem
1660            else
1661              header ::
1662              Cconst_symbol(curry_function f.arity) ::
1663              int_const f.arity ::
1664              Cconst_symbol f.label ::
1665              transl_fundecls (pos + 4) rem in
1666      Cop(Calloc, transl_fundecls 0 fundecls, Debuginfo.none)
1667  | Uoffset(arg, offset) ->
1668      (* produces a valid Caml value, pointing just after an infix header *)
1669      let ptr = transl env arg in
1670      if offset = 0
1671      then ptr
1672      else Cop(Caddv, [ptr; Cconst_int(offset * size_addr)], Debuginfo.none)
1673  | Udirect_apply(lbl, args, dbg) ->
1674      Cop(Capply typ_val, Cconst_symbol lbl :: List.map (transl env) args, dbg)
1675  | Ugeneric_apply(clos, [arg], dbg) ->
1676      bind "fun" (transl env clos) (fun clos ->
1677        Cop(Capply typ_val, [get_field env clos 0 dbg; transl env arg; clos],
1678          dbg))
1679  | Ugeneric_apply(clos, args, dbg) ->
1680      let arity = List.length args in
1681      let cargs = Cconst_symbol(apply_function arity) ::
1682        List.map (transl env) (args @ [clos]) in
1683      Cop(Capply typ_val, cargs, dbg)
1684  | Usend(kind, met, obj, args, dbg) ->
1685      let call_met obj args clos =
1686        if args = [] then
1687          Cop(Capply typ_val, [get_field env clos 0 dbg; obj; clos], dbg)
1688        else
1689          let arity = List.length args + 1 in
1690          let cargs = Cconst_symbol(apply_function arity) :: obj ::
1691            (List.map (transl env) args) @ [clos] in
1692          Cop(Capply typ_val, cargs, dbg)
1693      in
1694      bind "obj" (transl env obj) (fun obj ->
1695        match kind, args with
1696          Self, _ ->
1697            bind "met" (lookup_label obj (transl env met) dbg)
1698              (call_met obj args)
1699        | Cached, cache :: pos :: args ->
1700            call_cached_method obj
1701              (transl env met) (transl env cache) (transl env pos)
1702              (List.map (transl env) args) dbg
1703        | _ ->
1704            bind "met" (lookup_tag obj (transl env met) dbg)
1705              (call_met obj args))
1706  | Ulet(str, kind, id, exp, body) ->
1707      transl_let env str kind id exp body
1708  | Uletrec(bindings, body) ->
1709      transl_letrec env bindings (transl env body)
1710
1711  (* Primitives *)
1712  | Uprim(prim, args, dbg) ->
1713      begin match (simplif_primitive prim, args) with
1714        (Pgetglobal id, []) ->
1715          Cconst_symbol (Ident.name id)
1716      | (Pmakeblock _, []) ->
1717          assert false
1718      | (Pmakeblock(tag, _mut, _kind), args) ->
1719          make_alloc dbg tag (List.map (transl env) args)
1720      | (Pccall prim, args) ->
1721          transl_ccall env prim args dbg
1722      | (Pduparray (kind, _), [Uprim (Pmakearray (kind', _), args, _dbg)]) ->
1723          (* We arrive here in two cases:
1724             1. When using Closure, all the time.
1725             2. When using Flambda, if a float array longer than
1726             [Translcore.use_dup_for_constant_arrays_bigger_than] turns out
1727             to be non-constant.
1728             If for some reason Flambda fails to lift a constant array we
1729             could in theory also end up here.
1730             Note that [kind] above is unconstrained, but with the current
1731             state of [Translcore], we will in fact only get here with
1732             [Pfloatarray]s. *)
1733          assert (kind = kind');
1734          transl_make_array dbg env kind args
1735      | (Pduparray _, [arg]) ->
1736          let prim_obj_dup =
1737            Primitive.simple ~name:"caml_obj_dup" ~arity:1 ~alloc:true
1738          in
1739          transl_ccall env prim_obj_dup [arg] dbg
1740      | (Pmakearray _, []) ->
1741          transl_structured_constant (Uconst_block(0, []))
1742      | (Pmakearray (kind, _), args) -> transl_make_array dbg env kind args
1743      | (Pbigarrayref(unsafe, _num_dims, elt_kind, layout), arg1 :: argl) ->
1744          let elt =
1745            bigarray_get unsafe elt_kind layout
1746              (transl env arg1) (List.map (transl env) argl) dbg in
1747          begin match elt_kind with
1748            Pbigarray_float32 | Pbigarray_float64 -> box_float dbg elt
1749          | Pbigarray_complex32 | Pbigarray_complex64 -> elt
1750          | Pbigarray_int32 -> box_int dbg Pint32 elt
1751          | Pbigarray_int64 -> box_int dbg Pint64 elt
1752          | Pbigarray_native_int -> box_int dbg Pnativeint elt
1753          | Pbigarray_caml_int -> force_tag_int elt dbg
1754          | _ -> tag_int elt dbg
1755          end
1756      | (Pbigarrayset(unsafe, _num_dims, elt_kind, layout), arg1 :: argl) ->
1757          let (argidx, argnewval) = split_last argl in
1758          return_unit(bigarray_set unsafe elt_kind layout
1759            (transl env arg1)
1760            (List.map (transl env) argidx)
1761            (match elt_kind with
1762              Pbigarray_float32 | Pbigarray_float64 ->
1763                transl_unbox_float dbg env argnewval
1764            | Pbigarray_complex32 | Pbigarray_complex64 -> transl env argnewval
1765            | Pbigarray_int32 -> transl_unbox_int dbg env Pint32 argnewval
1766            | Pbigarray_int64 -> transl_unbox_int dbg env Pint64 argnewval
1767            | Pbigarray_native_int ->
1768                transl_unbox_int dbg env Pnativeint argnewval
1769            | _ -> untag_int (transl env argnewval) dbg)
1770            dbg)
1771      | (Pbigarraydim(n), [b]) ->
1772          let dim_ofs = 4 + n in
1773          tag_int (Cop(Cload (Word_int, Mutable),
1774            [field_address (transl env b) dim_ofs dbg],
1775            dbg)) dbg
1776      | (p, [arg]) ->
1777          transl_prim_1 env p arg dbg
1778      | (p, [arg1; arg2]) ->
1779          transl_prim_2 env p arg1 arg2 dbg
1780      | (p, [arg1; arg2; arg3]) ->
1781          transl_prim_3 env p arg1 arg2 arg3 dbg
1782      | (_, _) ->
1783          fatal_error "Cmmgen.transl:prim"
1784      end
1785
1786  (* Control structures *)
1787  | Uswitch(arg, s) ->
1788      let dbg = Debuginfo.none in
1789      (* As in the bytecode interpreter, only matching against constants
1790         can be checked *)
1791      if Array.length s.us_index_blocks = 0 then
1792        make_switch
1793          (untag_int (transl env arg) dbg)
1794          s.us_index_consts
1795          (Array.map (transl env) s.us_actions_consts)
1796          dbg
1797      else if Array.length s.us_index_consts = 0 then
1798        transl_switch dbg env (get_tag (transl env arg) dbg)
1799          s.us_index_blocks s.us_actions_blocks
1800      else
1801        bind "switch" (transl env arg) (fun arg ->
1802          Cifthenelse(
1803          Cop(Cand, [arg; Cconst_int 1], dbg),
1804          transl_switch dbg env
1805            (untag_int arg dbg) s.us_index_consts s.us_actions_consts,
1806          transl_switch dbg env
1807            (get_tag arg dbg) s.us_index_blocks s.us_actions_blocks))
1808  | Ustringswitch(arg,sw,d) ->
1809      let dbg = Debuginfo.none in
1810      bind "switch" (transl env arg)
1811        (fun arg ->
1812          strmatch_compile dbg arg (Misc.may_map (transl env) d)
1813            (List.map (fun (s,act) -> s,transl env act) sw))
1814  | Ustaticfail (nfail, args) ->
1815      Cexit (nfail, List.map (transl env) args)
1816  | Ucatch(nfail, [], body, handler) ->
1817      make_catch nfail (transl env body) (transl env handler)
1818  | Ucatch(nfail, ids, body, handler) ->
1819      ccatch(nfail, ids, transl env body, transl env handler)
1820  | Utrywith(body, exn, handler) ->
1821      Ctrywith(transl env body, exn, transl env handler)
1822  | Uifthenelse(Uprim(Pnot, [arg], _), ifso, ifnot) ->
1823      transl env (Uifthenelse(arg, ifnot, ifso))
1824  | Uifthenelse(cond, ifso, Ustaticfail (nfail, [])) ->
1825      let dbg = Debuginfo.none in
1826      exit_if_false dbg env cond (transl env ifso) nfail
1827  | Uifthenelse(cond, Ustaticfail (nfail, []), ifnot) ->
1828      let dbg = Debuginfo.none in
1829      exit_if_true dbg env cond nfail (transl env ifnot)
1830  | Uifthenelse(Uprim(Psequand, _, dbg) as cond, ifso, ifnot) ->
1831      let raise_num = next_raise_count () in
1832      make_catch
1833        raise_num
1834        (exit_if_false dbg env cond (transl env ifso) raise_num)
1835        (transl env ifnot)
1836  | Uifthenelse(Uprim(Psequor, _, dbg) as cond, ifso, ifnot) ->
1837      let raise_num = next_raise_count () in
1838      make_catch
1839        raise_num
1840        (exit_if_true dbg env cond raise_num (transl env ifnot))
1841        (transl env ifso)
1842  | Uifthenelse (Uifthenelse (cond, condso, condnot), ifso, ifnot) ->
1843      let dbg = Debuginfo.none in
1844      let num_true = next_raise_count () in
1845      make_catch
1846        num_true
1847        (make_catch2
1848           (fun shared_false ->
1849             if_then_else
1850               (test_bool dbg (transl env cond),
1851                exit_if_true dbg env condso num_true shared_false,
1852                exit_if_true dbg env condnot num_true shared_false))
1853           (transl env ifnot))
1854        (transl env ifso)
1855  | Uifthenelse(cond, ifso, ifnot) ->
1856      let dbg = Debuginfo.none in
1857      if_then_else(test_bool dbg (transl env cond), transl env ifso,
1858        transl env ifnot)
1859  | Usequence(exp1, exp2) ->
1860      Csequence(remove_unit(transl env exp1), transl env exp2)
1861  | Uwhile(cond, body) ->
1862      let dbg = Debuginfo.none in
1863      let raise_num = next_raise_count () in
1864      return_unit
1865        (ccatch
1866           (raise_num, [],
1867            Cloop(exit_if_false dbg env cond
1868                    (remove_unit(transl env body)) raise_num),
1869            Ctuple []))
1870  | Ufor(id, low, high, dir, body) ->
1871      let dbg = Debuginfo.none in
1872      let tst = match dir with Upto -> Cgt   | Downto -> Clt in
1873      let inc = match dir with Upto -> Caddi | Downto -> Csubi in
1874      let raise_num = next_raise_count () in
1875      let id_prev = Ident.rename id in
1876      return_unit
1877        (Clet
1878           (id, transl env low,
1879            bind_nonvar "bound" (transl env high) (fun high ->
1880              ccatch
1881                (raise_num, [],
1882                 Cifthenelse
1883                   (Cop(Ccmpi tst, [Cvar id; high], dbg),
1884                    Cexit (raise_num, []),
1885                    Cloop
1886                      (Csequence
1887                         (remove_unit(transl env body),
1888                         Clet(id_prev, Cvar id,
1889                          Csequence
1890                            (Cassign(id,
1891                               Cop(inc, [Cvar id; Cconst_int 2],
1892                                 dbg)),
1893                             Cifthenelse
1894                               (Cop(Ccmpi Ceq, [Cvar id_prev; high],
1895                                  dbg),
1896                                Cexit (raise_num,[]), Ctuple [])))))),
1897                 Ctuple []))))
1898  | Uassign(id, exp) ->
1899      let dbg = Debuginfo.none in
1900      begin match is_unboxed_id id env with
1901      | None ->
1902          return_unit (Cassign(id, transl env exp))
1903      | Some (unboxed_id, bn) ->
1904          return_unit(Cassign(unboxed_id,
1905            transl_unbox_number dbg env bn exp))
1906      end
1907  | Uunreachable ->
1908      let dbg = Debuginfo.none in
1909      Cop(Cload (Word_int, Mutable), [Cconst_int 0], dbg)
1910
1911and transl_make_array dbg env kind args =
1912  match kind with
1913  | Pgenarray ->
1914      Cop(Cextcall("caml_make_array", typ_val, true, None),
1915          [make_alloc dbg 0 (List.map (transl env) args)], dbg)
1916  | Paddrarray | Pintarray ->
1917      make_alloc dbg 0 (List.map (transl env) args)
1918  | Pfloatarray ->
1919      make_float_alloc dbg Obj.double_array_tag
1920                      (List.map (transl_unbox_float dbg env) args)
1921
1922and transl_ccall env prim args dbg =
1923  let transl_arg native_repr arg =
1924    match native_repr with
1925    | Same_as_ocaml_repr -> transl env arg
1926    | Unboxed_float -> transl_unbox_float dbg env arg
1927    | Unboxed_integer bi -> transl_unbox_int dbg env bi arg
1928    | Untagged_int -> untag_int (transl env arg) dbg
1929  in
1930  let rec transl_args native_repr_args args =
1931    match native_repr_args, args with
1932    | [], args ->
1933        (* We don't require the two lists to be of the same length as
1934           [default_prim] always sets the arity to [0]. *)
1935        List.map (transl env) args
1936    | _, [] -> assert false
1937    | native_repr :: native_repr_args, arg :: args ->
1938        transl_arg native_repr arg :: transl_args native_repr_args args
1939  in
1940  let typ_res, wrap_result =
1941    match prim.prim_native_repr_res with
1942    | Same_as_ocaml_repr -> (typ_val, fun x -> x)
1943    | Unboxed_float -> (typ_float, box_float dbg)
1944    | Unboxed_integer Pint64 when size_int = 4 ->
1945        ([|Int; Int|], box_int dbg Pint64)
1946    | Unboxed_integer bi -> (typ_int, box_int dbg bi)
1947    | Untagged_int -> (typ_int, (fun i -> tag_int i dbg))
1948  in
1949  let args = transl_args prim.prim_native_repr_args args in
1950  wrap_result
1951    (Cop(Cextcall(Primitive.native_name prim,
1952                  typ_res, prim.prim_alloc, None), args, dbg))
1953
1954and transl_prim_1 env p arg dbg =
1955  match p with
1956  (* Generic operations *)
1957    Pidentity | Pbytes_to_string | Pbytes_of_string | Popaque ->
1958      transl env arg
1959  | Pignore ->
1960      return_unit(remove_unit (transl env arg))
1961  (* Heap operations *)
1962  | Pfield n ->
1963      get_field env (transl env arg) n dbg
1964  | Pfloatfield n ->
1965      let ptr = transl env arg in
1966      box_float dbg (
1967        Cop(Cload (Double_u, Mutable),
1968            [if n = 0 then ptr
1969                       else Cop(Cadda, [ptr; Cconst_int(n * size_float)], dbg)],
1970            dbg))
1971  | Pint_as_pointer ->
1972     Cop(Caddi, [transl env arg; Cconst_int (-1)], dbg)
1973     (* always a pointer outside the heap *)
1974  (* Exceptions *)
1975  | Praise _ when not (!Clflags.debug) ->
1976      Cop(Craise Cmm.Raise_notrace, [transl env arg], dbg)
1977  | Praise Lambda.Raise_notrace ->
1978      Cop(Craise Cmm.Raise_notrace, [transl env arg], dbg)
1979  | Praise Lambda.Raise_reraise ->
1980      Cop(Craise Cmm.Raise_withtrace, [transl env arg], dbg)
1981  | Praise Lambda.Raise_regular ->
1982      raise_regular dbg (transl env arg)
1983  (* Integer operations *)
1984  | Pnegint ->
1985      Cop(Csubi, [Cconst_int 2; transl env arg], dbg)
1986  | Pctconst c ->
1987      let const_of_bool b = tag_int (Cconst_int (if b then 1 else 0)) dbg in
1988      begin
1989        match c with
1990        | Big_endian -> const_of_bool Arch.big_endian
1991        | Word_size -> tag_int (Cconst_int (8*Arch.size_int)) dbg
1992        | Int_size -> tag_int (Cconst_int ((8*Arch.size_int) - 1)) dbg
1993        | Max_wosize ->
1994            tag_int (Cconst_int ((1 lsl ((8*Arch.size_int) - 10)) - 1 )) dbg
1995        | Ostype_unix -> const_of_bool (Sys.os_type = "Unix")
1996        | Ostype_win32 -> const_of_bool (Sys.os_type = "Win32")
1997        | Ostype_cygwin -> const_of_bool (Sys.os_type = "Cygwin")
1998        | Backend_type ->
1999            tag_int (Cconst_int 0) dbg (* tag 0 is the same as Native here *)
2000      end
2001  | Poffsetint n ->
2002      if no_overflow_lsl n 1 then
2003        add_const (transl env arg) (n lsl 1) dbg
2004      else
2005        transl_prim_2 env Paddint arg (Uconst (Uconst_int n))
2006                      Debuginfo.none
2007  | Poffsetref n ->
2008      return_unit
2009        (bind "ref" (transl env arg) (fun arg ->
2010          Cop(Cstore (Word_int, Assignment),
2011              [arg;
2012               add_const (Cop(Cload (Word_int, Mutable), [arg], dbg))
2013                 (n lsl 1) dbg],
2014              dbg)))
2015  (* Floating-point operations *)
2016  | Pfloatofint ->
2017      box_float dbg (Cop(Cfloatofint, [untag_int(transl env arg) dbg], dbg))
2018  | Pintoffloat ->
2019     tag_int(Cop(Cintoffloat, [transl_unbox_float dbg env arg], dbg)) dbg
2020  | Pnegfloat ->
2021      box_float dbg (Cop(Cnegf, [transl_unbox_float dbg env arg], dbg))
2022  | Pabsfloat ->
2023      box_float dbg (Cop(Cabsf, [transl_unbox_float dbg env arg], dbg))
2024  (* String operations *)
2025  | Pstringlength | Pbyteslength ->
2026      tag_int(string_length (transl env arg) dbg) dbg
2027  (* Array operations *)
2028  | Parraylength kind ->
2029      let hdr = get_header_without_profinfo (transl env arg) dbg in
2030      begin match kind with
2031        Pgenarray ->
2032          let len =
2033            if wordsize_shift = numfloat_shift then
2034              Cop(Clsr, [hdr; Cconst_int wordsize_shift], dbg)
2035            else
2036              bind "header" hdr (fun hdr ->
2037                Cifthenelse(is_addr_array_hdr hdr dbg,
2038                            Cop(Clsr, [hdr; Cconst_int wordsize_shift], dbg),
2039                            Cop(Clsr, [hdr; Cconst_int numfloat_shift], dbg))) in
2040          Cop(Cor, [len; Cconst_int 1], dbg)
2041      | Paddrarray | Pintarray ->
2042          Cop(Cor, [addr_array_length hdr dbg; Cconst_int 1], dbg)
2043      | Pfloatarray ->
2044          Cop(Cor, [float_array_length hdr dbg; Cconst_int 1], dbg)
2045      end
2046  (* Boolean operations *)
2047  | Pnot ->
2048      Cop(Csubi, [Cconst_int 4; transl env arg], dbg) (* 1 -> 3, 3 -> 1 *)
2049  (* Test integer/block *)
2050  | Pisint ->
2051      tag_int(Cop(Cand, [transl env arg; Cconst_int 1], dbg)) dbg
2052  (* Boxed integers *)
2053  | Pbintofint bi ->
2054      box_int dbg bi (untag_int (transl env arg) dbg)
2055  | Pintofbint bi ->
2056      force_tag_int (transl_unbox_int dbg env bi arg) dbg
2057  | Pcvtbint(bi1, bi2) ->
2058      box_int dbg bi2 (transl_unbox_int dbg env bi1 arg)
2059  | Pnegbint bi ->
2060      box_int dbg bi
2061        (Cop(Csubi, [Cconst_int 0; transl_unbox_int dbg env bi arg], dbg))
2062  | Pbbswap bi ->
2063      let prim = match bi with
2064        | Pnativeint -> "nativeint"
2065        | Pint32 -> "int32"
2066        | Pint64 -> "int64" in
2067      box_int dbg bi (Cop(Cextcall(Printf.sprintf "caml_%s_direct_bswap" prim,
2068                               typ_int, false, None),
2069                      [transl_unbox_int dbg env bi arg],
2070                      dbg))
2071  | Pbswap16 ->
2072      tag_int (Cop(Cextcall("caml_bswap16_direct", typ_int, false, None),
2073                   [untag_int (transl env arg) dbg],
2074                   dbg))
2075              dbg
2076  | prim ->
2077      fatal_errorf "Cmmgen.transl_prim_1: %a" Printlambda.primitive prim
2078
2079and transl_prim_2 env p arg1 arg2 dbg =
2080  match p with
2081  (* Heap operations *)
2082  | Pfield_computed ->
2083      addr_array_ref (transl env arg1) (transl env arg2) dbg
2084  | Psetfield(n, ptr, init) ->
2085      begin match assignment_kind ptr init with
2086      | Caml_modify ->
2087        return_unit(Cop(Cextcall("caml_modify", typ_void, false, None),
2088                        [field_address (transl env arg1) n dbg;
2089                         transl env arg2],
2090                        dbg))
2091      | Caml_initialize ->
2092        return_unit(Cop(Cextcall("caml_initialize", typ_void, false, None),
2093                        [field_address (transl env arg1) n dbg;
2094                         transl env arg2],
2095                        dbg))
2096      | Simple ->
2097        return_unit(set_field (transl env arg1) n (transl env arg2) init dbg)
2098      end
2099  | Psetfloatfield (n, init) ->
2100      let ptr = transl env arg1 in
2101      return_unit(
2102        Cop(Cstore (Double_u, init),
2103            [if n = 0 then ptr
2104                       else Cop(Cadda, [ptr; Cconst_int(n * size_float)], dbg);
2105                   transl_unbox_float dbg env arg2], dbg))
2106
2107  (* Boolean operations *)
2108  | Psequand ->
2109      if_then_else(test_bool dbg (transl env arg1),
2110        transl env arg2, Cconst_int 1)
2111      (* let id = Ident.create "res1" in
2112      Clet(id, transl env arg1,
2113           Cifthenelse(test_bool dbg (Cvar id), transl env arg2, Cvar id)) *)
2114  | Psequor ->
2115      if_then_else(test_bool dbg (transl env arg1),
2116        Cconst_int 3, transl env arg2)
2117
2118  (* Integer operations *)
2119  | Paddint ->
2120      decr_int(add_int (transl env arg1) (transl env arg2) dbg) dbg
2121  | Psubint ->
2122      incr_int(sub_int (transl env arg1) (transl env arg2) dbg) dbg
2123  | Pmulint ->
2124     begin
2125       (* decrementing the non-constant part helps when the multiplication is
2126          followed by an addition;
2127          for example, using this trick compiles (100 * a + 7) into
2128            (+ ( * a 100) -85)
2129          rather than
2130            (+ ( * 200 (>>s a 1)) 15)
2131        *)
2132       match transl env arg1, transl env arg2 with
2133         | Cconst_int _ as c1, c2 ->
2134             incr_int (mul_int (untag_int c1 dbg) (decr_int c2 dbg) dbg) dbg
2135         | c1, c2 ->
2136             incr_int (mul_int (decr_int c1 dbg) (untag_int c2 dbg) dbg) dbg
2137     end
2138  | Pdivint is_safe ->
2139      tag_int(div_int (untag_int(transl env arg1) dbg)
2140        (untag_int(transl env arg2) dbg) is_safe dbg) dbg
2141  | Pmodint is_safe ->
2142      tag_int(mod_int (untag_int(transl env arg1) dbg)
2143        (untag_int(transl env arg2) dbg) is_safe dbg) dbg
2144  | Pandint ->
2145      Cop(Cand, [transl env arg1; transl env arg2], dbg)
2146  | Porint ->
2147      Cop(Cor, [transl env arg1; transl env arg2], dbg)
2148  | Pxorint ->
2149      Cop(Cor, [Cop(Cxor, [ignore_low_bit_int(transl env arg1);
2150                           ignore_low_bit_int(transl env arg2)], dbg);
2151                Cconst_int 1], dbg)
2152  | Plslint ->
2153      incr_int(lsl_int (decr_int(transl env arg1) dbg)
2154        (untag_int(transl env arg2) dbg) dbg) dbg
2155  | Plsrint ->
2156      Cop(Cor, [lsr_int (transl env arg1) (untag_int(transl env arg2) dbg) dbg;
2157                Cconst_int 1], dbg)
2158  | Pasrint ->
2159      Cop(Cor, [asr_int (transl env arg1) (untag_int(transl env arg2) dbg) dbg;
2160                Cconst_int 1], dbg)
2161  | Pintcomp cmp ->
2162      tag_int(Cop(Ccmpi(transl_comparison cmp),
2163                  [transl env arg1; transl env arg2], dbg)) dbg
2164  | Pisout ->
2165      transl_isout (transl env arg1) (transl env arg2) dbg
2166  (* Float operations *)
2167  | Paddfloat ->
2168      box_float dbg (Cop(Caddf,
2169                    [transl_unbox_float dbg env arg1; transl_unbox_float dbg env arg2],
2170                    dbg))
2171  | Psubfloat ->
2172      box_float dbg (Cop(Csubf,
2173                    [transl_unbox_float dbg env arg1; transl_unbox_float dbg env arg2],
2174                    dbg))
2175  | Pmulfloat ->
2176      box_float dbg (Cop(Cmulf,
2177                    [transl_unbox_float dbg env arg1; transl_unbox_float dbg env arg2],
2178                    dbg))
2179  | Pdivfloat ->
2180      box_float dbg (Cop(Cdivf,
2181                    [transl_unbox_float dbg env arg1; transl_unbox_float dbg env arg2],
2182                    dbg))
2183  | Pfloatcomp cmp ->
2184      tag_int(Cop(Ccmpf(transl_comparison cmp),
2185                  [transl_unbox_float dbg env arg1; transl_unbox_float dbg env arg2],
2186                  dbg)) dbg
2187
2188  (* String operations *)
2189  | Pstringrefu | Pbytesrefu ->
2190      tag_int(Cop(Cload (Byte_unsigned, Mutable),
2191                  [add_int (transl env arg1) (untag_int(transl env arg2) dbg)
2192                    dbg],
2193                  dbg)) dbg
2194  | Pstringrefs | Pbytesrefs ->
2195      tag_int
2196        (bind "str" (transl env arg1) (fun str ->
2197          bind "index" (untag_int (transl env arg2) dbg) (fun idx ->
2198            Csequence(
2199              make_checkbound dbg [string_length str dbg; idx],
2200              Cop(Cload (Byte_unsigned, Mutable),
2201                [add_int str idx dbg], dbg))))) dbg
2202
2203  | Pstring_load_16(unsafe) ->
2204     tag_int
2205       (bind "str" (transl env arg1) (fun str ->
2206        bind "index" (untag_int (transl env arg2) dbg) (fun idx ->
2207          check_bound unsafe dbg
2208             (sub_int (string_length str dbg) (Cconst_int 1) dbg)
2209             idx (unaligned_load_16 str idx dbg)))) dbg
2210
2211  | Pbigstring_load_16(unsafe) ->
2212     tag_int
2213       (bind "ba" (transl env arg1) (fun ba ->
2214        bind "index" (untag_int (transl env arg2) dbg) (fun idx ->
2215        bind "ba_data"
2216         (Cop(Cload (Word_int, Mutable), [field_address ba 1 dbg], dbg))
2217         (fun ba_data ->
2218          check_bound unsafe dbg (sub_int (Cop(Cload (Word_int, Mutable),
2219                                               [field_address ba 5 dbg], dbg))
2220                                          (Cconst_int 1) dbg) idx
2221                      (unaligned_load_16 ba_data idx dbg))))) dbg
2222
2223  | Pstring_load_32(unsafe) ->
2224     box_int dbg Pint32
2225       (bind "str" (transl env arg1) (fun str ->
2226        bind "index" (untag_int (transl env arg2) dbg) (fun idx ->
2227          check_bound unsafe dbg
2228            (sub_int (string_length str dbg) (Cconst_int 3) dbg)
2229            idx (unaligned_load_32 str idx dbg))))
2230
2231  | Pbigstring_load_32(unsafe) ->
2232     box_int dbg Pint32
2233       (bind "ba" (transl env arg1) (fun ba ->
2234        bind "index" (untag_int (transl env arg2) dbg) (fun idx ->
2235        bind "ba_data"
2236         (Cop(Cload (Word_int, Mutable), [field_address ba 1 dbg], dbg))
2237         (fun ba_data ->
2238          check_bound unsafe dbg (sub_int (Cop(Cload (Word_int, Mutable),
2239                                               [field_address ba 5 dbg], dbg))
2240                                          (Cconst_int 3) dbg) idx
2241                      (unaligned_load_32 ba_data idx dbg)))))
2242
2243  | Pstring_load_64(unsafe) ->
2244     box_int dbg Pint64
2245       (bind "str" (transl env arg1) (fun str ->
2246        bind "index" (untag_int (transl env arg2) dbg) (fun idx ->
2247          check_bound unsafe dbg
2248            (sub_int (string_length str dbg) (Cconst_int 7) dbg)
2249            idx (unaligned_load_64 str idx dbg))))
2250
2251  | Pbigstring_load_64(unsafe) ->
2252     box_int dbg Pint64
2253       (bind "ba" (transl env arg1) (fun ba ->
2254        bind "index" (untag_int (transl env arg2) dbg) (fun idx ->
2255        bind "ba_data"
2256         (Cop(Cload (Word_int, Mutable), [field_address ba 1 dbg], dbg))
2257         (fun ba_data ->
2258          check_bound unsafe dbg (sub_int (Cop(Cload (Word_int, Mutable),
2259                                               [field_address ba 5 dbg], dbg))
2260                                          (Cconst_int 7) dbg) idx
2261                      (unaligned_load_64 ba_data idx dbg)))))
2262
2263  (* Array operations *)
2264  | Parrayrefu kind ->
2265      begin match kind with
2266        Pgenarray ->
2267          bind "arr" (transl env arg1) (fun arr ->
2268            bind "index" (transl env arg2) (fun idx ->
2269              Cifthenelse(is_addr_array_ptr arr dbg,
2270                          addr_array_ref arr idx dbg,
2271                          float_array_ref dbg arr idx)))
2272      | Paddrarray ->
2273          addr_array_ref (transl env arg1) (transl env arg2) dbg
2274      | Pintarray ->
2275          (* CR mshinwell: for int/addr_array_ref move "dbg" to first arg *)
2276          int_array_ref (transl env arg1) (transl env arg2) dbg
2277      | Pfloatarray ->
2278          float_array_ref dbg (transl env arg1) (transl env arg2)
2279      end
2280  | Parrayrefs kind ->
2281      begin match kind with
2282      | Pgenarray ->
2283          bind "index" (transl env arg2) (fun idx ->
2284          bind "arr" (transl env arg1) (fun arr ->
2285          bind "header" (get_header_without_profinfo arr dbg) (fun hdr ->
2286            if wordsize_shift = numfloat_shift then
2287              Csequence(make_checkbound dbg [addr_array_length hdr dbg; idx],
2288                        Cifthenelse(is_addr_array_hdr hdr dbg,
2289                                    addr_array_ref arr idx dbg,
2290                                    float_array_ref dbg arr idx))
2291            else
2292              Cifthenelse(is_addr_array_hdr hdr dbg,
2293                Csequence(make_checkbound dbg [addr_array_length hdr dbg; idx],
2294                          addr_array_ref arr idx dbg),
2295                Csequence(make_checkbound dbg [float_array_length hdr dbg; idx],
2296                          float_array_ref dbg arr idx)))))
2297      | Paddrarray ->
2298          bind "index" (transl env arg2) (fun idx ->
2299          bind "arr" (transl env arg1) (fun arr ->
2300            Csequence(make_checkbound dbg [
2301              addr_array_length(get_header_without_profinfo arr dbg) dbg; idx],
2302                      addr_array_ref arr idx dbg)))
2303      | Pintarray ->
2304          bind "index" (transl env arg2) (fun idx ->
2305          bind "arr" (transl env arg1) (fun arr ->
2306            Csequence(make_checkbound dbg [
2307              addr_array_length(get_header_without_profinfo arr dbg) dbg; idx],
2308                      int_array_ref arr idx dbg)))
2309      | Pfloatarray ->
2310          box_float dbg (
2311            bind "index" (transl env arg2) (fun idx ->
2312            bind "arr" (transl env arg1) (fun arr ->
2313              Csequence(make_checkbound dbg
2314                [float_array_length(get_header_without_profinfo arr dbg) dbg;
2315                  idx],
2316                unboxed_float_array_ref arr idx dbg))))
2317      end
2318
2319  (* Operations on bitvects *)
2320  | Pbittest ->
2321      bind "index" (untag_int(transl env arg2) dbg) (fun idx ->
2322        tag_int(
2323          Cop(Cand, [Cop(Clsr, [Cop(Cload (Byte_unsigned, Mutable),
2324                                    [add_int (transl env arg1)
2325                                      (Cop(Clsr, [idx; Cconst_int 3], dbg))
2326                                      dbg],
2327                                    dbg);
2328                                Cop(Cand, [idx; Cconst_int 7], dbg)], dbg);
2329                     Cconst_int 1], dbg)) dbg)
2330
2331  (* Boxed integers *)
2332  | Paddbint bi ->
2333      box_int dbg bi (Cop(Caddi,
2334                      [transl_unbox_int dbg env bi arg1;
2335                       transl_unbox_int dbg env bi arg2], dbg))
2336  | Psubbint bi ->
2337      box_int dbg bi (Cop(Csubi,
2338                      [transl_unbox_int dbg env bi arg1;
2339                       transl_unbox_int dbg env bi arg2], dbg))
2340  | Pmulbint bi ->
2341      box_int dbg bi (Cop(Cmuli,
2342                      [transl_unbox_int dbg env bi arg1;
2343                       transl_unbox_int dbg env bi arg2], dbg))
2344  | Pdivbint { size = bi; is_safe } ->
2345      box_int dbg bi (safe_div_bi is_safe
2346                      (transl_unbox_int dbg env bi arg1)
2347                      (transl_unbox_int dbg env bi arg2)
2348                      bi dbg)
2349  | Pmodbint { size = bi; is_safe } ->
2350      box_int dbg bi (safe_mod_bi is_safe
2351                      (transl_unbox_int dbg env bi arg1)
2352                      (transl_unbox_int dbg env bi arg2)
2353                      bi dbg)
2354  | Pandbint bi ->
2355      box_int dbg bi (Cop(Cand,
2356                     [transl_unbox_int dbg env bi arg1;
2357                      transl_unbox_int dbg env bi arg2], dbg))
2358  | Porbint bi ->
2359      box_int dbg bi (Cop(Cor,
2360                     [transl_unbox_int dbg env bi arg1;
2361                      transl_unbox_int dbg env bi arg2], dbg))
2362  | Pxorbint bi ->
2363      box_int dbg bi (Cop(Cxor,
2364                     [transl_unbox_int dbg env bi arg1;
2365                      transl_unbox_int dbg env bi arg2], dbg))
2366  | Plslbint bi ->
2367      box_int dbg bi (Cop(Clsl,
2368                     [transl_unbox_int dbg env bi arg1;
2369                      untag_int(transl env arg2) dbg], dbg))
2370  | Plsrbint bi ->
2371      box_int dbg bi (Cop(Clsr,
2372                     [make_unsigned_int bi (transl_unbox_int dbg env bi arg1) dbg;
2373                      untag_int(transl env arg2) dbg], dbg))
2374  | Pasrbint bi ->
2375      box_int dbg bi (Cop(Casr,
2376                     [transl_unbox_int dbg env bi arg1;
2377                      untag_int(transl env arg2) dbg], dbg))
2378  | Pbintcomp(bi, cmp) ->
2379      tag_int (Cop(Ccmpi(transl_comparison cmp),
2380                     [transl_unbox_int dbg env bi arg1;
2381                      transl_unbox_int dbg env bi arg2], dbg)) dbg
2382  | prim ->
2383      fatal_errorf "Cmmgen.transl_prim_2: %a" Printlambda.primitive prim
2384
2385and transl_prim_3 env p arg1 arg2 arg3 dbg =
2386  match p with
2387  (* Heap operations *)
2388  | Psetfield_computed(ptr, init) ->
2389      begin match assignment_kind ptr init with
2390      | Caml_modify ->
2391        return_unit (
2392          addr_array_set (transl env arg1) (transl env arg2) (transl env arg3)
2393            dbg)
2394      | Caml_initialize ->
2395        return_unit (
2396          addr_array_initialize (transl env arg1) (transl env arg2)
2397            (transl env arg3) dbg)
2398      | Simple ->
2399        return_unit (
2400          int_array_set (transl env arg1) (transl env arg2) (transl env arg3)
2401            dbg)
2402      end
2403  (* String operations *)
2404  | Pbytessetu ->
2405      return_unit(Cop(Cstore (Byte_unsigned, Assignment),
2406                      [add_int (transl env arg1)
2407                          (untag_int(transl env arg2) dbg)
2408                          dbg;
2409                        untag_int(transl env arg3) dbg], dbg))
2410  | Pbytessets ->
2411      return_unit
2412        (bind "str" (transl env arg1) (fun str ->
2413          bind "index" (untag_int (transl env arg2) dbg) (fun idx ->
2414            Csequence(
2415              make_checkbound dbg [string_length str dbg; idx],
2416              Cop(Cstore (Byte_unsigned, Assignment),
2417                  [add_int str idx dbg; untag_int(transl env arg3) dbg],
2418                  dbg)))))
2419
2420  (* Array operations *)
2421  | Parraysetu kind ->
2422      return_unit(begin match kind with
2423        Pgenarray ->
2424          bind "newval" (transl env arg3) (fun newval ->
2425            bind "index" (transl env arg2) (fun index ->
2426              bind "arr" (transl env arg1) (fun arr ->
2427                Cifthenelse(is_addr_array_ptr arr dbg,
2428                            addr_array_set arr index newval dbg,
2429                            float_array_set arr index (unbox_float dbg newval)
2430                              dbg))))
2431      | Paddrarray ->
2432          addr_array_set (transl env arg1) (transl env arg2) (transl env arg3)
2433            dbg
2434      | Pintarray ->
2435          int_array_set (transl env arg1) (transl env arg2) (transl env arg3)
2436            dbg
2437      | Pfloatarray ->
2438          float_array_set (transl env arg1) (transl env arg2)
2439            (transl_unbox_float dbg env arg3)
2440            dbg
2441      end)
2442  | Parraysets kind ->
2443      return_unit(begin match kind with
2444      | Pgenarray ->
2445          bind "newval" (transl env arg3) (fun newval ->
2446          bind "index" (transl env arg2) (fun idx ->
2447          bind "arr" (transl env arg1) (fun arr ->
2448          bind "header" (get_header_without_profinfo arr dbg) (fun hdr ->
2449            if wordsize_shift = numfloat_shift then
2450              Csequence(make_checkbound dbg [addr_array_length hdr dbg; idx],
2451                        Cifthenelse(is_addr_array_hdr hdr dbg,
2452                                    addr_array_set arr idx newval dbg,
2453                                    float_array_set arr idx
2454                                                    (unbox_float dbg newval)
2455                                                    dbg))
2456            else
2457              Cifthenelse(is_addr_array_hdr hdr dbg,
2458                Csequence(make_checkbound dbg [addr_array_length hdr dbg; idx],
2459                          addr_array_set arr idx newval dbg),
2460                Csequence(make_checkbound dbg [float_array_length hdr dbg; idx],
2461                          float_array_set arr idx
2462                                          (unbox_float dbg newval) dbg))))))
2463      | Paddrarray ->
2464          bind "newval" (transl env arg3) (fun newval ->
2465          bind "index" (transl env arg2) (fun idx ->
2466          bind "arr" (transl env arg1) (fun arr ->
2467            Csequence(make_checkbound dbg [
2468              addr_array_length(get_header_without_profinfo arr dbg) dbg; idx],
2469                      addr_array_set arr idx newval dbg))))
2470      | Pintarray ->
2471          bind "newval" (transl env arg3) (fun newval ->
2472          bind "index" (transl env arg2) (fun idx ->
2473          bind "arr" (transl env arg1) (fun arr ->
2474            Csequence(make_checkbound dbg [
2475              addr_array_length(get_header_without_profinfo arr dbg) dbg; idx],
2476                      int_array_set arr idx newval dbg))))
2477      | Pfloatarray ->
2478          bind_load "newval" (transl_unbox_float dbg env arg3) (fun newval ->
2479          bind "index" (transl env arg2) (fun idx ->
2480          bind "arr" (transl env arg1) (fun arr ->
2481            Csequence(make_checkbound dbg [
2482              float_array_length (get_header_without_profinfo arr dbg) dbg;idx],
2483                      float_array_set arr idx newval dbg))))
2484      end)
2485
2486  | Pstring_set_16(unsafe) ->
2487     return_unit
2488       (bind "str" (transl env arg1) (fun str ->
2489        bind "index" (untag_int (transl env arg2) dbg) (fun idx ->
2490        bind "newval" (untag_int (transl env arg3) dbg) (fun newval ->
2491          check_bound unsafe dbg
2492                      (sub_int (string_length str dbg) (Cconst_int 1) dbg)
2493                      idx (unaligned_set_16 str idx newval dbg)))))
2494
2495  | Pbigstring_set_16(unsafe) ->
2496     return_unit
2497       (bind "ba" (transl env arg1) (fun ba ->
2498        bind "index" (untag_int (transl env arg2) dbg) (fun idx ->
2499        bind "newval" (untag_int (transl env arg3) dbg) (fun newval ->
2500        bind "ba_data"
2501             (Cop(Cload (Word_int, Mutable), [field_address ba 1 dbg], dbg))
2502             (fun ba_data ->
2503          check_bound unsafe dbg (sub_int (Cop(Cload (Word_int, Mutable),
2504                                               [field_address ba 5 dbg], dbg))
2505                                          (Cconst_int 1)
2506                                          dbg)
2507                      idx (unaligned_set_16 ba_data idx newval dbg))))))
2508
2509  | Pstring_set_32(unsafe) ->
2510     return_unit
2511       (bind "str" (transl env arg1) (fun str ->
2512        bind "index" (untag_int (transl env arg2) dbg) (fun idx ->
2513        bind "newval" (transl_unbox_int dbg env Pint32 arg3) (fun newval ->
2514          check_bound unsafe dbg
2515                      (sub_int (string_length str dbg) (Cconst_int 3) dbg)
2516                      idx (unaligned_set_32 str idx newval dbg)))))
2517
2518  | Pbigstring_set_32(unsafe) ->
2519     return_unit
2520       (bind "ba" (transl env arg1) (fun ba ->
2521        bind "index" (untag_int (transl env arg2) dbg) (fun idx ->
2522        bind "newval" (transl_unbox_int dbg env Pint32 arg3) (fun newval ->
2523        bind "ba_data"
2524             (Cop(Cload (Word_int, Mutable), [field_address ba 1 dbg], dbg))
2525             (fun ba_data ->
2526          check_bound unsafe dbg (sub_int (Cop(Cload (Word_int, Mutable),
2527                                               [field_address ba 5 dbg], dbg))
2528                                          (Cconst_int 3)
2529                                          dbg)
2530                      idx (unaligned_set_32 ba_data idx newval dbg))))))
2531
2532  | Pstring_set_64(unsafe) ->
2533     return_unit
2534       (bind "str" (transl env arg1) (fun str ->
2535        bind "index" (untag_int (transl env arg2) dbg) (fun idx ->
2536        bind "newval" (transl_unbox_int dbg env Pint64 arg3) (fun newval ->
2537          check_bound unsafe dbg
2538                      (sub_int (string_length str dbg) (Cconst_int 7) dbg)
2539                      idx (unaligned_set_64 str idx newval dbg)))))
2540
2541  | Pbigstring_set_64(unsafe) ->
2542     return_unit
2543       (bind "ba" (transl env arg1) (fun ba ->
2544        bind "index" (untag_int (transl env arg2) dbg) (fun idx ->
2545        bind "newval" (transl_unbox_int dbg env Pint64 arg3) (fun newval ->
2546        bind "ba_data"
2547             (Cop(Cload (Word_int, Mutable), [field_address ba 1 dbg], dbg))
2548             (fun ba_data ->
2549          check_bound unsafe dbg (sub_int (Cop(Cload (Word_int, Mutable),
2550                                               [field_address ba 5 dbg], dbg))
2551                                          (Cconst_int 7)
2552                                          dbg) idx
2553                      (unaligned_set_64 ba_data idx newval dbg))))))
2554
2555  | prim ->
2556      fatal_errorf "Cmmgen.transl_prim_3: %a" Printlambda.primitive prim
2557
2558and transl_unbox_float dbg env = function
2559    Uconst(Uconst_ref(_, Some (Uconst_float f))) -> Cconst_float f
2560  | exp -> unbox_float dbg (transl env exp)
2561
2562and transl_unbox_int dbg env bi = function
2563    Uconst(Uconst_ref(_, Some (Uconst_int32 n))) ->
2564      Cconst_natint (Nativeint.of_int32 n)
2565  | Uconst(Uconst_ref(_, Some (Uconst_nativeint n))) ->
2566      Cconst_natint n
2567  | Uconst(Uconst_ref(_, Some (Uconst_int64 n))) ->
2568      if size_int = 8 then
2569        Cconst_natint (Int64.to_nativeint n)
2570      else begin
2571        let low = Int64.to_nativeint n in
2572        let high = Int64.to_nativeint (Int64.shift_right_logical n 32) in
2573        if big_endian then Ctuple [Cconst_natint high; Cconst_natint low]
2574        else Ctuple [Cconst_natint low; Cconst_natint high]
2575      end
2576  | Uprim(Pbintofint bi',[Uconst(Uconst_int i)],_) when bi = bi' ->
2577      Cconst_int i
2578  | exp -> unbox_int bi (transl env exp) dbg
2579
2580and transl_unbox_number dbg env bn arg =
2581  match bn with
2582  | Boxed_float _ -> transl_unbox_float dbg env arg
2583  | Boxed_integer (bi, _) -> transl_unbox_int dbg env bi arg
2584
2585and transl_let env str kind id exp body =
2586  let dbg = Debuginfo.none in
2587  let unboxing =
2588    (* If [id] is a mutable variable (introduced to eliminate a local
2589       reference) and it contains a type of unboxable numbers, then
2590       force unboxing.  Indeed, if not boxed, each assignment to the variable
2591       might require some boxing, but such local references are often
2592       used in loops and we really want to avoid repeated boxing. *)
2593    match str, kind with
2594    | Mutable, Pfloatval ->
2595        Boxed (Boxed_float dbg, false)
2596    | Mutable, Pboxedintval bi ->
2597        Boxed (Boxed_integer (bi, dbg), false)
2598    | _, (Pfloatval | Pboxedintval _) ->
2599        (* It would be safe to always unbox in this case, but
2600           we do it only if this indeed allows us to get rid of
2601           some allocations in the bound expression. *)
2602        is_unboxed_number ~strict:false env exp
2603    | _, Pgenval ->
2604        (* Here we don't know statically that the bound expression
2605           evaluates to an unboxable number type.  We need to be stricter
2606           and ensure that all possible branches in the expression
2607           return a boxed value (of the same kind).  Indeed, with GADTs,
2608           different branches could return different types. *)
2609        is_unboxed_number ~strict:true env exp
2610    | _, Pintval ->
2611        No_unboxing
2612  in
2613  match unboxing with
2614  | No_unboxing | Boxed (_, true) | No_result ->
2615      (* N.B. [body] must still be traversed even if [exp] will never return:
2616         there may be constant closures inside that need lifting out. *)
2617      Clet(id, transl env exp, transl env body)
2618  | Boxed (boxed_number, _false) ->
2619      let unboxed_id = Ident.create (Ident.name id) in
2620      Clet(unboxed_id, transl_unbox_number dbg env boxed_number exp,
2621           transl (add_unboxed_id id unboxed_id boxed_number env) body)
2622
2623and make_catch ncatch body handler = match body with
2624| Cexit (nexit,[]) when nexit=ncatch -> handler
2625| _ ->  ccatch (ncatch, [], body, handler)
2626
2627and make_catch2 mk_body handler = match handler with
2628| Cexit (_,[])|Ctuple []|Cconst_int _|Cconst_pointer _ ->
2629    mk_body handler
2630| _ ->
2631    let nfail = next_raise_count () in
2632    make_catch
2633      nfail
2634      (mk_body (Cexit (nfail,[])))
2635      handler
2636
2637and exit_if_true dbg env cond nfail otherwise =
2638  match cond with
2639  | Uconst (Uconst_ptr 0) -> otherwise
2640  | Uconst (Uconst_ptr 1) -> Cexit (nfail,[])
2641  | Uifthenelse (arg1, Uconst (Uconst_ptr 1), arg2)
2642  | Uprim(Psequor, [arg1; arg2], _) ->
2643      exit_if_true dbg env arg1 nfail
2644        (exit_if_true dbg env arg2 nfail otherwise)
2645  | Uifthenelse (_, _, Uconst (Uconst_ptr 0))
2646  | Uprim(Psequand, _, _) ->
2647      begin match otherwise with
2648      | Cexit (raise_num,[]) ->
2649          exit_if_false dbg env cond (Cexit (nfail,[])) raise_num
2650      | _ ->
2651          let raise_num = next_raise_count () in
2652          make_catch
2653            raise_num
2654            (exit_if_false dbg env cond (Cexit (nfail,[])) raise_num)
2655            otherwise
2656      end
2657  | Uprim(Pnot, [arg], _) ->
2658      exit_if_false dbg env arg otherwise nfail
2659  | Uifthenelse (cond, ifso, ifnot) ->
2660      make_catch2
2661        (fun shared ->
2662          if_then_else
2663            (test_bool dbg (transl env cond),
2664             exit_if_true dbg env ifso nfail shared,
2665             exit_if_true dbg env ifnot nfail shared))
2666        otherwise
2667  | _ ->
2668      if_then_else(test_bool dbg (transl env cond),
2669        Cexit (nfail, []), otherwise)
2670
2671and exit_if_false dbg env cond otherwise nfail =
2672  match cond with
2673  | Uconst (Uconst_ptr 0) -> Cexit (nfail,[])
2674  | Uconst (Uconst_ptr 1) -> otherwise
2675  | Uifthenelse (arg1, arg2, Uconst (Uconst_ptr 0))
2676  | Uprim(Psequand, [arg1; arg2], _) ->
2677      exit_if_false dbg env arg1
2678        (exit_if_false dbg env arg2 otherwise nfail) nfail
2679  | Uifthenelse (_, Uconst (Uconst_ptr 1), _)
2680  | Uprim(Psequor, _, _) ->
2681      begin match otherwise with
2682      | Cexit (raise_num,[]) ->
2683          exit_if_true dbg env cond raise_num (Cexit (nfail,[]))
2684      | _ ->
2685          let raise_num = next_raise_count () in
2686          make_catch
2687            raise_num
2688            (exit_if_true dbg env cond raise_num (Cexit (nfail,[])))
2689            otherwise
2690      end
2691  | Uprim(Pnot, [arg], _) ->
2692      exit_if_true dbg env arg nfail otherwise
2693  | Uifthenelse (cond, ifso, ifnot) ->
2694      make_catch2
2695        (fun shared ->
2696          if_then_else
2697            (test_bool dbg (transl env cond),
2698             exit_if_false dbg env ifso shared nfail,
2699             exit_if_false dbg env ifnot shared nfail))
2700        otherwise
2701  | _ ->
2702      if_then_else (test_bool dbg (transl env cond), otherwise,
2703        Cexit (nfail, []))
2704
2705and transl_switch _dbg env arg index cases = match Array.length cases with
2706| 0 -> fatal_error "Cmmgen.transl_switch"
2707| 1 -> transl env cases.(0)
2708| _ ->
2709    let cases = Array.map (transl env) cases in
2710    let store = StoreExp.mk_store () in
2711    let index =
2712      Array.map
2713        (fun j -> store.Switch.act_store cases.(j))
2714        index in
2715    let n_index = Array.length index in
2716    let inters = ref []
2717    and this_high = ref (n_index-1)
2718    and this_low = ref (n_index-1)
2719    and this_act = ref index.(n_index-1) in
2720    for i = n_index-2 downto 0 do
2721      let act = index.(i) in
2722      if act = !this_act then
2723        decr this_low
2724      else begin
2725        inters := (!this_low, !this_high, !this_act) :: !inters ;
2726        this_high := i ;
2727        this_low := i ;
2728        this_act := act
2729      end
2730    done ;
2731    inters := (0, !this_high, !this_act) :: !inters ;
2732    match !inters with
2733    | [_] -> cases.(0)
2734    | inters ->
2735        bind "switcher" arg
2736          (fun a ->
2737            SwitcherBlocks.zyva
2738              (0,n_index-1)
2739              a
2740              (Array.of_list inters) store)
2741
2742and transl_letrec env bindings cont =
2743  let dbg = Debuginfo.none in
2744  let bsz =
2745    List.map (fun (id, exp) -> (id, exp, expr_size Ident.empty exp))
2746      bindings
2747  in
2748  let op_alloc prim sz =
2749    Cop(Cextcall(prim, typ_val, true, None), [int_const sz], dbg) in
2750  let rec init_blocks = function
2751    | [] -> fill_nonrec bsz
2752    | (id, _exp, RHS_block sz) :: rem ->
2753        Clet(id, op_alloc "caml_alloc_dummy" sz,
2754          init_blocks rem)
2755    | (id, _exp, RHS_floatblock sz) :: rem ->
2756        Clet(id, op_alloc "caml_alloc_dummy_float" sz,
2757          init_blocks rem)
2758    | (id, _exp, RHS_nonrec) :: rem ->
2759        Clet (id, Cconst_int 0, init_blocks rem)
2760  and fill_nonrec = function
2761    | [] -> fill_blocks bsz
2762    | (_id, _exp, (RHS_block _ | RHS_floatblock _)) :: rem ->
2763        fill_nonrec rem
2764    | (id, exp, RHS_nonrec) :: rem ->
2765        Clet(id, transl env exp, fill_nonrec rem)
2766  and fill_blocks = function
2767    | [] -> cont
2768    | (id, exp, (RHS_block _ | RHS_floatblock _)) :: rem ->
2769        let op =
2770          Cop(Cextcall("caml_update_dummy", typ_void, false, None),
2771              [Cvar id; transl env exp], dbg) in
2772        Csequence(op, fill_blocks rem)
2773    | (_id, _exp, RHS_nonrec) :: rem ->
2774        fill_blocks rem
2775  in init_blocks bsz
2776
2777(* Translate a function definition *)
2778
2779let transl_function f =
2780  let body =
2781    if Config.flambda then
2782      Un_anf.apply f.body ~what:f.label
2783    else
2784      f.body
2785  in
2786  let cmm_body =
2787    let env = create_env ~environment_param:f.env in
2788    if !Clflags.afl_instrument then
2789      Afl_instrument.instrument_function (transl env body)
2790    else
2791      transl env body in
2792  Cfunction {fun_name = f.label;
2793             fun_args = List.map (fun id -> (id, typ_val)) f.params;
2794             fun_body = cmm_body;
2795             fun_fast = !Clflags.optimize_for_speed;
2796             fun_dbg  = f.dbg}
2797
2798(* Translate all function definitions *)
2799
2800module StringSet =
2801  Set.Make(struct
2802    type t = string
2803    let compare (x:t) y = compare x y
2804  end)
2805
2806let rec transl_all_functions already_translated cont =
2807  try
2808    let f = Queue.take functions in
2809    if StringSet.mem f.label already_translated then
2810      transl_all_functions already_translated cont
2811    else begin
2812      transl_all_functions
2813        (StringSet.add f.label already_translated)
2814        ((f.dbg, transl_function f) :: cont)
2815    end
2816  with Queue.Empty ->
2817    cont, already_translated
2818
2819let cdefine_symbol (symb, global) =
2820  match global with
2821  | Global -> [Cglobal_symbol symb; Cdefine_symbol symb]
2822  | Not_global -> [Cdefine_symbol symb]
2823
2824(* Emit structured constants *)
2825
2826let rec emit_structured_constant symb cst cont =
2827  let emit_block white_header symb cont =
2828    (* Headers for structured constants must be marked black in case we
2829       are in no-naked-pointers mode.  See [caml_darken]. *)
2830    let black_header = Nativeint.logor white_header caml_black in
2831    Cint black_header :: cdefine_symbol symb @ cont
2832  in
2833  match cst with
2834  | Uconst_float s->
2835      emit_block float_header symb (Cdouble s :: cont)
2836  | Uconst_string s ->
2837      emit_block (string_header (String.length s)) symb
2838        (emit_string_constant s cont)
2839  | Uconst_int32 n ->
2840      emit_block boxedint32_header symb
2841        (emit_boxed_int32_constant n cont)
2842  | Uconst_int64 n ->
2843      emit_block boxedint64_header symb
2844        (emit_boxed_int64_constant n cont)
2845  | Uconst_nativeint n ->
2846      emit_block boxedintnat_header symb
2847        (emit_boxed_nativeint_constant n cont)
2848  | Uconst_block (tag, csts) ->
2849      let cont = List.fold_right emit_constant csts cont in
2850      emit_block (block_header tag (List.length csts)) symb cont
2851  | Uconst_float_array fields ->
2852      emit_block (floatarray_header (List.length fields)) symb
2853        (Misc.map_end (fun f -> Cdouble f) fields cont)
2854  | Uconst_closure(fundecls, lbl, fv) ->
2855      assert(lbl = fst symb);
2856      add_cmm_constant (Const_closure (symb, fundecls, fv));
2857      List.iter (fun f -> Queue.add f functions) fundecls;
2858      cont
2859
2860and emit_constant cst cont =
2861  match cst with
2862  | Uconst_int n | Uconst_ptr n ->
2863      cint_const n
2864      :: cont
2865  | Uconst_ref (label, _) ->
2866      Csymbol_address label :: cont
2867
2868and emit_string_constant s cont =
2869  let n = size_int - 1 - (String.length s) mod size_int in
2870  Cstring s :: Cskip n :: Cint8 n :: cont
2871
2872and emit_boxed_int32_constant n cont =
2873  let n = Nativeint.of_int32 n in
2874  if size_int = 8 then
2875    Csymbol_address("caml_int32_ops") :: Cint32 n :: Cint32 0n :: cont
2876  else
2877    Csymbol_address("caml_int32_ops") :: Cint n :: cont
2878
2879and emit_boxed_nativeint_constant n cont =
2880  Csymbol_address("caml_nativeint_ops") :: Cint n :: cont
2881
2882and emit_boxed_int64_constant n cont =
2883  let lo = Int64.to_nativeint n in
2884  if size_int = 8 then
2885    Csymbol_address("caml_int64_ops") :: Cint lo :: cont
2886  else begin
2887    let hi = Int64.to_nativeint (Int64.shift_right n 32) in
2888    if big_endian then
2889      Csymbol_address("caml_int64_ops") :: Cint hi :: Cint lo :: cont
2890    else
2891      Csymbol_address("caml_int64_ops") :: Cint lo :: Cint hi :: cont
2892  end
2893
2894(* Emit constant closures *)
2895
2896let emit_constant_closure ((_, global_symb) as symb) fundecls clos_vars cont =
2897  let closure_symbol f =
2898    if Config.flambda then
2899      cdefine_symbol (f.label ^ "_closure", global_symb)
2900    else
2901      []
2902  in
2903  match fundecls with
2904    [] ->
2905      (* This should probably not happen: dead code has normally been
2906         eliminated and a closure cannot be accessed without going through
2907         a [Project_closure], which depends on the function. *)
2908      assert (clos_vars = []);
2909      cdefine_symbol symb @
2910        List.fold_right emit_constant clos_vars cont
2911  | f1 :: remainder ->
2912      let rec emit_others pos = function
2913          [] ->
2914            List.fold_right emit_constant clos_vars cont
2915      | f2 :: rem ->
2916          if f2.arity = 1 || f2.arity = 0 then
2917            Cint(infix_header pos) ::
2918            (closure_symbol f2) @
2919            Csymbol_address f2.label ::
2920            cint_const f2.arity ::
2921            emit_others (pos + 3) rem
2922          else
2923            Cint(infix_header pos) ::
2924            (closure_symbol f2) @
2925            Csymbol_address(curry_function f2.arity) ::
2926            cint_const f2.arity ::
2927            Csymbol_address f2.label ::
2928            emit_others (pos + 4) rem in
2929      Cint(black_closure_header (fundecls_size fundecls
2930                                 + List.length clos_vars)) ::
2931      cdefine_symbol symb @
2932      (closure_symbol f1) @
2933      if f1.arity = 1 || f1.arity = 0 then
2934        Csymbol_address f1.label ::
2935        cint_const f1.arity ::
2936        emit_others 3 remainder
2937      else
2938        Csymbol_address(curry_function f1.arity) ::
2939        cint_const f1.arity ::
2940        Csymbol_address f1.label ::
2941        emit_others 4 remainder
2942
2943(* Emit constant blocks *)
2944
2945let emit_constant_table symb elems =
2946  cdefine_symbol symb @
2947  elems
2948
2949(* Emit all structured constants *)
2950
2951let emit_constants cont (constants:Clambda.preallocated_constant list) =
2952  let c = ref cont in
2953  List.iter
2954    (fun { symbol = lbl; exported; definition = cst } ->
2955       let global = if exported then Global else Not_global in
2956       let cst = emit_structured_constant (lbl, global) cst [] in
2957         c:= Cdata(cst):: !c)
2958    constants;
2959  List.iter
2960    (function
2961    | Const_closure (symb, fundecls, clos_vars) ->
2962        c := Cdata(emit_constant_closure symb fundecls clos_vars []) :: !c
2963    | Const_table (symb, elems) ->
2964        c := Cdata(emit_constant_table symb elems) :: !c)
2965    !cmm_constants;
2966  cmm_constants := [];
2967  !c
2968
2969let emit_all_constants cont =
2970  let constants = Compilenv.structured_constants () in
2971  Compilenv.clear_structured_constants ();
2972  emit_constants cont constants
2973
2974let transl_all_functions_and_emit_all_constants cont =
2975  let rec aux already_translated cont translated_functions =
2976    if Compilenv.structured_constants () = [] &&
2977       Queue.is_empty functions
2978    then cont, translated_functions
2979    else
2980      let translated_functions, already_translated =
2981        transl_all_functions already_translated translated_functions
2982      in
2983      let cont = emit_all_constants cont in
2984      aux already_translated cont translated_functions
2985  in
2986  let cont, translated_functions =
2987    aux StringSet.empty cont []
2988  in
2989  let translated_functions =
2990    (* Sort functions according to source position *)
2991    List.map snd
2992      (List.sort (fun (dbg1, _) (dbg2, _) ->
2993           Debuginfo.compare dbg1 dbg2) translated_functions)
2994  in
2995  translated_functions @ cont
2996
2997(* Build the NULL terminated array of gc roots *)
2998
2999let emit_gc_roots_table ~symbols cont =
3000  let table_symbol = Compilenv.make_symbol (Some "gc_roots") in
3001  Cdata(Cglobal_symbol table_symbol ::
3002        Cdefine_symbol table_symbol ::
3003        List.map (fun s -> Csymbol_address s) symbols @
3004        [Cint 0n])
3005  :: cont
3006
3007(* Build preallocated blocks (used for Flambda [Initialize_symbol]
3008   constructs, and Clambda global module) *)
3009
3010let preallocate_block cont { Clambda.symbol; exported; tag; size } =
3011  let space =
3012    (* These words will be registered as roots and as such must contain
3013       valid values, in case we are in no-naked-pointers mode.  Likewise
3014       the block header must be black, below (see [caml_darken]), since
3015       the overall record may be referenced. *)
3016    Array.to_list
3017      (Array.init size (fun _index ->
3018        Cint (Nativeint.of_int 1 (* Val_unit *))))
3019  in
3020  let data =
3021    Cint(black_block_header tag size) ::
3022    if exported then
3023      Cglobal_symbol symbol ::
3024      Cdefine_symbol symbol :: space
3025    else
3026      Cdefine_symbol symbol :: space
3027  in
3028  Cdata data :: cont
3029
3030let emit_preallocated_blocks preallocated_blocks cont =
3031  let symbols =
3032    List.map (fun ({ Clambda.symbol }:Clambda.preallocated_block) -> symbol)
3033      preallocated_blocks
3034  in
3035  let c1 = emit_gc_roots_table ~symbols cont in
3036  List.fold_left preallocate_block c1 preallocated_blocks
3037
3038(* Translate a compilation unit *)
3039
3040let compunit (ulam, preallocated_blocks, constants) =
3041  let init_code =
3042    if !Clflags.afl_instrument then
3043      Afl_instrument.instrument_initialiser (transl empty_env ulam)
3044    else
3045      transl empty_env ulam in
3046  let c1 = [Cfunction {fun_name = Compilenv.make_symbol (Some "entry");
3047                       fun_args = [];
3048                       fun_body = init_code; fun_fast = false;
3049                       fun_dbg  = Debuginfo.none }] in
3050  let c2 = emit_constants c1 constants in
3051  let c3 = transl_all_functions_and_emit_all_constants c2 in
3052  emit_preallocated_blocks preallocated_blocks c3
3053
3054(*
3055CAMLprim value caml_cache_public_method (value meths, value tag, value *cache)
3056{
3057  int li = 3, hi = Field(meths,0), mi;
3058  while (li < hi) { // no need to check the 1st time
3059    mi = ((li+hi) >> 1) | 1;
3060    if (tag < Field(meths,mi)) hi = mi-2;
3061    else li = mi;
3062  }
3063  *cache = (li-3)*sizeof(value)+1;
3064  return Field (meths, li-1);
3065}
3066*)
3067
3068let cache_public_method meths tag cache dbg =
3069  let raise_num = next_raise_count () in
3070  let li = Ident.create "li" and hi = Ident.create "hi"
3071  and mi = Ident.create "mi" and tagged = Ident.create "tagged" in
3072  Clet (
3073  li, Cconst_int 3,
3074  Clet (
3075  hi, Cop(Cload (Word_int, Mutable), [meths], dbg),
3076  Csequence(
3077  ccatch
3078    (raise_num, [],
3079     Cloop
3080       (Clet(
3081        mi,
3082        Cop(Cor,
3083            [Cop(Clsr, [Cop(Caddi, [Cvar li; Cvar hi], dbg); Cconst_int 1],
3084               dbg);
3085             Cconst_int 1],
3086            dbg),
3087        Csequence(
3088        Cifthenelse
3089          (Cop (Ccmpi Clt,
3090                [tag;
3091                 Cop(Cload (Word_int, Mutable),
3092                     [Cop(Cadda,
3093                          [meths; lsl_const (Cvar mi) log2_size_addr dbg],
3094                          dbg)],
3095                     dbg)], dbg),
3096           Cassign(hi, Cop(Csubi, [Cvar mi; Cconst_int 2], dbg)),
3097           Cassign(li, Cvar mi)),
3098        Cifthenelse
3099          (Cop(Ccmpi Cge, [Cvar li; Cvar hi], dbg), Cexit (raise_num, []),
3100           Ctuple [])))),
3101     Ctuple []),
3102  Clet (
3103    tagged,
3104      Cop(Cadda, [lsl_const (Cvar li) log2_size_addr dbg;
3105        Cconst_int(1 - 3 * size_addr)], dbg),
3106    Csequence(Cop (Cstore (Word_int, Assignment), [cache; Cvar tagged], dbg),
3107              Cvar tagged)))))
3108
3109(* Generate an application function:
3110     (defun caml_applyN (a1 ... aN clos)
3111       (if (= clos.arity N)
3112         (app clos.direct a1 ... aN clos)
3113         (let (clos1 (app clos.code a1 clos)
3114               clos2 (app clos1.code a2 clos)
3115               ...
3116               closN-1 (app closN-2.code aN-1 closN-2))
3117           (app closN-1.code aN closN-1))))
3118*)
3119
3120let apply_function_body arity =
3121  let dbg = Debuginfo.none in
3122  let arg = Array.make arity (Ident.create "arg") in
3123  for i = 1 to arity - 1 do arg.(i) <- Ident.create "arg" done;
3124  let clos = Ident.create "clos" in
3125  let env = empty_env in
3126  let rec app_fun clos n =
3127    if n = arity-1 then
3128      Cop(Capply typ_val,
3129          [get_field env (Cvar clos) 0 dbg; Cvar arg.(n); Cvar clos], dbg)
3130    else begin
3131      let newclos = Ident.create "clos" in
3132      Clet(newclos,
3133           Cop(Capply typ_val,
3134               [get_field env (Cvar clos) 0 dbg; Cvar arg.(n); Cvar clos], dbg),
3135           app_fun newclos (n+1))
3136    end in
3137  let args = Array.to_list arg in
3138  let all_args = args @ [clos] in
3139  (args, clos,
3140   if arity = 1 then app_fun clos 0 else
3141   Cifthenelse(
3142   Cop(Ccmpi Ceq, [get_field env (Cvar clos) 1 dbg; int_const arity], dbg),
3143   Cop(Capply typ_val,
3144       get_field env (Cvar clos) 2 dbg :: List.map (fun s -> Cvar s) all_args,
3145       dbg),
3146   app_fun clos 0))
3147
3148let send_function arity =
3149  let dbg = Debuginfo.none in
3150  let (args, clos', body) = apply_function_body (1+arity) in
3151  let cache = Ident.create "cache"
3152  and obj = List.hd args
3153  and tag = Ident.create "tag" in
3154  let env = empty_env in
3155  let clos =
3156    let cache = Cvar cache and obj = Cvar obj and tag = Cvar tag in
3157    let meths = Ident.create "meths" and cached = Ident.create "cached" in
3158    let real = Ident.create "real" in
3159    let mask = get_field env (Cvar meths) 1 dbg in
3160    let cached_pos = Cvar cached in
3161    let tag_pos = Cop(Cadda, [Cop (Cadda, [cached_pos; Cvar meths], dbg);
3162                              Cconst_int(3*size_addr-1)], dbg) in
3163    let tag' = Cop(Cload (Word_int, Mutable), [tag_pos], dbg) in
3164    Clet (
3165    meths, Cop(Cload (Word_val, Mutable), [obj], dbg),
3166    Clet (
3167    cached,
3168      Cop(Cand, [Cop(Cload (Word_int, Mutable), [cache], dbg); mask], dbg),
3169    Clet (
3170    real,
3171    Cifthenelse(Cop(Ccmpa Cne, [tag'; tag], dbg),
3172                cache_public_method (Cvar meths) tag cache dbg,
3173                cached_pos),
3174    Cop(Cload (Word_val, Mutable),
3175      [Cop(Cadda, [Cop (Cadda, [Cvar real; Cvar meths], dbg);
3176       Cconst_int(2*size_addr-1)], dbg)], dbg))))
3177
3178  in
3179  let body = Clet(clos', clos, body) in
3180  let cache = cache in
3181  let fun_args =
3182    [obj, typ_val; tag, typ_int; cache, typ_val]
3183    @ List.map (fun id -> (id, typ_val)) (List.tl args) in
3184  let fun_name = "caml_send" ^ string_of_int arity in
3185  Cfunction
3186   {fun_name;
3187    fun_args = fun_args;
3188    fun_body = body;
3189    fun_fast = true;
3190    fun_dbg  = Debuginfo.none }
3191
3192let apply_function arity =
3193  let (args, clos, body) = apply_function_body arity in
3194  let all_args = args @ [clos] in
3195  let fun_name = "caml_apply" ^ string_of_int arity in
3196  Cfunction
3197   {fun_name;
3198    fun_args = List.map (fun id -> (id, typ_val)) all_args;
3199    fun_body = body;
3200    fun_fast = true;
3201    fun_dbg  = Debuginfo.none;
3202   }
3203
3204(* Generate tuplifying functions:
3205      (defun caml_tuplifyN (arg clos)
3206        (app clos.direct #0(arg) ... #N-1(arg) clos)) *)
3207
3208let tuplify_function arity =
3209  let dbg = Debuginfo.none in
3210  let arg = Ident.create "arg" in
3211  let clos = Ident.create "clos" in
3212  let env = empty_env in
3213  let rec access_components i =
3214    if i >= arity
3215    then []
3216    else get_field env (Cvar arg) i dbg :: access_components(i+1) in
3217  let fun_name = "caml_tuplify" ^ string_of_int arity in
3218  Cfunction
3219   {fun_name;
3220    fun_args = [arg, typ_val; clos, typ_val];
3221    fun_body =
3222      Cop(Capply typ_val,
3223          get_field env (Cvar clos) 2 dbg :: access_components 0 @ [Cvar clos],
3224          dbg);
3225    fun_fast = true;
3226    fun_dbg  = Debuginfo.none;
3227   }
3228
3229(* Generate currying functions:
3230      (defun caml_curryN (arg clos)
3231         (alloc HDR caml_curryN_1 <arity (N-1)> caml_curry_N_1_app arg clos))
3232      (defun caml_curryN_1 (arg clos)
3233         (alloc HDR caml_curryN_2 <arity (N-2)> caml_curry_N_2_app arg clos))
3234      ...
3235      (defun caml_curryN_N-1 (arg clos)
3236         (let (closN-2 clos.vars[1]
3237               closN-3 closN-2.vars[1]
3238               ...
3239               clos1 clos2.vars[1]
3240               clos clos1.vars[1])
3241           (app clos.direct
3242                clos1.vars[0] ... closN-2.vars[0] clos.vars[0] arg clos)))
3243
3244    Special "shortcut" functions are also generated to handle the
3245    case where a partially applied function is applied to all remaining
3246    arguments in one go.  For instance:
3247      (defun caml_curry_N_1_app (arg2 ... argN clos)
3248        (let clos' clos.vars[1]
3249           (app clos'.direct clos.vars[0] arg2 ... argN clos')))
3250
3251    Those shortcuts may lead to a quadratic number of application
3252    primitives being generated in the worst case, which resulted in
3253    linking time blowup in practice (PR#5933), so we only generate and
3254    use them when below a fixed arity 'max_arity_optimized'.
3255*)
3256
3257let max_arity_optimized = 15
3258let final_curry_function arity =
3259  let dbg = Debuginfo.none in
3260  let last_arg = Ident.create "arg" in
3261  let last_clos = Ident.create "clos" in
3262  let env = empty_env in
3263  let rec curry_fun args clos n =
3264    if n = 0 then
3265      Cop(Capply typ_val,
3266          get_field env (Cvar clos) 2 dbg ::
3267            args @ [Cvar last_arg; Cvar clos],
3268          dbg)
3269    else
3270      if n = arity - 1 || arity > max_arity_optimized then
3271        begin
3272      let newclos = Ident.create "clos" in
3273      Clet(newclos,
3274           get_field env (Cvar clos) 3 dbg,
3275           curry_fun (get_field env (Cvar clos) 2 dbg :: args) newclos (n-1))
3276        end else
3277        begin
3278          let newclos = Ident.create "clos" in
3279          Clet(newclos,
3280               get_field env (Cvar clos) 4 dbg,
3281               curry_fun (get_field env (Cvar clos) 3 dbg :: args) newclos (n-1))
3282    end in
3283  Cfunction
3284   {fun_name = "caml_curry" ^ string_of_int arity ^
3285               "_" ^ string_of_int (arity-1);
3286    fun_args = [last_arg, typ_val; last_clos, typ_val];
3287    fun_body = curry_fun [] last_clos (arity-1);
3288    fun_fast = true;
3289    fun_dbg  = Debuginfo.none }
3290
3291let rec intermediate_curry_functions arity num =
3292  let dbg = Debuginfo.none in
3293  let env = empty_env in
3294  if num = arity - 1 then
3295    [final_curry_function arity]
3296  else begin
3297    let name1 = "caml_curry" ^ string_of_int arity in
3298    let name2 = if num = 0 then name1 else name1 ^ "_" ^ string_of_int num in
3299    let arg = Ident.create "arg" and clos = Ident.create "clos" in
3300    Cfunction
3301     {fun_name = name2;
3302      fun_args = [arg, typ_val; clos, typ_val];
3303      fun_body =
3304         if arity - num > 2 && arity <= max_arity_optimized then
3305           Cop(Calloc,
3306               [alloc_closure_header 5 Debuginfo.none;
3307                Cconst_symbol(name1 ^ "_" ^ string_of_int (num+1));
3308                int_const (arity - num - 1);
3309                Cconst_symbol(name1 ^ "_" ^ string_of_int (num+1) ^ "_app");
3310                Cvar arg; Cvar clos],
3311               dbg)
3312         else
3313           Cop(Calloc,
3314                [alloc_closure_header 4 Debuginfo.none;
3315                 Cconst_symbol(name1 ^ "_" ^ string_of_int (num+1));
3316                 int_const 1; Cvar arg; Cvar clos],
3317                dbg);
3318      fun_fast = true;
3319      fun_dbg  = Debuginfo.none }
3320    ::
3321      (if arity <= max_arity_optimized && arity - num > 2 then
3322          let rec iter i =
3323            if i <= arity then
3324              let arg = Ident.create (Printf.sprintf "arg%d" i) in
3325              (arg, typ_val) :: iter (i+1)
3326            else []
3327          in
3328          let direct_args = iter (num+2) in
3329          let rec iter i args clos =
3330            if i = 0 then
3331              Cop(Capply typ_val,
3332                  (get_field env (Cvar clos) 2 dbg) :: args @ [Cvar clos],
3333                  dbg)
3334            else
3335              let newclos = Ident.create "clos" in
3336              Clet(newclos,
3337                   get_field env (Cvar clos) 4 dbg,
3338                   iter (i-1) (get_field env (Cvar clos) 3 dbg :: args) newclos)
3339          in
3340          let cf =
3341            Cfunction
3342              {fun_name = name1 ^ "_" ^ string_of_int (num+1) ^ "_app";
3343               fun_args = direct_args @ [clos, typ_val];
3344               fun_body = iter (num+1)
3345                  (List.map (fun (arg,_) -> Cvar arg) direct_args) clos;
3346               fun_fast = true;
3347               fun_dbg = Debuginfo.none }
3348          in
3349          cf :: intermediate_curry_functions arity (num+1)
3350       else
3351          intermediate_curry_functions arity (num+1))
3352  end
3353
3354let curry_function arity =
3355  assert(arity <> 0);
3356  (* Functions with arity = 0 does not have a curry_function *)
3357  if arity > 0
3358  then intermediate_curry_functions arity 0
3359  else [tuplify_function (-arity)]
3360
3361
3362module IntSet = Set.Make(
3363  struct
3364    type t = int
3365    let compare (x:t) y = compare x y
3366  end)
3367
3368let default_apply = IntSet.add 2 (IntSet.add 3 IntSet.empty)
3369  (* These apply funs are always present in the main program because
3370     the run-time system needs them (cf. asmrun/<arch>.S) . *)
3371
3372let generic_functions shared units =
3373  let (apply,send,curry) =
3374    List.fold_left
3375      (fun (apply,send,curry) ui ->
3376         List.fold_right IntSet.add ui.ui_apply_fun apply,
3377         List.fold_right IntSet.add ui.ui_send_fun send,
3378         List.fold_right IntSet.add ui.ui_curry_fun curry)
3379      (IntSet.empty,IntSet.empty,IntSet.empty)
3380      units in
3381  let apply = if shared then apply else IntSet.union apply default_apply in
3382  let accu = IntSet.fold (fun n accu -> apply_function n :: accu) apply [] in
3383  let accu = IntSet.fold (fun n accu -> send_function n :: accu) send accu in
3384  IntSet.fold (fun n accu -> curry_function n @ accu) curry accu
3385
3386(* Generate the entry point *)
3387
3388let entry_point namelist =
3389  (* CR mshinwell: review all of these "None"s.  We should be able to at
3390     least have filenames for these. *)
3391  let dbg = Debuginfo.none in
3392  let incr_global_inited =
3393    Cop(Cstore (Word_int, Assignment),
3394        [Cconst_symbol "caml_globals_inited";
3395         Cop(Caddi, [Cop(Cload (Word_int, Mutable),
3396                       [Cconst_symbol "caml_globals_inited"], dbg);
3397                     Cconst_int 1], dbg)], dbg) in
3398  let body =
3399    List.fold_right
3400      (fun name next ->
3401        let entry_sym = Compilenv.make_symbol ~unitname:name (Some "entry") in
3402        Csequence(Cop(Capply typ_void,
3403                         [Cconst_symbol entry_sym], dbg),
3404                  Csequence(incr_global_inited, next)))
3405      namelist (Cconst_int 1) in
3406  Cfunction {fun_name = "caml_program";
3407             fun_args = [];
3408             fun_body = body;
3409             fun_fast = false;
3410             fun_dbg  = Debuginfo.none }
3411
3412(* Generate the table of globals *)
3413
3414let cint_zero = Cint 0n
3415
3416let global_table namelist =
3417  let mksym name =
3418    Csymbol_address (Compilenv.make_symbol ~unitname:name (Some "gc_roots"))
3419  in
3420  Cdata(Cglobal_symbol "caml_globals" ::
3421        Cdefine_symbol "caml_globals" ::
3422        List.map mksym namelist @
3423        [cint_zero])
3424
3425let reference_symbols namelist =
3426  let mksym name = Csymbol_address name in
3427  Cdata(List.map mksym namelist)
3428
3429let global_data name v =
3430  Cdata(emit_structured_constant (name, Global)
3431          (Uconst_string (Marshal.to_string v [])) [])
3432
3433let globals_map v = global_data "caml_globals_map" v
3434
3435(* Generate the master table of frame descriptors *)
3436
3437let frame_table namelist =
3438  let mksym name =
3439    Csymbol_address (Compilenv.make_symbol ~unitname:name (Some "frametable"))
3440  in
3441  Cdata(Cglobal_symbol "caml_frametable" ::
3442        Cdefine_symbol "caml_frametable" ::
3443        List.map mksym namelist
3444        @ [cint_zero])
3445
3446(* Generate the master table of Spacetime shapes *)
3447
3448let spacetime_shapes namelist =
3449  let mksym name =
3450    Csymbol_address (
3451      Compilenv.make_symbol ~unitname:name (Some "spacetime_shapes"))
3452  in
3453  Cdata(Cglobal_symbol "caml_spacetime_shapes" ::
3454        Cdefine_symbol "caml_spacetime_shapes" ::
3455        List.map mksym namelist
3456        @ [cint_zero])
3457
3458(* Generate the table of module data and code segments *)
3459
3460let segment_table namelist symbol begname endname =
3461  let addsyms name lst =
3462    Csymbol_address (Compilenv.make_symbol ~unitname:name (Some begname)) ::
3463    Csymbol_address (Compilenv.make_symbol ~unitname:name (Some endname)) ::
3464    lst
3465  in
3466  Cdata(Cglobal_symbol symbol ::
3467        Cdefine_symbol symbol ::
3468        List.fold_right addsyms namelist [cint_zero])
3469
3470let data_segment_table namelist =
3471  segment_table namelist "caml_data_segments" "data_begin" "data_end"
3472
3473let code_segment_table namelist =
3474  segment_table namelist "caml_code_segments" "code_begin" "code_end"
3475
3476(* Initialize a predefined exception *)
3477
3478let predef_exception i name =
3479  let symname = "caml_exn_" ^ name in
3480  let cst = Uconst_string name in
3481  let label = Compilenv.new_const_symbol () in
3482  let cont = emit_structured_constant (label, Not_global) cst [] in
3483  Cdata(emit_structured_constant (symname, Global)
3484          (Uconst_block(Obj.object_tag,
3485                       [
3486                         Uconst_ref(label, Some cst);
3487                         Uconst_int (-i-1);
3488                       ])) cont)
3489
3490(* Header for a plugin *)
3491
3492let plugin_header units =
3493  let mk (ui,crc) =
3494    { dynu_name = ui.ui_name;
3495      dynu_crc = crc;
3496      dynu_imports_cmi = ui.ui_imports_cmi;
3497      dynu_imports_cmx = ui.ui_imports_cmx;
3498      dynu_defines = ui.ui_defines
3499    } in
3500  global_data "caml_plugin_header"
3501    { dynu_magic = Config.cmxs_magic_number; dynu_units = List.map mk units }
3502