(* TEST modules = "is_in_static_data.c is_static_flambda_dep.ml" * flambda ** naked_pointers *** native *) (* Data that should be statically allocated by the compiler (flambda only) *) external is_in_static_data : 'a -> bool = "caml_is_in_static_data" (* Also after inlining *) let g x = let block = (1,x) in assert(is_in_static_data block) let () = (g [@inlined always]) 2 (* Toplevel immutable blocks should be static *) let block3 = (Sys.opaque_identity 1, Sys.opaque_identity 2) let () = assert(is_in_static_data block3) (* Not being bound shouldn't prevent it *) let () = assert(is_in_static_data (Sys.opaque_identity 1, Sys.opaque_identity 2)) (* Only with rounds >= 2 currently ! (* Also after inlining *) let h x = let block = (Sys.opaque_identity 1,x) in assert(is_in_static_data block) let () = (h [@inlined always]) (Sys.opaque_identity 2) *) (* Recursive constant values should be static *) let rec a = 1 :: b and b = 2 :: a let () = assert(is_in_static_data a); assert(is_in_static_data b) (* And a mix *) type e = E : 'a -> e let rec f1 a = E (g1 a, l1) and g1 a = E (f1 a, l2) and l1 = E (f1, l2) and l2 = E (g1, l1) let () = assert(is_in_static_data f1); assert(is_in_static_data g1); assert(is_in_static_data l1); assert(is_in_static_data l2) (* Also in functions *) let i () = let rec f1 a = E (g1 a, l1) and g1 a = E (f1 a, l2) and l1 = E (f1, l2) and l2 = E (g1, l1) in assert(is_in_static_data f1); assert(is_in_static_data g1); assert(is_in_static_data l1); assert(is_in_static_data l2) let () = (i [@inlined never]) () module type P = module type of Stdlib (* Top-level modules should be static *) let () = assert(is_in_static_data (module Stdlib:P)) (* Not constant let rec to test extraction to initialize_symbol *) let r = ref 0 let rec a = (incr r; !r) :: b and b = (incr r; !r) :: a let next = let r = ref 0 in fun () -> incr r; !r let () = assert(is_in_static_data next) (* Exceptions without arguments should be static *) exception No_argument let () = assert(is_in_static_data No_argument) (* And also with constant arguments *) exception Some_argument of string let () = assert(is_in_static_data (Some_argument "some string")) (* Even when exposed by inlining *) let () = let exn = try (failwith [@inlined always]) "some other string" with exn -> exn in assert(is_in_static_data exn) (* Verify that approximation intersection correctly loads exported approximations. Is_static_flambda_dep.pair is a pair with 1 as first element. The intersection of approximations should return a block with approximation: [tag 0: [tag 0: Int 1, Unknown], Unknown] *) let f x = let pair = if Sys.opaque_identity x then (1, 2), 3 else Is_static_flambda_dep.pair, 4 in let n = fst (fst pair) in let res = n, n in assert(is_in_static_data res) [@@inline never] let () = f true; f false (* Verify that physical equality/inequality is correctly propagated *) (* In these tests, tuple can be statically allocated only if it is a known constant since the function is never inlined (hence this code is never at toplevel) *) let () = let f () = let v = (1, 2) in (* eq is supposed to be considered always true since v is a constant, hence aliased to a symbol. It is not yet optimized away if it is not constant *) let eq = v == v in let n = if eq then 1 else 2 in let tuple = (n,n) in assert(is_in_static_data tuple) in (f [@inlined never]) () let () = let f () = let v = (1, 2) in (* same with inequality *) let eq = v != v in let n = if eq then 1 else 2 in let tuple = (n,n) in assert(is_in_static_data tuple) in (f [@inlined never]) () let () = let f x = let v1 = Some x in let v2 = None in let eq = v1 == v2 in (* The values are structurally different, so must be physically different *) let n = if eq then 1 else 2 in let tuple = (n,n) in assert(is_in_static_data tuple) in (f [@inlined never]) () let () = let f x = let v1 = Some x in let v2 = None in let eq = v1 != v2 in (* same with inequality *) let n = if eq then 1 else 2 in let tuple = (n,n) in assert(is_in_static_data tuple) in (f [@inlined never]) () let () = let f x = let v1 = (1, 2) in let v2 = (3, 2) in let eq = v1 == v2 in (* difference is deeper *) let n = if eq then 1 else 2 in let tuple = (n,n) in assert(is_in_static_data tuple) in (f [@inlined never]) () module Int = struct type t = int let compare (a:int) b = compare a b end module IntMap = Map.Make (Int) let () = let f () = let a = IntMap.empty in let b = (IntMap.add [@inlined]) 1 (Some 1) a in assert(is_in_static_data b); let c = (IntMap.add [@inlined]) 1 (Some 2) b in assert(is_in_static_data c); let d = (IntMap.add [@inlined]) 1 (Some 2) c in assert(is_in_static_data d); in (f [@inlined never]) ()