[ocamlformat] upgrade ocamlformat to 0.8

Reviewed By: mbouaziz

Differential Revision: D10359577

fbshipit-source-id: e7f5286e3
master
Josh Berdine 6 years ago committed by Facebook Github Bot
parent 9eecd1bb9b
commit e1d4aad487

@ -1,3 +1,4 @@
let-binding-spacing = sparse
break-cases = nested break-cases = nested
margin = 100 margin = 100
version = 0.7 version = 0.8

@ -1 +1 @@
b3ed72b3997cb7712e54f90d47128d6dd8e18f53 e2cf2fd21fdc2f79840ddf994403a0c2469b6bfd

@ -684,7 +684,7 @@ endif
# This is a magical version number that doesn't reinstall the world when added on top of what we # This is a magical version number that doesn't reinstall the world when added on top of what we
# have in opam.lock. To upgrade this version number, manually try to install several utop versions # have in opam.lock. To upgrade this version number, manually try to install several utop versions
# until you find one that doesn't recompile the world. TODO(t20828442): get rid of magic # until you find one that doesn't recompile the world. TODO(t20828442): get rid of magic
OPAM_DEV_DEPS = ocamlformat.$$(grep version .ocamlformat | cut -d ' ' -f 3) ocp-indent merlin utop.2.2.0 webbrowser OPAM_DEV_DEPS = ocp-indent merlin utop.2.2.0 webbrowser
ifneq ($(EMACS),no) ifneq ($(EMACS),no)
OPAM_DEV_DEPS += tuareg OPAM_DEV_DEPS += tuareg
@ -697,6 +697,8 @@ devsetup: Makefile.autoconf
OPAMSWITCH=$(OPAMSWITCH); $(OPAM) install --yes --no-checksum user-setup $(OPAM_DEV_DEPS)) OPAMSWITCH=$(OPAMSWITCH); $(OPAM) install --yes --no-checksum user-setup $(OPAM_DEV_DEPS))
$(QUIET)echo '$(TERM_INFO)*** Running `opam config setup -a`$(TERM_RESET)' >&2 $(QUIET)echo '$(TERM_INFO)*** Running `opam config setup -a`$(TERM_RESET)' >&2
$(QUIET)OPAMSWITCH=$(OPAMSWITCH); $(OPAM) config --yes setup -a $(QUIET)OPAMSWITCH=$(OPAMSWITCH); $(OPAM) config --yes setup -a
$(QUIET)$(call silent_on_success,installing ocamlformat,\
OPAMSWITCH=$(OPAMSWITCH); $(OPAM) pin add --yes ocamlformat.$$(grep version .ocamlformat | cut -d ' ' -f 3) https://github.com/ocaml-ppx/ocamlformat.git#$$(grep version .ocamlformat | cut -d ' ' -f 3)-opam1)
$(QUIET)echo '$(TERM_INFO)*** Running `opam user-setup`$(TERM_RESET)' >&2 $(QUIET)echo '$(TERM_INFO)*** Running `opam user-setup`$(TERM_RESET)' >&2
$(QUIET)OPAMSWITCH=$(OPAMSWITCH); OPAMYES=1; $(OPAM) user-setup install $(QUIET)OPAMSWITCH=$(OPAMSWITCH); OPAMYES=1; $(OPAM) user-setup install
$(QUIET)if [ "$(PLATFORM)" = "Darwin" ] && [ x"$(GNU_SED)" = x"no" ]; then \ $(QUIET)if [ "$(PLATFORM)" = "Darwin" ] && [ x"$(GNU_SED)" = x"no" ]; then \

@ -210,6 +210,7 @@ let rec eval_arithmetic_binop op e1 e2 =
| _ -> | _ ->
None None
and eval = function and eval = function
| Constant c -> | Constant c ->
Some c Some c

@ -1188,8 +1188,8 @@ and () =
issue types. This option provides fine-grained filtering over which types of issue should \ issue types. This option provides fine-grained filtering over which types of issue should \
be reported once the checkers have run. In particular, note that disabling issue types \ be reported once the checkers have run. In particular, note that disabling issue types \
does not make the corresponding checker not run.\n\ does not make the corresponding checker not run.\n\
By default, the following issue types are disabled: %s.\n\n \ \ By default, the following issue types are disabled: %s.\n\n\
See also $(b,--report-issue-type).\n" \ See also $(b,--report-issue-type).\n"
(String.concat ~sep:", " disabled_issues_ids)) ; (String.concat ~sep:", " disabled_issues_ids)) ;
mk true ~long:"enable-issue-type" mk true ~long:"enable-issue-type"
~deprecated:["enable_checks"; "-enable-checks"] ~deprecated:["enable_checks"; "-enable-checks"]

@ -7,9 +7,10 @@
open! IStd open! IStd
exception
(* WARNING: ONLY USE IF Logging IS NOT AVAILABLE TO YOU FOR SOME REASON (e.g., inside Config). *) (* WARNING: ONLY USE IF Logging IS NOT AVAILABLE TO YOU FOR SOME REASON (e.g., inside Config). *)
InferExternalError of
exception InferExternalError of string string
exception InferInternalError of string exception InferInternalError of string

@ -46,7 +46,7 @@ let load_and_validate () =
(Printf.sprintf (Printf.sprintf
"'%s' already exists but it is not an empty directory and it does not look like an \ "'%s' already exists but it is not an empty directory and it does not look like an \
infer results directory:\n\ infer results directory:\n\
%s\n\ \ %s\n\
Was it created using an older version of infer?" Was it created using an older version of infer?"
Config.results_dir err_msg) ) Config.results_dir err_msg) )
msg msg

@ -10,9 +10,8 @@ open! IStd
(** Re-arrangement and extension of structures with fresh variables *) (** Re-arrangement and extension of structures with fresh variables *)
(* TODO: this description is not clear *) exception (* TODO: this description is not clear *)
ARRAY_ACCESS
exception ARRAY_ACCESS
val is_only_pt_by_fld_or_param_nonnull : val is_only_pt_by_fld_or_param_nonnull :
Procdesc.t -> Tenv.t -> Prop.normal Prop.t -> Exp.t -> bool Procdesc.t -> Tenv.t -> Prop.normal Prop.t -> Exp.t -> bool

@ -8,6 +8,7 @@
open! IStd open! IStd
module F = Format module F = Format
module L = Logging module L = Logging
(* forward dependency analysis for computing set of variables that (* forward dependency analysis for computing set of variables that
affect the looping behavior of the program affect the looping behavior of the program

@ -8,6 +8,7 @@ open! IStd
open Graph open Graph
module L = Logging module L = Logging
module CFG = ProcCfg.Normal module CFG = ProcCfg.Normal
(* Use ocamlgraph's dominators functor to get the dominators *) (* Use ocamlgraph's dominators functor to get the dominators *)
module GDoms = Dominator.Make (ProcCfg.MakeOcamlGraph (CFG)) module GDoms = Dominator.Make (ProcCfg.MakeOcamlGraph (CFG))

@ -148,5 +148,6 @@ module Summary = struct
post = set of uninit local variables of the procedure *) post = set of uninit local variables of the procedure *)
type t = Domain.t prepost type t = Domain.t prepost
let pp fmt {pre; post} = F.fprintf fmt "@\n Pre: %a @\nPost: %a @\n" Domain.pp pre Domain.pp post let pp fmt {pre; post} =
F.fprintf fmt "@\n Pre: %a @\nPost: %a @\n" Domain.pp pre Domain.pp post
end end

@ -160,7 +160,8 @@ let cc1_capture clang_cmd =
else if else if
Config.skip_analysis_in_path_skips_compilation && CLocation.is_file_blacklisted source_path Config.skip_analysis_in_path_skips_compilation && CLocation.is_file_blacklisted source_path
then ( then (
L.(debug Capture Quiet) "@\n Skip compilation and analysis of source file %s@\n@\n" source_path ; L.(debug Capture Quiet)
"@\n Skip compilation and analysis of source file %s@\n@\n" source_path ;
() ) () )
else else
match Config.clang_biniou_file with match Config.clang_biniou_file with

@ -181,6 +181,6 @@ let exe ~prog ~args =
L.(debug Capture Quiet) L.(debug Capture Quiet)
"WARNING: `clang -### <args>` returned an empty set of commands to run and no error. Will \ "WARNING: `clang -### <args>` returned an empty set of commands to run and no error. Will \
run the original command directly:@\n\ run the original command directly:@\n\
%s@\n" \ %s@\n"
(String.concat ~sep:" " @@ (prog :: args)) ; (String.concat ~sep:" " @@ (prog :: args)) ;
Process.create_process_and_wait ~prog ~args ) Process.create_process_and_wait ~prog ~args )

@ -1165,6 +1165,7 @@ let rec eval_Atomic pred_name_ args an lcxt =
| _ -> | _ ->
L.(die ExternalError) "Undefined Predicate or wrong set of arguments: '%s'" pred_name L.(die ExternalError) "Undefined Predicate or wrong set of arguments: '%s'" pred_name
and eval_AND an lcxt f1 f2 = and eval_AND an lcxt f1 f2 =
match eval_formula f1 an lcxt with match eval_formula f1 an lcxt with
| Some witness1 -> ( | Some witness1 -> (
@ -1176,6 +1177,7 @@ and eval_AND an lcxt f1 f2 =
| None (* we short-circuit the AND evaluation *) -> | None (* we short-circuit the AND evaluation *) ->
None None
and eval_OR an lcxt f1 f2 = choose_witness_opt (eval_formula f1 an lcxt) (eval_formula f2 an lcxt) and eval_OR an lcxt f1 f2 = choose_witness_opt (eval_formula f1 an lcxt) (eval_formula f2 an lcxt)
and eval_Implies an lcxt f1 f2 = and eval_Implies an lcxt f1 f2 =
@ -1183,6 +1185,7 @@ and eval_Implies an lcxt f1 f2 =
let witness2 = eval_formula f2 an lcxt in let witness2 = eval_formula f2 an lcxt in
choose_witness_opt witness1 witness2 choose_witness_opt witness1 witness2
(* an, lcxt |= EF phi <=> (* an, lcxt |= EF phi <=>
an, lcxt |= phi or exists an' in Successors(st): an', lcxt |= EF phi an, lcxt |= phi or exists an' in Successors(st): an', lcxt |= EF phi
@ -1203,6 +1206,7 @@ and eval_EF phi an lcxt trans =
List.fold_left (Ctl_parser_types.get_direct_successor_nodes an) ~init:witness_opt List.fold_left (Ctl_parser_types.get_direct_successor_nodes an) ~init:witness_opt
~f:(fun acc node -> choose_witness_opt (eval_EF phi node lcxt trans) acc ) ~f:(fun acc node -> choose_witness_opt (eval_EF phi node lcxt trans) acc )
(* an, lcxt |= EX phi <=> exists an' in Successors(st): an', lcxt |= phi (* an, lcxt |= EX phi <=> exists an' in Successors(st): an', lcxt |= phi
That is: a (an, lcxt) satifies EX phi if and only if That is: a (an, lcxt) satifies EX phi if and only if
@ -1227,6 +1231,7 @@ and eval_EX phi an lcxt trans =
| _ -> | _ ->
witness_opt witness_opt
(* an, lcxt |= E(phi1 U phi2) evaluated using the equivalence (* an, lcxt |= E(phi1 U phi2) evaluated using the equivalence
an, lcxt |= E(phi1 U phi2) <=> an, lcxt |= phi2 or (phi1 and EX(E(phi1 U phi2))) an, lcxt |= E(phi1 U phi2) <=> an, lcxt |= phi2 or (phi1 and EX(E(phi1 U phi2)))
@ -1237,6 +1242,7 @@ and eval_EU phi1 phi2 an lcxt trans =
let f = Or (phi2, And (phi1, EX (trans, EU (trans, phi1, phi2)))) in let f = Or (phi2, And (phi1, EX (trans, EU (trans, phi1, phi2)))) in
eval_formula f an lcxt eval_formula f an lcxt
(* an |= A(phi1 U phi2) evaluated using the equivalence (* an |= A(phi1 U phi2) evaluated using the equivalence
an |= A(phi1 U phi2) <=> an |= phi2 or (phi1 and AX(A(phi1 U phi2))) an |= A(phi1 U phi2) <=> an |= phi2 or (phi1 and AX(A(phi1 U phi2)))
@ -1246,6 +1252,7 @@ and eval_AU phi1 phi2 an lcxt trans =
let f = Or (phi2, And (phi1, AX (trans, AU (trans, phi1, phi2)))) in let f = Or (phi2, And (phi1, AX (trans, AU (trans, phi1, phi2)))) in
eval_formula f an lcxt eval_formula f an lcxt
(* an, lcxt |= InNode[node_type_list] phi <=> (* an, lcxt |= InNode[node_type_list] phi <=>
an is a node of type in node_type_list and an satifies phi an is a node of type in node_type_list and an satifies phi
*) *)
@ -1263,6 +1270,7 @@ and in_node node_type_list phi an lctx =
List.fold_left node_type_list ~init:None ~f:(fun acc node -> List.fold_left node_type_list ~init:None ~f:(fun acc node ->
choose_witness_opt (holds_for_one_node node) acc ) choose_witness_opt (holds_for_one_node node) acc )
(* Intuitive meaning: (an,lcxt) satifies EH[Classes] phi (* Intuitive meaning: (an,lcxt) satifies EH[Classes] phi
if the node an is among the declaration specified by the list Classes and if the node an is among the declaration specified by the list Classes and
there exists a super class in its hierarchy whose declaration satisfy phi. there exists a super class in its hierarchy whose declaration satisfy phi.
@ -1275,6 +1283,7 @@ and eval_EH classes phi an lcxt =
let f = ET (classes, None, EX (Some Super, EF (Some Super, phi))) in let f = ET (classes, None, EX (Some Super, EF (Some Super, phi))) in
eval_formula f an lcxt eval_formula f an lcxt
(* an, lcxt |= ET[T][->l]phi <=> (* an, lcxt |= ET[T][->l]phi <=>
eventually we reach a node an' such that an' is among the types defined in T eventually we reach a node an' such that an' is among the types defined in T
and: and:
@ -1295,6 +1304,7 @@ and eval_ET tl trs phi an lcxt =
in in
eval_formula f an lcxt eval_formula f an lcxt
(* Formulas are evaluated on a AST node an and a linter context lcxt *) (* Formulas are evaluated on a AST node an and a linter context lcxt *)
and eval_formula f an lcxt : Ctl_parser_types.ast_node option = and eval_formula f an lcxt : Ctl_parser_types.ast_node option =
debug_eval_begin (debug_create_payload an f lcxt) ; debug_eval_begin (debug_create_payload an f lcxt) ;

@ -98,6 +98,7 @@ let rec build_array_type translate_decl tenv (qual_type : Clang_ast_t.qual_type)
let stride = Option.map ~f:IntLit.of_int stride_opt in let stride = Option.map ~f:IntLit.of_int stride_opt in
Typ.Tarray {elt= array_type; length; stride} Typ.Tarray {elt= array_type; length; stride}
and type_desc_of_attr_type translate_decl tenv type_info attr_info = and type_desc_of_attr_type translate_decl tenv type_info attr_info =
match type_info.Clang_ast_t.ti_desugared_type with match type_info.Clang_ast_t.ti_desugared_type with
| Some type_ptr -> ( | Some type_ptr -> (
@ -110,6 +111,7 @@ and type_desc_of_attr_type translate_decl tenv type_info attr_info =
| None -> | None ->
Typ.Tvoid Typ.Tvoid
and type_desc_of_c_type translate_decl tenv c_type : Typ.desc = and type_desc_of_c_type translate_decl tenv c_type : Typ.desc =
let open Clang_ast_t in let open Clang_ast_t in
match c_type with match c_type with
@ -167,6 +169,7 @@ and type_desc_of_c_type translate_decl tenv c_type : Typ.desc =
| None -> | None ->
Typ.Tvoid ) Typ.Tvoid )
and decl_ptr_to_type_desc translate_decl tenv decl_ptr : Typ.desc = and decl_ptr_to_type_desc translate_decl tenv decl_ptr : Typ.desc =
let open Clang_ast_t in let open Clang_ast_t in
let typ = Clang_ast_extend.DeclPtr decl_ptr in let typ = Clang_ast_extend.DeclPtr decl_ptr in
@ -194,6 +197,7 @@ and decl_ptr_to_type_desc translate_decl tenv decl_ptr : Typ.desc =
(Clang_ast_j.string_of_pointer decl_ptr) ; (Clang_ast_j.string_of_pointer decl_ptr) ;
Typ.Tvoid ) Typ.Tvoid )
and clang_type_ptr_to_type_desc translate_decl tenv type_ptr = and clang_type_ptr_to_type_desc translate_decl tenv type_ptr =
try Clang_ast_extend.TypePointerMap.find type_ptr !CFrontend_config.sil_types_map try Clang_ast_extend.TypePointerMap.find type_ptr !CFrontend_config.sil_types_map
with Caml.Not_found -> ( with Caml.Not_found -> (
@ -205,6 +209,7 @@ and clang_type_ptr_to_type_desc translate_decl tenv type_ptr =
| _ -> | _ ->
Typ.Tvoid ) Typ.Tvoid )
and type_ptr_to_type_desc translate_decl tenv type_ptr : Typ.desc = and type_ptr_to_type_desc translate_decl tenv type_ptr : Typ.desc =
match type_ptr with match type_ptr with
| Clang_ast_types.TypePtr.Ptr _ -> | Clang_ast_types.TypePtr.Ptr _ ->
@ -226,6 +231,7 @@ and type_ptr_to_type_desc translate_decl tenv type_ptr : Typ.desc =
| _ -> | _ ->
L.(die InternalError) "unknown variant for type_ptr" L.(die InternalError) "unknown variant for type_ptr"
and qual_type_to_sil_type translate_decl tenv qual_type = and qual_type_to_sil_type translate_decl tenv qual_type =
let desc = type_ptr_to_type_desc translate_decl tenv qual_type.Clang_ast_t.qt_type_ptr in let desc = type_ptr_to_type_desc translate_decl tenv qual_type.Clang_ast_t.qt_type_ptr in
let quals = Typ.mk_type_quals ~is_const:qual_type.Clang_ast_t.qt_is_const () in let quals = Typ.mk_type_quals ~is_const:qual_type.Clang_ast_t.qt_is_const () in

@ -6,6 +6,7 @@
*) *)
open! IStd open! IStd
(* This module adds more variants to some types in AST The implementation extends default one from (* This module adds more variants to some types in AST The implementation extends default one from
the facebook-clang-plugins repository *) the facebook-clang-plugins repository *)
@ -88,6 +89,7 @@ module TypePointerOrd = struct
L.(die InternalError) L.(die InternalError)
"unexpected type_ptr variants: %s, %s" (type_ptr_to_string t1) (type_ptr_to_string t2) "unexpected type_ptr variants: %s, %s" (type_ptr_to_string t1) (type_ptr_to_string t2)
and compare_qual_type (qt1 : Clang_ast_t.qual_type) (qt2 : Clang_ast_t.qual_type) = and compare_qual_type (qt1 : Clang_ast_t.qual_type) (qt2 : Clang_ast_t.qual_type) =
if phys_equal qt1 qt2 then 0 if phys_equal qt1 qt2 then 0
else else

@ -255,9 +255,9 @@ let add_valid_formulae an checker lcxt cl =
| AG _ | AX _ | AF _ | AU _ | EH _ | ET _ | Implies _ -> | AG _ | AX _ | AF _ | AU _ | EH _ | ET _ | Implies _ ->
Logging.die InternalError Logging.die InternalError
"@\n\ "@\n\
We should not have operators AG, AX, AF, AU, EH, ET.\n \ \ We should not have operators AG, AX, AF, AU, EH, ET.\n\
Failing with formula @\n \ \ Failing with formula @\n\
%a@\n" \ %a@\n"
CTL.Debug.pp_formula phi CTL.Debug.pp_formula phi
| _ -> | _ ->
acc_set acc_set

@ -742,7 +742,8 @@ let get_reporting_explanation_java report_kind tenv pname thread =
if is_thread_safe_method pname tenv then if is_thread_safe_method pname tenv then
Some Some
(F.asprintf (F.asprintf
"@\n Reporting because current method is annotated %a or overrides an annotated method." "@\n\
\ Reporting because current method is annotated %a or overrides an annotated method."
MF.pp_monospaced "@ThreadSafe") MF.pp_monospaced "@ThreadSafe")
else else
match FbThreadSafety.get_fbthreadsafe_class_annot pname tenv with match FbThreadSafety.get_fbthreadsafe_class_annot pname tenv with
@ -789,7 +790,7 @@ let get_reporting_explanation_java report_kind tenv pname thread =
( IssueType.thread_safety_violation ( IssueType.thread_safety_violation
, F.asprintf , F.asprintf
"@\n\ "@\n\
Reporting because another access to the same memory occurs on a background thread, \ \ Reporting because another access to the same memory occurs on a background thread, \
although this access may not." ) although this access may not." )

@ -699,7 +699,7 @@ let pp fmt {threads; locks; accesses; ownership; attribute_map; wobbly_paths} =
F.fprintf fmt F.fprintf fmt
"Threads: %a, Locks: %a @\n\ "Threads: %a, Locks: %a @\n\
Accesses %a @\n\ Accesses %a @\n\
Ownership: %a @\n\ \ Ownership: %a @\n\
Attributes: %a @\n\ Attributes: %a @\n\
Non-stable Paths: %a@\n" Non-stable Paths: %a@\n"
ThreadsDomain.pp threads LocksDomain.pp locks AccessDomain.pp accesses OwnershipDomain.pp ThreadsDomain.pp threads LocksDomain.pp locks AccessDomain.pp accesses OwnershipDomain.pp

@ -138,8 +138,8 @@ let tests =
; var_assign_id "var" "read_id" ; var_assign_id "var" "read_id"
; invariant ; invariant
"{ base_id$0.f* => (SOURCE -> ?),\n\ "{ base_id$0.f* => (SOURCE -> ?),\n\
ret_id$0* => (SOURCE -> ?),\n \ \ ret_id$0* => (SOURCE -> ?),\n\
var* => (SOURCE -> ?) }" ] ) \ var* => (SOURCE -> ?) }" ] )
; ( "source flows to var then cleared" ; ( "source flows to var then cleared"
, [ assign_to_source "ret_id" , [ assign_to_source "ret_id"
; var_assign_id "var" "ret_id" ; var_assign_id "var" "ret_id"

@ -39,6 +39,7 @@ end = struct
let (Arg (trm, set)) = List.fold_right ~f:pair args ~init in let (Arg (trm, set)) = List.fold_right ~f:pair args ~init in
Term.app (Term.const set) trm Term.app (Term.const set) trm
let args : arg list ref = ref [] let args : arg list ref = ref []
let mk ~default arg = let mk ~default arg =
@ -47,6 +48,7 @@ end = struct
args := Arg (arg, set) :: !args ; args := Arg (arg, set) :: !args ;
var var
let parse info validate = let parse info validate =
match Term.eval (Term.(ret (const validate $ tuple !args)), info) with match Term.eval (Term.(ret (const validate $ tuple !args)), info) with
| `Ok () -> () | `Ok () -> ()
@ -60,14 +62,17 @@ let input =
mk ~default:"" mk ~default:""
Arg.(required & pos ~rev:true 0 (some string) None & info []) Arg.(required & pos ~rev:true 0 (some string) None & info [])
let output = let output =
let default = None in let default = None in
mk ~default Arg.(value & opt (some string) default & info ["o"; "output"]) mk ~default Arg.(value & opt (some string) default & info ["o"; "output"])
let trace_all = let trace_all =
let default = false in let default = false in
mk ~default Arg.(value & flag & info ["t"; "trace-all"]) mk ~default Arg.(value & flag & info ["t"; "trace-all"])
let info = Term.info "sledge" ~version:Version.version let info = Term.info "sledge" ~version:Version.version
let validate () = `Ok () let validate () = `Ok ()

@ -43,11 +43,13 @@ let option_fmt fmt pp ff = function
| Some x -> Format.fprintf ff fmt pp x | Some x -> Format.fprintf ff fmt pp x
| None -> () | None -> ()
let rec list_fmt sep pp ff = function let rec list_fmt sep pp ff = function
| [] -> () | [] -> ()
| [x] -> pp ff x | [x] -> pp ff x
| x :: xs -> Format.fprintf ff "%a%( %)%a" pp x sep (list_fmt sep pp) xs | x :: xs -> Format.fprintf ff "%a%( %)%a" pp x sep (list_fmt sep pp) xs
let vector_fmt sep pp ff v = list_fmt sep pp ff (Vector.to_list v) let vector_fmt sep pp ff v = list_fmt sep pp ff (Vector.to_list v)
let warn fmt = let warn fmt =
@ -60,6 +62,7 @@ let warn fmt =
Format.pp_force_newline ff () ) Format.pp_force_newline ff () )
ff fmt ff fmt
let raisef exn fmt = let raisef exn fmt =
let bt = Caml.Printexc.get_raw_backtrace () in let bt = Caml.Printexc.get_raw_backtrace () in
let ff = Format.str_formatter in let ff = Format.str_formatter in
@ -72,6 +75,7 @@ let raisef exn fmt =
Caml.Printexc.raise_with_backtrace exn bt ) Caml.Printexc.raise_with_backtrace exn bt )
ff fmt ff fmt
exception Unimplemented of string exception Unimplemented of string
let todo fmt = raisef (fun msg -> Unimplemented msg) fmt let todo fmt = raisef (fun msg -> Unimplemented msg) fmt
@ -82,10 +86,12 @@ let assertf cnd fmt =
if not cnd then fail fmt if not cnd then fail fmt
else Format.ikfprintf (fun _ () -> ()) Format.str_formatter fmt else Format.ikfprintf (fun _ () -> ()) Format.str_formatter fmt
let checkf cnd fmt = let checkf cnd fmt =
if not cnd then fail fmt if not cnd then fail fmt
else Format.ikfprintf (fun _ () -> true) Format.str_formatter fmt else Format.ikfprintf (fun _ () -> true) Format.str_formatter fmt
type 'a or_error = ('a, exn * Caml.Printexc.raw_backtrace) Result.t type 'a or_error = ('a, exn * Caml.Printexc.raw_backtrace) Result.t
let or_error f x () = let or_error f x () =

@ -70,6 +70,7 @@ let uncurry exp =
in in
uncurry_ [] exp uncurry_ [] exp
let rec fmt ff exp = let rec fmt ff exp =
let pf fmt = let pf fmt =
Format.pp_open_box ff 2 ; Format.pp_open_box ff 2 ;
@ -125,6 +126,7 @@ let rec fmt ff exp =
| Rem, [x; y] -> pf "(%a@ %% %a)" fmt x fmt y | Rem, [x; y] -> pf "(%a@ %% %a)" fmt x fmt y
| URem, [x; y] -> pf "(%a@ u%% %a)" fmt x fmt y | URem, [x; y] -> pf "(%a@ u%% %a)" fmt x fmt y
(** Queries *) (** Queries *)
let rec typ_of : t -> Typ.t = function[@warning "p"] let rec typ_of : t -> Typ.t = function[@warning "p"]
@ -172,6 +174,7 @@ let rec typ_of : t -> Typ.t = function[@warning "p"]
typ_of arg typ_of arg
| AppN {op} -> typ_of op | AppN {op} -> typ_of op
let valid_fld fld elts = 0 <= fld && fld < Vector.length elts let valid_fld fld elts = 0 <= fld && fld < Vector.length elts
(** Re-exported modules *) (** Re-exported modules *)
@ -220,6 +223,7 @@ module Global = struct
(option_fmt " =@ @[%a@]" fmt) (option_fmt " =@ @[%a@]" fmt)
init init
let fmt = fmt let fmt = fmt
let mk ?init ?(loc = Loc.none) name typ = let mk ?init ?(loc = Loc.none) name typ =
@ -228,6 +232,7 @@ module Global = struct
Typ.equal typ (Typ.mkPointer ~elt:(typ_of exp)) ) ) ; Typ.equal typ (Typ.mkPointer ~elt:(typ_of exp)) ) ) ;
Global {name; init; typ; loc} Global {name; init; typ; loc}
let of_exp e = match e with Global _ -> Some e | _ -> None let of_exp e = match e with Global _ -> Some e | _ -> None
let name = function[@warning "p"] Global {name} -> name let name = function[@warning "p"] Global {name} -> name
@ -249,6 +254,7 @@ let locate loc exp =
| AppN {op; args} -> AppN {op; args; loc} | AppN {op; args} -> AppN {op; args; loc}
| _ -> exp | _ -> exp
let mkApp1 op arg = App {op; arg; loc= Loc.none} let mkApp1 op arg = App {op; arg; loc= Loc.none}
let mkApp2 op x y = mkApp1 (mkApp1 op x) y let mkApp2 op x y = mkApp1 (mkApp1 op x) y
@ -265,12 +271,14 @@ let mkNondet (typ : Typ.t) msg =
assert (match typ with Function _ -> false | _ -> true) ; assert (match typ with Function _ -> false | _ -> true) ;
Nondet {typ; loc= Loc.none; msg} Nondet {typ; loc= Loc.none; msg}
let mkLabel ~parent ~name = Label {parent; name; loc= Loc.none} let mkLabel ~parent ~name = Label {parent; name; loc= Loc.none}
let mkNull (typ : Typ.t) = let mkNull (typ : Typ.t) =
assert (match typ with Opaque _ | Function _ -> false | _ -> true) ; assert (match typ with Opaque _ | Function _ -> false | _ -> true) ;
Null {typ} Null {typ}
let mkPtrFld ~ptr ~fld = let mkPtrFld ~ptr ~fld =
assert ( assert (
match typ_of ptr with match typ_of ptr with
@ -278,6 +286,7 @@ let mkPtrFld ~ptr ~fld =
| _ -> false ) ; | _ -> false ) ;
mkApp1 (PtrFld {fld}) ptr mkApp1 (PtrFld {fld}) ptr
let mkPtrIdx ~ptr ~idx = let mkPtrIdx ~ptr ~idx =
assert ( assert (
match (typ_of ptr, typ_of idx) with match (typ_of ptr, typ_of idx) with
@ -285,6 +294,7 @@ let mkPtrIdx ~ptr ~idx =
| _ -> false ) ; | _ -> false ) ;
mkApp2 PtrIdx ptr idx mkApp2 PtrIdx ptr idx
let mkPrjFld ~agg ~fld = let mkPrjFld ~agg ~fld =
assert ( assert (
match typ_of agg with match typ_of agg with
@ -292,6 +302,7 @@ let mkPrjFld ~agg ~fld =
| _ -> false ) ; | _ -> false ) ;
mkApp1 (PrjFld {fld}) agg mkApp1 (PrjFld {fld}) agg
let mkPrjIdx ~arr ~idx = let mkPrjIdx ~arr ~idx =
assert ( assert (
match (typ_of arr, typ_of idx) with match (typ_of arr, typ_of idx) with
@ -299,6 +310,7 @@ let mkPrjIdx ~arr ~idx =
| _ -> false ) ; | _ -> false ) ;
mkApp2 PrjIdx arr idx mkApp2 PrjIdx arr idx
let mkUpdFld ~agg ~elt ~fld = let mkUpdFld ~agg ~elt ~fld =
assert ( assert (
match typ_of agg with match typ_of agg with
@ -307,6 +319,7 @@ let mkUpdFld ~agg ~elt ~fld =
| _ -> false ) ; | _ -> false ) ;
mkApp2 (UpdFld {fld}) agg elt mkApp2 (UpdFld {fld}) agg elt
let mkUpdIdx ~arr ~elt ~idx = let mkUpdIdx ~arr ~elt ~idx =
assert ( assert (
match (typ_of arr, typ_of idx) with match (typ_of arr, typ_of idx) with
@ -314,6 +327,7 @@ let mkUpdIdx ~arr ~elt ~idx =
| _ -> false ) ; | _ -> false ) ;
mkApp3 UpdIdx arr elt idx mkApp3 UpdIdx arr elt idx
let mkInteger data (typ : Typ.t) = let mkInteger data (typ : Typ.t) =
assert ( assert (
let in_range num bits = let in_range num bits =
@ -324,12 +338,14 @@ let mkInteger data (typ : Typ.t) =
match typ with Integer {bits} -> in_range data bits | _ -> false ) ; match typ with Integer {bits} -> in_range data bits | _ -> false ) ;
Integer {data; typ} Integer {data; typ}
let mkBool b = mkInteger (Z.of_int (Bool.to_int b)) Typ.i1 let mkBool b = mkInteger (Z.of_int (Bool.to_int b)) Typ.i1
let mkFloat data (typ : Typ.t) = let mkFloat data (typ : Typ.t) =
assert (match typ with Float _ -> true | _ -> false) ; assert (match typ with Float _ -> true | _ -> false) ;
Float {data; typ} Float {data; typ}
let mkArray elts (typ : Typ.t) = let mkArray elts (typ : Typ.t) =
assert ( assert (
match typ with match typ with
@ -339,6 +355,7 @@ let mkArray elts (typ : Typ.t) =
| _ -> false ) ; | _ -> false ) ;
mkAppN (Array {typ}) elts mkAppN (Array {typ}) elts
let mkStruct elts (typ : Typ.t) = let mkStruct elts (typ : Typ.t) =
assert ( assert (
match typ with match typ with
@ -348,6 +365,7 @@ let mkStruct elts (typ : Typ.t) =
| _ -> false ) ; | _ -> false ) ;
mkAppN (Struct {typ}) elts mkAppN (Struct {typ}) elts
let mkStruct_rec key = let mkStruct_rec key =
let memo_id = Hashtbl.create key () in let memo_id = Hashtbl.create key () in
let dummy = Null {typ= Typ.mkBytes} in let dummy = Null {typ= Typ.mkBytes} in
@ -373,14 +391,17 @@ let mkStruct_rec key =
in in
Staged.stage mkStruct_ Staged.stage mkStruct_
let mkCast exp typ = let mkCast exp typ =
assert (Typ.compatible (typ_of exp) typ) ; assert (Typ.compatible (typ_of exp) typ) ;
mkApp1 (Cast {typ}) exp mkApp1 (Cast {typ}) exp
let mkConv exp ?(signed = false) typ = let mkConv exp ?(signed = false) typ =
assert (Typ.compatible (typ_of exp) typ) ; assert (Typ.compatible (typ_of exp) typ) ;
mkApp1 (Conv {signed; typ}) exp mkApp1 (Conv {signed; typ}) exp
let mkSelect ~cnd ~thn ~els = let mkSelect ~cnd ~thn ~els =
assert ( assert (
match (typ_of cnd, typ_of thn, typ_of els) with match (typ_of cnd, typ_of thn, typ_of els) with
@ -390,6 +411,7 @@ let mkSelect ~cnd ~thn ~els =
| _ -> false ) ; | _ -> false ) ;
mkApp3 Select cnd thn els mkApp3 Select cnd thn els
let binop op x y = let binop op x y =
assertf assertf
(let typ = typ_of x in (let typ = typ_of x in
@ -404,6 +426,7 @@ let binop op x y =
"ill-typed: %a" fmt (mkApp2 op x y) () ; "ill-typed: %a" fmt (mkApp2 op x y) () ;
mkApp2 op x y mkApp2 op x y
let mkEq = binop Eq let mkEq = binop Eq
let mkNe = binop Ne let mkNe = binop Ne

@ -14,6 +14,7 @@ let fmt_llvalue ff t = Format.pp_print_string ff (Llvm.string_of_llvalue t)
let fmt_llblock ff t = let fmt_llblock ff t =
Format.pp_print_string ff (Llvm.string_of_llvalue (Llvm.value_of_block t)) Format.pp_print_string ff (Llvm.string_of_llvalue (Llvm.value_of_block t))
(* gather debug locations *) (* gather debug locations *)
let (scan_locs : Llvm.llmodule -> unit), (find_loc : Llvm.llvalue -> Loc.t) let (scan_locs : Llvm.llmodule -> unit), (find_loc : Llvm.llvalue -> Loc.t)
= =
@ -81,6 +82,7 @@ let (scan_locs : Llvm.llmodule -> unit), (find_loc : Llvm.llvalue -> Loc.t)
in in
(scan_locs, find_loc) (scan_locs, find_loc)
let ( (scan_names : Llvm.llmodule -> unit) let ( (scan_names : Llvm.llmodule -> unit)
, (find_name : Llvm.llvalue -> string) ) = , (find_name : Llvm.llvalue -> string) ) =
let name_tbl = Hashtbl.Poly.create () in let name_tbl = Hashtbl.Poly.create () in
@ -156,12 +158,15 @@ let ( (scan_names : Llvm.llmodule -> unit)
let find_name v = Hashtbl.find_exn name_tbl v in let find_name v = Hashtbl.find_exn name_tbl v in
(scan_names, find_name) (scan_names, find_name)
let label_of_block : Llvm.llbasicblock -> string = let label_of_block : Llvm.llbasicblock -> string =
fun blk -> find_name (Llvm.value_of_block blk) fun blk -> find_name (Llvm.value_of_block blk)
let anon_struct_name : (Llvm.lltype, string) Hashtbl.t = let anon_struct_name : (Llvm.lltype, string) Hashtbl.t =
Hashtbl.Poly.create () Hashtbl.Poly.create ()
let struct_name : Llvm.lltype -> string = let struct_name : Llvm.lltype -> string =
fun llt -> fun llt ->
match Llvm.struct_name llt with match Llvm.struct_name llt with
@ -170,6 +175,7 @@ let struct_name : Llvm.lltype -> string =
Hashtbl.find_or_add anon_struct_name llt ~default:(fun () -> Hashtbl.find_or_add anon_struct_name llt ~default:(fun () ->
Int.to_string (Hashtbl.length anon_struct_name) ) Int.to_string (Hashtbl.length anon_struct_name) )
let memo_type : (Llvm.lltype, Typ.t) Hashtbl.t = Hashtbl.Poly.create () let memo_type : (Llvm.lltype, Typ.t) Hashtbl.t = Hashtbl.Poly.create ()
let rec xlate_type : Llvm.lltype -> Typ.t = let rec xlate_type : Llvm.lltype -> Typ.t =
@ -226,12 +232,14 @@ let rec xlate_type : Llvm.lltype -> Typ.t =
|> |>
[%Trace.retn fun pf -> pf "%a" Typ.fmt_defn] ) [%Trace.retn fun pf -> pf "%a" Typ.fmt_defn] )
and xlate_type_opt : Llvm.lltype -> Typ.t option = and xlate_type_opt : Llvm.lltype -> Typ.t option =
fun llt -> fun llt ->
match Llvm.classify_type llt with match Llvm.classify_type llt with
| Void -> None | Void -> None
| _ -> Some (xlate_type llt) | _ -> Some (xlate_type llt)
let rec is_zero : Exp.t -> bool = let rec is_zero : Exp.t -> bool =
fun exp -> fun exp ->
match exp with match exp with
@ -241,9 +249,11 @@ let rec is_zero : Exp.t -> bool =
| App {op; arg} -> is_zero op && is_zero arg | App {op; arg} -> is_zero op && is_zero arg
| _ -> false | _ -> false
let suffix_after_space : string -> string = let suffix_after_space : string -> string =
fun str -> String.slice str (String.rindex_exn str ' ' + 1) 0 fun str -> String.slice str (String.rindex_exn str ' ' + 1) 0
let xlate_int : Llvm.llvalue -> Exp.t = let xlate_int : Llvm.llvalue -> Exp.t =
fun llv -> fun llv ->
let typ = xlate_type (Llvm.type_of llv) in let typ = xlate_type (Llvm.type_of llv) in
@ -254,12 +264,14 @@ let xlate_int : Llvm.llvalue -> Exp.t =
in in
Exp.mkInteger data typ Exp.mkInteger data typ
let xlate_float : Llvm.llvalue -> Exp.t = let xlate_float : Llvm.llvalue -> Exp.t =
fun llv -> fun llv ->
let typ = xlate_type (Llvm.type_of llv) in let typ = xlate_type (Llvm.type_of llv) in
let data = suffix_after_space (Llvm.string_of_llvalue llv) in let data = suffix_after_space (Llvm.string_of_llvalue llv) in
Exp.mkFloat data typ Exp.mkFloat data typ
let xlate_name_opt : Llvm.llvalue -> Var.t option = let xlate_name_opt : Llvm.llvalue -> Var.t option =
fun instr -> fun instr ->
Option.map Option.map
@ -269,9 +281,11 @@ let xlate_name_opt : Llvm.llvalue -> Var.t option =
let loc = find_loc instr in let loc = find_loc instr in
Var.mk name typ ~loc ) Var.mk name typ ~loc )
let xlate_name : Llvm.llvalue -> Var.t = let xlate_name : Llvm.llvalue -> Var.t =
fun instr -> Option.value_exn (xlate_name_opt instr) fun instr -> Option.value_exn (xlate_name_opt instr)
let xlate_intrinsic_exp : string -> (Exp.t -> Exp.t) option = let xlate_intrinsic_exp : string -> (Exp.t -> Exp.t) option =
fun name -> fun name ->
let i32 = Typ.mkInteger ~bits:32 in let i32 = Typ.mkInteger ~bits:32 in
@ -279,6 +293,7 @@ let xlate_intrinsic_exp : string -> (Exp.t -> Exp.t) option =
| "llvm.eh.typeid.for" -> Some (fun arg -> Exp.mkCast arg i32) | "llvm.eh.typeid.for" -> Some (fun arg -> Exp.mkCast arg i32)
| _ -> None | _ -> None
let memo_value : (Llvm.llvalue, Exp.t) Hashtbl.t = Hashtbl.Poly.create () let memo_value : (Llvm.llvalue, Exp.t) Hashtbl.t = Hashtbl.Poly.create ()
module Llvalue = struct module Llvalue = struct
@ -368,6 +383,7 @@ let rec xlate_value : Llvm.llvalue -> Exp.t =
typ' fmt_llvalue llv () ; typ' fmt_llvalue llv () ;
pf "%a" Exp.fmt exp] ) pf "%a" Exp.fmt exp] )
and xlate_opcode : Llvm.llvalue -> Llvm.Opcode.t -> Exp.t = and xlate_opcode : Llvm.llvalue -> Llvm.Opcode.t -> Exp.t =
fun llv opcode -> fun llv opcode ->
[%Trace.call fun pf -> pf "%a" fmt_llvalue llv] [%Trace.call fun pf -> pf "%a" fmt_llvalue llv]
@ -529,6 +545,7 @@ and xlate_opcode : Llvm.llvalue -> Llvm.Opcode.t -> Exp.t =
fmt_llvalue llv () ; fmt_llvalue llv () ;
pf "%a" Exp.fmt exp] pf "%a" Exp.fmt exp]
and xlate_global : Llvm.llvalue -> Global.t = and xlate_global : Llvm.llvalue -> Global.t =
fun llg -> fun llg ->
let init = let init =
@ -540,6 +557,7 @@ and xlate_global : Llvm.llvalue -> Global.t =
let g = xlate_name llg in let g = xlate_name llg in
Global.mk (Var.name g) (Var.typ g) ~loc:(Var.loc g) ?init Global.mk (Var.name g) (Var.typ g) ~loc:(Var.loc g) ?init
let xlate_global : Llvm.llvalue -> Global.t = let xlate_global : Llvm.llvalue -> Global.t =
fun llg -> fun llg ->
[%Trace.call fun pf -> pf "%a" fmt_llvalue llg] [%Trace.call fun pf -> pf "%a" fmt_llvalue llg]
@ -548,6 +566,7 @@ let xlate_global : Llvm.llvalue -> Global.t =
|> |>
[%Trace.retn fun pf -> pf "%a" Global.fmt] [%Trace.retn fun pf -> pf "%a" Global.fmt]
type pop_thunk = Loc.t -> Llair.inst list type pop_thunk = Loc.t -> Llair.inst list
let pop_stack_frame_of_function : let pop_stack_frame_of_function :
@ -580,6 +599,7 @@ let pop_stack_frame_of_function :
in in
pop pop
(** construct the types involved in landingpads: i32, std::type_info*, and (** construct the types involved in landingpads: i32, std::type_info*, and
__cxa_exception *) __cxa_exception *)
let landingpad_typs : Llvm.llvalue -> Typ.t * Typ.t * Typ.t = let landingpad_typs : Llvm.llvalue -> Typ.t * Typ.t * Typ.t =
@ -607,12 +627,14 @@ let landingpad_typs : Llvm.llvalue -> Typ.t * Typ.t * Typ.t =
let cxa_exception = Llvm.struct_type llcontext [|tip; dtor|] in let cxa_exception = Llvm.struct_type llcontext [|tip; dtor|] in
(i32, xlate_type tip, xlate_type cxa_exception) (i32, xlate_type tip, xlate_type cxa_exception)
(** construct the argument of a landingpad block, mainly fix the encoding (** construct the argument of a landingpad block, mainly fix the encoding
scheme for landingpad instruction name to block arg name *) scheme for landingpad instruction name to block arg name *)
let landingpad_arg : Llvm.llvalue -> Var.t = let landingpad_arg : Llvm.llvalue -> Var.t =
fun instr -> fun instr ->
Var.mk (find_name instr ^ ".exc") Typ.i8p ~loc:(find_loc instr) Var.mk (find_name instr ^ ".exc") Typ.i8p ~loc:(find_loc instr)
(** [rev_map_phis ~f blk] returns [(retn_arg, rev_args, pos)] by rev_mapping (** [rev_map_phis ~f blk] returns [(retn_arg, rev_args, pos)] by rev_mapping
over the prefix of [PHI] instructions at the beginning of [blk]. over the prefix of [PHI] instructions at the beginning of [blk].
[retn_arg], if any, is [f] applied to the [PHI] instruction which takes [retn_arg], if any, is [f] applied to the [PHI] instruction which takes
@ -669,6 +691,7 @@ let rev_map_phis :
in in
block_args_ false None [] (Llvm.instr_begin blk) block_args_ false None [] (Llvm.instr_begin blk)
(** [trampoline_args jump_instr dest_block] is the actual arguments to which (** [trampoline_args jump_instr dest_block] is the actual arguments to which
the translation of [dest_block] should be partially-applied, to yield a the translation of [dest_block] should be partially-applied, to yield a
trampoline accepting the return parameter of the block and then jumping trampoline accepting the return parameter of the block and then jumping
@ -681,6 +704,7 @@ let trampoline_args : Llvm.llvalue -> Llvm.llbasicblock -> Exp.t vector =
if Poly.equal pred src then Some (xlate_value arg) else None ) ) if Poly.equal pred src then Some (xlate_value arg) else None ) )
|> snd3 |> Vector.of_list_rev |> snd3 |> Vector.of_list_rev
(** [unique_pred blk] is the unique predecessor of [blk], or [None] if there (** [unique_pred blk] is the unique predecessor of [blk], or [None] if there
are 0 or >1 predecessors. *) are 0 or >1 predecessors. *)
let unique_pred : Llvm.llbasicblock -> Llvm.llvalue option = let unique_pred : Llvm.llbasicblock -> Llvm.llvalue option =
@ -692,11 +716,13 @@ let unique_pred : Llvm.llbasicblock -> Llvm.llvalue option =
| Some _ -> None ) | Some _ -> None )
| None -> None | None -> None
(** [return_formal_is_used instr] holds if the return value of [instr] is (** [return_formal_is_used instr] holds if the return value of [instr] is
used anywhere. *) used anywhere. *)
let return_formal_is_used : Llvm.llvalue -> bool = let return_formal_is_used : Llvm.llvalue -> bool =
fun instr -> Option.is_some (Llvm.use_begin instr) fun instr -> Option.is_some (Llvm.use_begin instr)
(** [need_return_trampoline instr blk] holds when the return formal of (** [need_return_trampoline instr blk] holds when the return formal of
[instr] is used, but the returned to block [blk] does not take it as an [instr] is used, but the returned to block [blk] does not take it as an
argument (e.g. if it has multiple predecessors and no PHI node). *) argument (e.g. if it has multiple predecessors and no PHI node). *)
@ -706,6 +732,7 @@ let need_return_trampoline : Llvm.llvalue -> Llvm.llbasicblock -> bool =
&& Option.is_none (unique_pred blk) && Option.is_none (unique_pred blk)
&& return_formal_is_used instr && return_formal_is_used instr
(** [unique_used_invoke_pred blk] is the unique predecessor of [blk], if it (** [unique_used_invoke_pred blk] is the unique predecessor of [blk], if it
is an [Invoke] instruction, whose return value is used. *) is an [Invoke] instruction, whose return value is used. *)
let unique_used_invoke_pred : Llvm.llbasicblock -> 'a option = let unique_used_invoke_pred : Llvm.llbasicblock -> 'a option =
@ -716,6 +743,7 @@ let unique_used_invoke_pred : Llvm.llbasicblock -> 'a option =
Some instr Some instr
| _ -> None | _ -> None
(** formal parameters accepted by a block *) (** formal parameters accepted by a block *)
let block_formals : Llvm.llbasicblock -> Var.t list * _ Llvm.llpos = let block_formals : Llvm.llbasicblock -> Var.t list * _ Llvm.llpos =
fun blk -> fun blk ->
@ -734,6 +762,7 @@ let block_formals : Llvm.llbasicblock -> Var.t list * _ Llvm.llpos =
(List.rev_append rev_args (Option.to_list instr_arg), pos) (List.rev_append rev_args (Option.to_list instr_arg), pos)
| At_end blk -> fail "block_formals: %a" fmt_llblock blk () | At_end blk -> fail "block_formals: %a" fmt_llblock blk ()
(** actual arguments passed by a jump to a block *) (** actual arguments passed by a jump to a block *)
let jump_args : Llvm.llvalue -> Llvm.llbasicblock -> Exp.t vector = let jump_args : Llvm.llvalue -> Llvm.llbasicblock -> Exp.t vector =
fun jmp dst -> fun jmp dst ->
@ -752,6 +781,7 @@ let jump_args : Llvm.llvalue -> Llvm.llbasicblock -> Exp.t vector =
in in
Vector.of_list (List.rev_append rev_args (Option.to_list retn_arg)) Vector.of_list (List.rev_append rev_args (Option.to_list retn_arg))
(** An LLVM instruction is translated to a sequence of LLAIR instructions (** An LLVM instruction is translated to a sequence of LLAIR instructions
and a terminator, plus some additional blocks to which it may refer and a terminator, plus some additional blocks to which it may refer
(that is, essentially a function body). These are needed since LLVM and (that is, essentially a function body). These are needed since LLVM and
@ -774,6 +804,7 @@ let fmt_code ff (insts, term, blocks) =
(list_fmt "@ " Llair.Block.fmt) (list_fmt "@ " Llair.Block.fmt)
blocks blocks
let rec xlate_func_name llv = let rec xlate_func_name llv =
match Llvm.classify_value llv with match Llvm.classify_value llv with
| Function -> | Function ->
@ -788,6 +819,7 @@ let rec xlate_func_name llv =
| InlineAsm -> todo "inline asm: %a" fmt_llvalue llv () | InlineAsm -> todo "inline asm: %a" fmt_llvalue llv ()
| _ -> fail "unknown function: %a" fmt_llvalue llv () | _ -> fail "unknown function: %a" fmt_llvalue llv ()
let xlate_instr : let xlate_instr :
pop_thunk pop_thunk
-> Llvm.llvalue -> Llvm.llvalue
@ -1173,6 +1205,7 @@ let xlate_instr :
fail "xlate_instr: %a" fmt_llvalue instr () fail "xlate_instr: %a" fmt_llvalue instr ()
| PHI | Invalid | Invalid2 | UserOp1 | UserOp2 -> assert false | PHI | Invalid | Invalid2 | UserOp1 | UserOp2 -> assert false
let rec xlate_instrs : pop_thunk -> _ Llvm.llpos -> code = let rec xlate_instrs : pop_thunk -> _ Llvm.llpos -> code =
fun pop -> function fun pop -> function
| Before instrI -> | Before instrI ->
@ -1183,6 +1216,7 @@ let rec xlate_instrs : pop_thunk -> _ Llvm.llpos -> code =
(instsI, termI, blocksI @ blocksJN) ) (instsI, termI, blocksI @ blocksJN) )
| At_end blk -> fail "xlate_instrs: %a" fmt_llblock blk () | At_end blk -> fail "xlate_instrs: %a" fmt_llblock blk ()
let xlate_block : pop_thunk -> Llvm.llbasicblock -> Llair.block list = let xlate_block : pop_thunk -> Llvm.llbasicblock -> Llair.block list =
fun pop blk -> fun pop blk ->
[%Trace.call fun pf -> pf "%a" fmt_llblock blk] [%Trace.call fun pf -> pf "%a" fmt_llblock blk]
@ -1196,6 +1230,7 @@ let xlate_block : pop_thunk -> Llvm.llbasicblock -> Llair.block list =
|> |>
[%Trace.retn fun pf blocks -> pf "%s" (List.hd_exn blocks).Llair.lbl] [%Trace.retn fun pf blocks -> pf "%s" (List.hd_exn blocks).Llair.lbl]
let xlate_function : Llvm.llvalue -> Llair.func = let xlate_function : Llvm.llvalue -> Llair.func =
fun llf -> fun llf ->
[%Trace.call fun pf -> pf "%a" fmt_llvalue llf] [%Trace.call fun pf -> pf "%a" fmt_llvalue llf]
@ -1234,6 +1269,7 @@ let xlate_function : Llvm.llvalue -> Llair.func =
|> |>
[%Trace.retn fun pf -> pf "@\n%a" Llair.Func.fmt] [%Trace.retn fun pf -> pf "@\n%a" Llair.Func.fmt]
let transform : Llvm.llmodule -> unit = let transform : Llvm.llmodule -> unit =
fun llmodule -> fun llmodule ->
let pm = Llvm.PassManager.create () in let pm = Llvm.PassManager.create () in
@ -1245,6 +1281,7 @@ let transform : Llvm.llmodule -> unit =
Llvm.PassManager.run_module llmodule pm |> (ignore : bool -> _) ; Llvm.PassManager.run_module llmodule pm |> (ignore : bool -> _) ;
Llvm.PassManager.dispose pm Llvm.PassManager.dispose pm
exception Invalid_llvm of string exception Invalid_llvm of string
let invalid_llvm : string -> 'a = let invalid_llvm : string -> 'a =
@ -1256,6 +1293,7 @@ let invalid_llvm : string -> 'a =
Format.printf "@\n%s@\n" msg ; Format.printf "@\n%s@\n" msg ;
raise (Invalid_llvm first_line) raise (Invalid_llvm first_line)
let translate : string -> Llair.t = let translate : string -> Llair.t =
fun file -> fun file ->
[%Trace.call fun pf -> pf "%s" file] [%Trace.call fun pf -> pf "%s" file]

@ -66,9 +66,11 @@ let rec dummy_block =
; parent= dummy_func ; parent= dummy_func
; sort_index= 0 } ; sort_index= 0 }
and dummy_func = and dummy_func =
{name= Global.mk "dummy" Typ.i8p; entry= dummy_block; cfg= Vector.empty} {name= Global.mk "dummy" Typ.i8p; entry= dummy_block; cfg= Vector.empty}
module Inst = struct module Inst = struct
type t = inst type t = inst
@ -79,6 +81,7 @@ module Inst = struct
| _ -> false ) ; | _ -> false ) ;
Load {reg; ptr; loc} Load {reg; ptr; loc}
let mkStore ~ptr ~exp ~loc = let mkStore ~ptr ~exp ~loc =
assert ( assert (
match Exp.typ ptr with match Exp.typ ptr with
@ -86,6 +89,7 @@ module Inst = struct
| _ -> false ) ; | _ -> false ) ;
Store {ptr; exp; loc} Store {ptr; exp; loc}
let mkMemcpy ~dst ~src ~len ~loc = let mkMemcpy ~dst ~src ~len ~loc =
assert ( assert (
match (Exp.typ dst, Exp.typ src, Exp.typ len) with match (Exp.typ dst, Exp.typ src, Exp.typ len) with
@ -94,6 +98,7 @@ module Inst = struct
| _ -> false ) ; | _ -> false ) ;
Memcpy {dst; src; len; loc} Memcpy {dst; src; len; loc}
let mkMemmov ~dst ~src ~len ~loc = let mkMemmov ~dst ~src ~len ~loc =
assert ( assert (
match (Exp.typ dst, Exp.typ src, Exp.typ len) with match (Exp.typ dst, Exp.typ src, Exp.typ len) with
@ -102,6 +107,7 @@ module Inst = struct
| _ -> false ) ; | _ -> false ) ;
Memmov {dst; src; len; loc} Memmov {dst; src; len; loc}
let mkMemset ~dst ~byt ~len ~loc = let mkMemset ~dst ~byt ~len ~loc =
assert ( assert (
match (Exp.typ dst, Exp.typ byt, Exp.typ len) with match (Exp.typ dst, Exp.typ byt, Exp.typ len) with
@ -109,6 +115,7 @@ module Inst = struct
| _ -> false ) ; | _ -> false ) ;
Memset {dst; byt; len; loc} Memset {dst; byt; len; loc}
let mkAlloc ~reg ~num ~loc = let mkAlloc ~reg ~num ~loc =
assert ( assert (
match (Var.typ reg, Exp.typ num) with match (Var.typ reg, Exp.typ num) with
@ -116,6 +123,7 @@ module Inst = struct
| _ -> false ) ; | _ -> false ) ;
Alloc {reg; num; loc} Alloc {reg; num; loc}
let mkFree ~ptr ~loc = let mkFree ~ptr ~loc =
assert ( assert (
match Exp.typ ptr with match Exp.typ ptr with
@ -123,10 +131,12 @@ module Inst = struct
| _ -> false ) ; | _ -> false ) ;
Free {ptr; loc} Free {ptr; loc}
let mkNondet ~reg ~msg ~loc = let mkNondet ~reg ~msg ~loc =
assert (Option.for_all ~f:(Var.typ >> Typ.is_sized) reg) ; assert (Option.for_all ~f:(Var.typ >> Typ.is_sized) reg) ;
Nondet {reg; msg; loc} Nondet {reg; msg; loc}
let fmt ff inst = let fmt ff inst =
let pf fmt = Format.fprintf ff fmt in let pf fmt = Format.fprintf ff fmt in
match inst with match inst with
@ -151,9 +161,11 @@ let fmt_cmnd = vector_fmt "@ " Inst.fmt
let fmt_args fmt_arg ff args = let fmt_args fmt_arg ff args =
Format.fprintf ff "@ (@[%a@])" (vector_fmt ",@ " fmt_arg) args Format.fprintf ff "@ (@[%a@])" (vector_fmt ",@ " fmt_arg) args
let fmt_param ff var = let fmt_param ff var =
Format.fprintf ff "%a %a" Typ.fmt (Var.typ var) Var.fmt var Format.fprintf ff "%a %a" Typ.fmt (Var.typ var) Var.fmt var
module Jump = struct module Jump = struct
type t = jump type t = jump
@ -172,6 +184,7 @@ module Term = struct
assert (match Exp.typ key with Integer _ -> true | _ -> false) ; assert (match Exp.typ key with Integer _ -> true | _ -> false) ;
Switch {key; tbl; els; loc} Switch {key; tbl; els; loc}
let mkISwitch ~ptr ~tbl ~loc = let mkISwitch ~ptr ~tbl ~loc =
assert ( assert (
match Exp.typ ptr with match Exp.typ ptr with
@ -179,6 +192,7 @@ module Term = struct
| _ -> false ) ; | _ -> false ) ;
ISwitch {ptr; tbl; loc} ISwitch {ptr; tbl; loc}
let mkCall ~func ~args ~return ~throw ~ignore_result ~loc = let mkCall ~func ~args ~return ~throw ~ignore_result ~loc =
assert ( assert (
match Exp.typ func with match Exp.typ func with
@ -193,6 +207,7 @@ module Term = struct
; ignore_result ; ignore_result
; loc } ; loc }
let mkReturn ~exp ~loc = Return {exp; loc} let mkReturn ~exp ~loc = Return {exp; loc}
let mkThrow ~exc ~loc = Throw {exc; loc} let mkThrow ~exc ~loc = Throw {exc; loc}
@ -239,6 +254,7 @@ module Block = struct
) ; ) ;
{dummy_block with lbl; params; cmnd; term} {dummy_block with lbl; params; cmnd; term}
(* blocks in a [t] are uniquely identified by [sort_index] *) (* blocks in a [t] are uniquely identified by [sort_index] *)
let compare x y = Int.compare x.sort_index y.sort_index let compare x y = Int.compare x.sort_index y.sort_index
@ -257,15 +273,18 @@ module Func = struct
let find functions func = let find functions func =
Vector.find functions ~f:(fun {name} -> Global.equal func name) Vector.find functions ~f:(fun {name} -> Global.equal func name)
let is_undefined = function let is_undefined = function
| {entry= {cmnd; term= Unreachable}} -> Vector.is_empty cmnd | {entry= {cmnd; term= Unreachable}} -> Vector.is_empty cmnd
| _ -> false | _ -> false
let fold_term {entry; cfg} ~init ~f = let fold_term {entry; cfg} ~init ~f =
let fold_block {term} ~init ~f = f init term in let fold_block {term} ~init ~f = f init term in
Vector.fold cfg ~init:(fold_block entry ~init ~f) ~f:(fun z k -> Vector.fold cfg ~init:(fold_block entry ~init ~f) ~f:(fun z k ->
fold_block k ~init:z ~f ) fold_block k ~init:z ~f )
let mk ~name ~entry ~cfg = let mk ~name ~entry ~cfg =
let func = {name; entry; cfg} in let func = {name; entry; cfg} in
let resolve_parent_and_jumps block = let resolve_parent_and_jumps block =
@ -330,6 +349,7 @@ module Func = struct
true ) ; true ) ;
func func
let mk_undefined ~name ~params = let mk_undefined ~name ~params =
let entry = let entry =
Block.mk ~lbl:"" ~params ~cmnd:Vector.empty ~term:Term.mkUnreachable Block.mk ~lbl:"" ~params ~cmnd:Vector.empty ~term:Term.mkUnreachable
@ -337,6 +357,7 @@ module Func = struct
let cfg = Vector.empty in let cfg = Vector.empty in
mk ~name ~entry ~cfg mk ~name ~entry ~cfg
let fmt ff ({name; entry= {params; cmnd; term; sort_index}; cfg} as func) let fmt ff ({name; entry= {params; cmnd; term; sort_index}; cfg} as func)
= =
let fmt_if cnd str ff = if cnd then Format.fprintf ff str in let fmt_if cnd str ff = if cnd then Format.fprintf ff str in
@ -363,6 +384,7 @@ module Block_id = struct
[%compare: string * Global.t] (x.lbl, x.parent.name) [%compare: string * Global.t] (x.lbl, x.parent.name)
(y.lbl, y.parent.name) (y.lbl, y.parent.name)
let hash b = Hashtbl.hash (b.lbl, b.parent.name) let hash b = Hashtbl.hash (b.lbl, b.parent.name)
end end
@ -442,6 +464,7 @@ let set_derived_metadata functions =
sort_functions functions ; sort_functions functions ;
Vector.of_array functions Vector.of_array functions
let mk ~typ_defns ~globals ~functions = let mk ~typ_defns ~globals ~functions =
assert ( assert (
(not (not
@ -462,6 +485,7 @@ let mk ~typ_defns ~globals ~functions =
; globals= Vector.of_list_rev globals ; globals= Vector.of_list_rev globals
; functions= set_derived_metadata functions } ; functions= set_derived_metadata functions }
let fmt ff {typ_defns; globals; functions} = let fmt ff {typ_defns; globals; functions} =
Format.fprintf ff "@[<v>@[%a@]@ @ @ @[%a@]@ @ @ @[%a@]@]" Format.fprintf ff "@[<v>@[%a@]@ @ @ @[%a@]@ @ @ @[%a@]@]"
(list_fmt "@\n@\n" Typ.fmt_defn) (list_fmt "@\n@\n" Typ.fmt_defn)

@ -15,6 +15,7 @@ let none = {dir= ""; file= ""; line= 0; col= 0}
let mk ?(dir = none.dir) ?(file = none.file) ?(col = none.col) ~line = let mk ?(dir = none.dir) ?(file = none.file) ?(col = none.col) ~line =
{dir; file; line; col} {dir; file; line; col}
let fmt ff {dir; file; line; col} = let fmt ff {dir; file; line; col} =
Format.pp_print_string ff dir ; Format.pp_print_string ff dir ;
if not (String.is_empty dir) then if not (String.is_empty dir) then

@ -45,6 +45,7 @@ let rec fmt ff typ =
| Struct {name} | Opaque {name} -> Format.fprintf ff "@[%%%s@]" name | Struct {name} | Opaque {name} -> Format.fprintf ff "@[%%%s@]" name
| Bytes -> Format.fprintf ff "bytes" | Bytes -> Format.fprintf ff "bytes"
and fmts ff typs = vector_fmt ",@ " fmt ff typs and fmts ff typs = vector_fmt ",@ " fmt ff typs
let fmt_defn ff = function let fmt_defn ff = function
@ -54,6 +55,7 @@ let fmt_defn ff = function
| Opaque {name} -> Format.fprintf ff "@[<2>%%%s =@ opaque@]" name | Opaque {name} -> Format.fprintf ff "@[<2>%%%s =@ opaque@]" name
| typ -> fmt ff typ | typ -> fmt ff typ
let is_sized = function let is_sized = function
| Function _ | Bytes -> false | Function _ | Bytes -> false
| Integer _ | Float _ | Pointer _ | Array _ | Tuple _ | Struct _ -> true | Integer _ | Float _ | Pointer _ | Array _ | Tuple _ | Struct _ -> true
@ -62,12 +64,14 @@ let is_sized = function
as they are not sized but may become sized through linking. *) as they are not sized but may become sized through linking. *)
true true
let rec prim_bit_size_of = function let rec prim_bit_size_of = function
| Integer {bits} | Float {bits} -> Some bits | Integer {bits} | Float {bits} -> Some bits
| Array {elt; len} -> | Array {elt; len} ->
Option.map (prim_bit_size_of elt) ~f:(fun n -> n * len) Option.map (prim_bit_size_of elt) ~f:(fun n -> n * len)
| Opaque _ | Function _ | Pointer _ | Tuple _ | Struct _ | Bytes -> None | Opaque _ | Function _ | Pointer _ | Tuple _ | Struct _ | Bytes -> None
let rec compatible t0 t1 = let rec compatible t0 t1 =
match (t0, t1, prim_bit_size_of t0, prim_bit_size_of t1) with match (t0, t1, prim_bit_size_of t0, prim_bit_size_of t1) with
| ( (Integer _ | Float _ | Pointer _) | ( (Integer _ | Float _ | Pointer _)
@ -86,11 +90,13 @@ let rec compatible t0 t1 =
true true
| _ -> false | _ -> false
let mkFunction ~return ~args = let mkFunction ~return ~args =
assert ( assert (
Option.for_all ~f:is_sized return && Vector.for_all ~f:is_sized args ) ; Option.for_all ~f:is_sized return && Vector.for_all ~f:is_sized args ) ;
Function {return; args} Function {return; args}
let mkInteger ~bits = Integer {bits} let mkInteger ~bits = Integer {bits}
let mkFloat ~bits ~enc = Float {bits; enc} let mkFloat ~bits ~enc = Float {bits; enc}
@ -101,12 +107,14 @@ let mkArray ~elt ~len =
assert (is_sized elt) ; assert (is_sized elt) ;
Array {elt; len} Array {elt; len}
let defns : (string, t) Hashtbl.t = Hashtbl.create (module String) () let defns : (string, t) Hashtbl.t = Hashtbl.create (module String) ()
let mkTuple ~packed elts = let mkTuple ~packed elts =
assert (Vector.for_all ~f:is_sized elts) ; assert (Vector.for_all ~f:is_sized elts) ;
Tuple {elts; packed} Tuple {elts; packed}
let mkStruct ~name ~packed elt_thks = let mkStruct ~name ~packed elt_thks =
match Hashtbl.find defns name with match Hashtbl.find defns name with
| Some typ -> typ | Some typ -> typ
@ -124,6 +132,7 @@ let mkStruct ~name ~packed elt_thks =
elts.(i) <- elt ) ; elts.(i) <- elt ) ;
typ typ
let mkOpaque ~name = Opaque {name} let mkOpaque ~name = Opaque {name}
let mkBytes = Bytes let mkBytes = Bytes

@ -54,6 +54,7 @@ let rec get_fun_name pat =
(Selected_ast.To_ocaml.copy_pattern p) ) (Selected_ast.To_ocaml.copy_pattern p) )
pat pat
let vb_stack_with, vb_stack_top = let vb_stack_with, vb_stack_top =
let stack = ref [] in let stack = ref [] in
let with_ x ~f = let with_ x ~f =
@ -65,6 +66,7 @@ let vb_stack_with, vb_stack_top =
let top () = List.hd_exn !stack in let top () = List.hd_exn !stack in
(with_, top) (with_, top)
let mapper = let mapper =
let value_binding (m : Ast_mapper.mapper) vb = let value_binding (m : Ast_mapper.mapper) vb =
vb_stack_with vb.pvb_pat ~f:(fun () -> vb_stack_with vb.pvb_pat ~f:(fun () ->
@ -113,6 +115,7 @@ let mapper =
in in
{Ast_mapper.default_mapper with expr; value_binding} {Ast_mapper.default_mapper with expr; value_binding}
let impl = Selected_ast.Ast.map_structure mapper let impl = Selected_ast.Ast.map_structure mapper
;; ;;

@ -32,5 +32,6 @@ let main ~input ~output =
(Caml.Printexc.to_string exn) ) ; (Caml.Printexc.to_string exn) ) ;
Caml.Printexc.raise_with_backtrace exn bt Caml.Printexc.raise_with_backtrace exn bt
;; ;;
Config.run main Config.run main

@ -26,6 +26,7 @@ let init ~trace_all:ta =
Caml.at_exit flush ; Caml.at_exit flush ;
trace_all := ta trace_all := ta
(* selective tracing not yet implemented *) (* selective tracing not yet implemented *)
let enabled _ = !trace_all let enabled _ = !trace_all
@ -35,18 +36,21 @@ let info mod_name fun_name fmt =
Format.kfprintf (fun ff -> Format.fprintf ff "@]") ff fmt ) Format.kfprintf (fun ff -> Format.fprintf ff "@]") ff fmt )
else Format.ifprintf ff fmt else Format.ifprintf ff fmt
let incf rev_prefix name fmt = let incf rev_prefix name fmt =
if enabled (name :: rev_prefix) then ( if enabled (name :: rev_prefix) then (
Format.fprintf ff "@\n@[<2>@[( %s: " name ; Format.fprintf ff "@\n@[<2>@[( %s: " name ;
Format.kfprintf (fun ff -> Format.fprintf ff "@]") ff fmt ) Format.kfprintf (fun ff -> Format.fprintf ff "@]") ff fmt )
else Format.ifprintf ff fmt else Format.ifprintf ff fmt
let decf rev_prefix name fmt = let decf rev_prefix name fmt =
if enabled (name :: rev_prefix) then ( if enabled (name :: rev_prefix) then (
Format.fprintf ff "@]@\n@[<2>) %s:@ " name ; Format.fprintf ff "@]@\n@[<2>) %s:@ " name ;
Format.kfprintf (fun ff -> Format.fprintf ff "@]") ff fmt ) Format.kfprintf (fun ff -> Format.fprintf ff "@]") ff fmt )
else Format.ifprintf ff fmt else Format.ifprintf ff fmt
let call mod_name fun_name k = k (incf [mod_name] fun_name) let call mod_name fun_name k = k (incf [mod_name] fun_name)
let retn mod_name fun_name k result = let retn mod_name fun_name k result =

Loading…
Cancel
Save