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