Index: bindings/ocaml/llvm/llvm_ocaml.c =================================================================== --- bindings/ocaml/llvm/llvm_ocaml.c +++ bindings/ocaml/llvm/llvm_ocaml.c @@ -2539,8 +2539,24 @@ return Val_bool(LLVMFinalizeFunctionPassManager(FPM)); } +/* (LLVM.PassManager.t, (string -> bool)) list + Holds all the closures that */ +extern value *active_closures_list; + /* PassManager.any PassManager.t -> unit */ CAMLprim value llvm_passmanager_dispose(LLVMPassManagerRef PM) { + + // We drop any closures associated with this PassManager. The closures will + // then be GCed + static value *drop_closure_f = NULL; + if (drop_closure_f == NULL) { + drop_closure_f = caml_named_value("ll_drop_closure"); + } + if (active_closures_list != NULL) { + *active_closures_list = + caml_callback2(*drop_closure_f, *active_closures_list, (value)PM); + } + LLVMDisposePassManager(PM); return Val_unit; } Index: bindings/ocaml/transforms/ipo/ipo_ocaml.c =================================================================== --- bindings/ocaml/transforms/ipo/ipo_ocaml.c +++ bindings/ocaml/transforms/ipo/ipo_ocaml.c @@ -15,9 +15,15 @@ |* *| \*===----------------------------------------------------------------------===*/ -#include "llvm-c/Transforms/IPO.h" -#include "caml/mlvalues.h" +#include "caml/alloc.h" +#include "caml/callback.h" +#include "caml/fail.h" +#include "caml/memory.h" #include "caml/misc.h" +#include "caml/mlvalues.h" +#include "llvm-c/Core.h" +#include "llvm-c/Transforms/IPO.h" +#include /* [`Module] Llvm.PassManager.t -> unit */ CAMLprim value llvm_add_argument_promotion(LLVMPassManagerRef PM) { @@ -91,6 +97,57 @@ return Val_unit; } +/* (LLVM.PassManager.t, (string -> bool)) list + Memory managed by OCaml GC*/ +value *active_closures_list = NULL; + +LLVMBool MustPreserveCallBack(LLVMValueRef Val, void *Ctx) { + CAMLparam0(); + CAMLlocal2(LLVMValName, Predicate); + const char *llvmValName; + LLVMBool ret; + LLVMPassManagerRef PM = (LLVMPassManagerRef)Ctx; + static value *find_closure_f = NULL; + if (find_closure_f == NULL) { + find_closure_f = caml_named_value("ll_find_closure"); + } + Predicate = caml_callback2(*find_closure_f, *active_closures_list, (value)PM); + llvmValName = LLVMGetValueName(Val); + LLVMValName = caml_copy_string(llvmValName); + ret = Bool_val(caml_callback(Predicate, LLVMValName)); + + CAMLreturnT(LLVMBool, ret); +} + +/* [`Module] Llvm.PassManager.t -> (string -> bool) -> unit */ +CAMLprim value llvm_add_internalize_predicate(LLVMPassManagerRef PM, + value Predicate) { + CAMLparam1(Predicate); + if (active_closures_list == NULL) { + // initialize the active_closure_list + active_closures_list = malloc(sizeof(value)); + if (active_closures_list == NULL) + caml_raise_out_of_memory(); + *active_closures_list = Val_emptylist; + caml_register_global_root(active_closures_list); + } + + static value *add_or_replace_closure_f = NULL; + if (add_or_replace_closure_f == NULL) { + add_or_replace_closure_f = caml_named_value("ll_add_or_replace_closure"); + } + *active_closures_list = caml_callback3( + *add_or_replace_closure_f, *active_closures_list, (value)PM, Predicate); + + /* We can't directly pass the Predicate value to the callback as GC might move + it + before callback calls it. So we pass it the PM pointer, which is not GC + dependant. */ + LLVMAddInternalizePassWithMustPreservePredicate(PM, PM, + &MustPreserveCallBack); + CAMLreturn(Val_unit); +} + /* [`Module] Llvm.PassManager.t -> unit */ CAMLprim value llvm_add_strip_dead_prototypes(LLVMPassManagerRef PM) { LLVMAddStripDeadPrototypesPass(PM); Index: bindings/ocaml/transforms/ipo/llvm_ipo.ml =================================================================== --- bindings/ocaml/transforms/ipo/llvm_ipo.ml +++ bindings/ocaml/transforms/ipo/llvm_ipo.ml @@ -42,9 +42,42 @@ external add_internalize : [ `Module ] Llvm.PassManager.t -> all_but_main:bool -> unit = "llvm_add_internalize" +external add_internalize_predicate + : [ `Module ] Llvm.PassManager.t -> (string -> bool) -> unit + = "llvm_add_internalize_predicate" external add_strip_dead_prototypes : [ `Module ] Llvm.PassManager.t -> unit = "llvm_add_strip_dead_prototypes" external add_strip_symbols : [ `Module ] Llvm.PassManager.t -> unit = "llvm_add_strip_symbols" + + +(* Helper functions for add_internalize_predicate. Used by the C code *) +let add_or_replace_closure : + ([`Module] Llvm.PassManager.t * (string -> bool)) list + -> [`Module] Llvm.PassManager.t + -> (string -> bool) + -> ([`Module] Llvm.PassManager.t * (string -> bool)) list = + fun ls pm c -> (pm, c) :: List.filter (fun (pm', _) -> pm' == pm) ls + +let rec find_closure : + ([`Module] Llvm.PassManager.t * (string -> bool)) list + -> [`Module] Llvm.PassManager.t + -> string + -> bool = + fun ls pm -> + match ls with + | [] -> assert false + | (pm', c) :: _ when pm' == pm -> c + | head :: tail -> find_closure tail pm + +let drop_closure : + ([`Module] Llvm.PassManager.t * (string -> bool)) list + -> [`Module] Llvm.PassManager.t + -> ([`Module] Llvm.PassManager.t * (string -> bool)) list = + fun ls pm -> List.filter (fun (pm', _) -> pm' == pm) ls + +let _ = Callback.register "ll_add_or_replace_closure" add_or_replace_closure +let _ = Callback.register "ll_find_closure" find_closure +let _ = Callback.register "ll_drop_closure" drop_closure Index: bindings/ocaml/transforms/ipo/llvm_ipo.mli =================================================================== --- bindings/ocaml/transforms/ipo/llvm_ipo.mli +++ bindings/ocaml/transforms/ipo/llvm_ipo.mli @@ -71,6 +71,11 @@ : [ `Module ] Llvm.PassManager.t -> all_but_main:bool -> unit = "llvm_add_internalize" +(** See the [llvm::createInternalizePass] function. + If predicate returns [true], that symbol is preserved. *) +val add_internalize_predicate + : [ `Module ] Llvm.PassManager.t -> (string -> bool) -> unit + (** See the [llvm::createStripDeadPrototypesPass] function. *) external add_strip_dead_prototypes : [ `Module ] Llvm.PassManager.t -> unit