[llvm] [OCaml] Add OCaml bindings for intrinsics API (PR #173817)

via llvm-commits llvm-commits at lists.llvm.org
Sun Dec 28 19:42:24 PST 2025


https://github.com/alan-j-hu created https://github.com/llvm/llvm-project/pull/173817

None

>From 7a03aeae2cbd241055c0d43c65ebe6c3d2c58cb5 Mon Sep 17 00:00:00 2001
From: Alan Hu <ahulambda at gmail.com>
Date: Sun, 28 Dec 2025 22:40:52 -0500
Subject: [PATCH] [OCaml] Add OCaml bindings for intrinsics API

---
 llvm/bindings/ocaml/llvm/llvm.ml      | 12 +++++-
 llvm/bindings/ocaml/llvm/llvm.mli     | 34 +++++++++++++++
 llvm/bindings/ocaml/llvm/llvm_ocaml.c | 62 +++++++++++++++++++++++++--
 llvm/test/Bindings/OCaml/core.ml      | 14 ++++++
 4 files changed, 118 insertions(+), 4 deletions(-)

diff --git a/llvm/bindings/ocaml/llvm/llvm.ml b/llvm/bindings/ocaml/llvm/llvm.ml
index d78d5d8000f33..88e8c200d5bb0 100644
--- a/llvm/bindings/ocaml/llvm/llvm.ml
+++ b/llvm/bindings/ocaml/llvm/llvm.ml
@@ -792,7 +792,17 @@ external define_function : string -> lltype -> llmodule -> llvalue
 external lookup_function : string -> llmodule -> llvalue option
                          = "llvm_lookup_function"
 external delete_function : llvalue -> unit = "llvm_delete_function"
-external is_intrinsic : llvalue -> bool = "llvm_is_intrinsic"
+external lookup_intrinsic_id : string -> int = "llvm_lookup_intrinsic_id"
+external intrinsic_id : llvalue -> int = "llvm_intrinsic_id"
+let is_intrinsic v = intrinsic_id v <> 0
+external intrinsic_declaration : llmodule -> int -> lltype array -> llvalue
+                               = "llvm_intrinsic_declaration"
+external intrinsic_type : llcontext -> int -> lltype array -> lltype
+                        = "llvm_intrinsic_type"
+external intrinsic_name : int -> string = "llvm_intrinsic_name"
+external intrinsic_overloaded_name : llmodule -> int -> lltype array -> string
+                                   = "llvm_intrinsic_overloaded_name"
+external intrinsic_is_overloaded : int -> bool = "llvm_intrinsic_is_overloaded"
 external function_call_conv : llvalue -> int = "llvm_function_call_conv"
 external set_function_call_conv : int -> llvalue -> unit
                                 = "llvm_set_function_call_conv"
diff --git a/llvm/bindings/ocaml/llvm/llvm.mli b/llvm/bindings/ocaml/llvm/llvm.mli
index 8ba49f9c2474b..67a4403c103da 100644
--- a/llvm/bindings/ocaml/llvm/llvm.mli
+++ b/llvm/bindings/ocaml/llvm/llvm.mli
@@ -1473,10 +1473,44 @@ val rev_iter_functions : (llvalue -> unit) -> llmodule -> unit
     [f1,...,fN] are the functions of module [m]. Tail recursive. *)
 val fold_right_functions : (llvalue -> 'a -> 'a) -> llmodule -> 'a -> 'a
 
+(** [lookup_intrinsic_id name] obtains the intrinsic ID number for the given
+    function name. See the method [llvm::Intrinsic::lookupIntrinsicID].*)
+val lookup_intrinsic_id : string -> int
+
+(** [intrinsic_id] returns the ID of intrinsic function [f]. If [f] is not
+    an intrinsic, returns [0]. See the method
+    [llvm::Function::getIntrinsicID]. *)
+val intrinsic_id : llvalue -> int
+
 (** [is_intrinsic f] returns true if the function [f] is an intrinsic.
     See the method [llvm::Function::isIntrinsic]. *)
 val is_intrinsic : llvalue -> bool
 
+(** [intrinsic_declaration m id param_types] gets or inserts the declaration
+    of an intrinsic. For overloaded intrinsics, parameter types must be
+    provided to uniquely identify an overload. See the method
+    [llvm::Intrinsic::getOrInsertDeclaration]. *)
+val intrinsic_declaration : llmodule -> int -> lltype array -> llvalue
+
+(** [intrinsic_type c id param_types] returns the type of intrinsic [id] in
+    context [c]. For overloaded intrinsics, parameter types must be provided
+    to uniquely identify an overload. See the method
+    [llvm::Intrinsic::getType]. *)
+val intrinsic_type : llcontext -> int -> lltype array -> lltype
+
+(** [intrinsic_name id] returns the name of intrinsic [id]. See the method
+    [llvm::Intrinsic::getName()]. *)
+val intrinsic_name : int -> string
+
+(** [intrinsic_overloaded_name m id param_types] returns the name of an
+    overloaded intrinsic [id] identified by the parameter types
+    [param_types]. See the method [llvm::Intrinsic::getName]. *)
+val intrinsic_overloaded_name : llmodule -> int -> lltype array -> string
+
+(** [intrinsic_is_overloaded id] returns if intrinsic [id] is overloaded. See
+    the method [llvm::Intrinsic::isOverloaded]. *)
+val intrinsic_is_overloaded : int -> bool
+
 (** [function_call_conv f] returns the calling convention of the function [f].
     See the method [llvm::Function::getCallingConv]. *)
 val function_call_conv : llvalue -> int
diff --git a/llvm/bindings/ocaml/llvm/llvm_ocaml.c b/llvm/bindings/ocaml/llvm/llvm_ocaml.c
index cd2bd73f57351..a3a6db4edddc1 100644
--- a/llvm/bindings/ocaml/llvm/llvm_ocaml.c
+++ b/llvm/bindings/ocaml/llvm/llvm_ocaml.c
@@ -1595,9 +1595,65 @@ value llvm_delete_function(value Fn) {
   return Val_unit;
 }
 
-/* llvalue -> bool */
-value llvm_is_intrinsic(value Fn) {
-  return Val_bool(LLVMGetIntrinsicID(Value_val(Fn)));
+/* string -> int */
+value llvm_lookup_intrinsic_id(value Name) {
+  const char* NameCStr = String_val(Name);
+  size_t Len = caml_string_length(Name);
+  return Val_int(LLVMLookupIntrinsicID(NameCStr, Len));
+}
+
+/* llvalue -> int */
+value llvm_intrinsic_id(value Fn) {
+  return Val_int(LLVMGetIntrinsicID(Value_val(Fn)));
+}
+
+/* llmodule -> int -> lltype array -> llvalue */
+value llvm_intrinsic_declaration(value M, value ID, value ParamTys) {
+  mlsize_t Length = Wosize_val(ParamTys);
+  LLVMTypeRef *Temp = from_val_array(ParamTys);
+  LLVMValueRef Intrinsic =
+    LLVMGetIntrinsicDeclaration(Module_val(M), Int_val(ID), Temp, Length);
+  free(Temp);
+  return to_val(Intrinsic);
+}
+
+/* llcontext -> int -> lltype array -> lltype */
+value llvm_intrinsic_type(value C, value ID, value ParamTys) {
+  mlsize_t Length = Wosize_val(ParamTys);
+  LLVMTypeRef *Temp = from_val_array(ParamTys);
+  LLVMTypeRef Type =
+    LLVMIntrinsicGetType(Context_val(C), Int_val(ID), Temp, Length);
+  free(Temp);
+  return to_val(Type);
+}
+
+/* int -> string */
+value llvm_intrinsic_name(value ID) {
+  size_t Length = -1;
+  const char *NameCStr = LLVMIntrinsicGetName(Int_val(ID), &Length);
+  return caml_copy_string(NameCStr);
+}
+
+/* llmodule -> int -> lltype array -> string */
+value llvm_intrinsic_overloaded_name(value M, value ID, value ParamTys) {
+  mlsize_t ParamCount = Wosize_val(ParamTys);
+  LLVMTypeRef *Temp = from_val_array(ParamTys);
+  size_t NameLength = -1;
+  char *OverloadedNameCStrOwned =
+    LLVMIntrinsicCopyOverloadedName2(Module_val(M),
+                                     Int_val(ID),
+                                     Temp,
+                                     ParamCount,
+                                     &NameLength);
+  value OverloadedName = caml_copy_string(OverloadedNameCStrOwned);
+  free(OverloadedNameCStrOwned);
+  free(Temp);
+  return OverloadedName;
+}
+
+/* int -> bool */
+value llvm_intrinsic_is_overloaded(int ID) {
+  return Val_bool(LLVMIntrinsicIsOverloaded(Int_val(ID)));
 }
 
 /* llvalue -> int */
diff --git a/llvm/test/Bindings/OCaml/core.ml b/llvm/test/Bindings/OCaml/core.ml
index 289fe013bed2a..2af2a124ac4a0 100644
--- a/llvm/test/Bindings/OCaml/core.ml
+++ b/llvm/test/Bindings/OCaml/core.ml
@@ -677,6 +677,20 @@ let test_functions () =
   set_value_name "Param2" params.(1);
   ignore (build_unreachable (builder_at_end context (entry_block fn)));
 
+  group "intrinsics";
+  insist (not (is_intrinsic fn));
+  let abs_id = lookup_intrinsic_id "llvm.abs" in
+  let abs_decl = intrinsic_declaration m abs_id [|i32_type|] in
+  insist ("llvm.abs.i8" = intrinsic_overloaded_name m abs_id [|i8_type|]);
+  insist ("llvm.abs.i32" = intrinsic_overloaded_name m abs_id [|i32_type|]);
+  insist (is_intrinsic abs_decl);
+  insist (intrinsic_is_overloaded abs_id);
+  let stackmap_id = lookup_intrinsic_id "llvm.experimental.stackmap" in
+  let stackmap_decl = intrinsic_declaration m stackmap_id [||] in
+  insist ("llvm.experimental.stackmap" = intrinsic_name stackmap_id);
+  insist (is_intrinsic stackmap_decl);
+  insist (not (intrinsic_is_overloaded stackmap_id));
+
   (* CHECK: fastcc{{.*}}Fn5
    *)
   group "callconv";



More information about the llvm-commits mailing list