Source

ocaml-llvm-phantom / examples / pi.ml

(* Simple monte-carlo to compute pi *)

let (&) = (@@)

open Llvm_phantom.Std
module P = Phantom

let context = Llvm.global_context () 

include Create(struct let context = context end)
open Type
open Value

include CreateModule(struct
  let name = "mymodule"
  let opt = true
end)

let random = External.declare "random" i32 P.c0
let rand_max = 2147483647.0 (* This is RAND_MAX from stdlib.h, in my environment *)

let random_point_1d = perform
  r_i32 <-- call random P.c0;
  r_double <-- sitofp r_i32 double;
  r_double /.! Const.double rand_max (* 0.0 - 1.0 *)

let sq_dist_of_2d_point x y = perform
  x2 <-- x *.! x;
  y2 <-- y *.! y;
  x2 +.! y2

let incr v = perform
  i <-- Gep.(gep_load v (pos 0) end_); (* CR jfuruse: this should be written like v.{pos 0} *)
  i' <-- i +! Const.i32_1;
  Gep.(gep_store i' ~dst:v (pos 0) end_) (* CR jfurus: this should be written like v.{pos 0} <- i' *)

let number = 10000000

let test = perform
  in_points_ptr <-- alloca_with ~name:"in_points" i32 (Const.i32_0);
  
  for_loop (Const.i32_of_int number)
    (fun n -> icmp Llvm.Icmp.Ne n Const.i32_0)
    (fun n -> perform
      x <-- random_point_1d;
      y <-- random_point_1d;
      dist <-- sq_dist_of_2d_point x y;
      (* printf "%d %f %f %f\n" [!?n; !?x; !?y; !?dist]; *)
      imp_if_then_else
        (fcmp Llvm.Fcmp.Olt dist (Const.double 1.0))
        (incr in_points_ptr)
        (return ());
      n -! Const.i32_1);

  in_points <-- Gep.(gep_load in_points_ptr (pos 0) end_);
  in_points <-- sitofp in_points double;
  in_points /.! Const.double (Pervasives.float number /. 4.0)

let test_f = build & func0 "calc_pi" ~dump:true double () & fun _self () -> test
let run_test_f = ExecutionEngine.run_function0 test_f
let run_test_ocaml () = Genvalue.as_float double (run_test_f ())

let () = Printf.eprintf "pi(%d times)=%f\n" number (run_test_ocaml ())