Index: bindings/ocaml/llvm/llvm_ocaml.c =================================================================== --- bindings/ocaml/llvm/llvm_ocaml.c +++ bindings/ocaml/llvm/llvm_ocaml.c @@ -2539,8 +2539,39 @@ return Val_bool(LLVMFinalizeFunctionPassManager(FPM)); } +struct pm_predicate_block { + struct pm_predicate_block *next; + LLVMPassManagerRef PM; + value *predicate_f; +}; + +extern struct pm_predicate_block *pm_predicate_register; + /* PassManager.any PassManager.t -> unit */ CAMLprim value llvm_passmanager_dispose(LLVMPassManagerRef PM) { + + // Free the internalize predicates added by llvm_add_internalize_predicate + struct pm_predicate_block *curr = pm_predicate_register; + struct pm_predicate_block **prev_next = &pm_predicate_register; + + while (curr != NULL) { + if (curr->PM == PM) { + struct pm_predicate_block *prev = curr; + // Drop curr from the linked list + *prev_next = curr->next; + curr = curr->next; + + // Free resources + caml_remove_global_root(prev->predicate_f); + free(prev->predicate_f); + free(prev); + } else { + + prev_next = &curr->next; + curr = curr->next; + } + } + 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,14 @@ |* *| \*===----------------------------------------------------------------------===*/ -#include "llvm-c/Transforms/IPO.h" -#include "caml/mlvalues.h" +#include "caml/alloc.h" +#include "caml/callback.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 +96,51 @@ return Val_unit; } +struct pm_predicate_block { + struct pm_predicate_block *next; + LLVMPassManagerRef PM; + value *predicate_f; +}; + +/* Used by llvm_pass_manager_dispose */ +struct pm_predicate_block *pm_predicate_register = NULL; + +LLVMBool MustPreserveCallBack(LLVMValueRef Val, void *Ctx) { + CAMLparam0(); + CAMLlocal1(LLVMValName); + const char *llvmValName; + LLVMBool ret; + struct pm_predicate_block *pm_predicate = Ctx; + llvmValName = LLVMGetValueName(Val); + LLVMValName = caml_copy_string(llvmValName); + ret = Bool_val(caml_callback(*(pm_predicate->predicate_f), LLVMValName)); + + CAMLreturnT(LLVMBool, ret); +} + +/* [`Module] Llvm.PassManager.t -> (string -> bool) -> unit */ +CAMLprim value llvm_add_internalize_predicate(LLVMPassManagerRef PM, + value Predicate) { + struct pm_predicate_block *pm_predicate = + malloc(sizeof(struct pm_predicate_block)); + + if (pm_predicate == NULL) + caml_raise_out_of_memory(); + pm_predicate->predicate_f = malloc(sizeof(value)); + if (pm_predicate->predicate_f == NULL) + caml_raise_out_of_memory(); + caml_register_global_root(pm_predicate->predicate_f); + + *pm_predicate->predicate_f = Predicate; + pm_predicate->PM = PM; + pm_predicate->next = pm_predicate_register; + pm_predicate_register = pm_predicate; + + LLVMAddInternalizePassWithMustPreservePredicate(PM, pm_predicate, + &MustPreserveCallBack); + return 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,6 +42,9 @@ 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" 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