I can't seem to find reference to intrinsics in the official LLVM OCaml binding, beyond the is_intrinsic
function.
I am building a backend which needs to perform some target-specific code-generation (for SSE, AVX, and NEON), and intrinsics are the standard path in the C++ API.
Disclaimer: I never used LLVM. After a quick look at the binding documentation, it looks like the answer is "no". There is a support for inline assembly however, which may or may not suit your needs.
Finally, it seems it is accepted by the LLVM developers that the OCaml binding is not complete: if you want to, you can add some more functionality (if you're not familiar with OCaml, C bindings are really not the easiest part, but the LLVM bindings are full of example code that you could probably successfully adapt to other LLVM functions), then provide a patch for it on the LLVMdev list.
The OCaml binding supports intrinsics in exactly the same way as the C language binding:
There is no special support for them in the interface (as there is in the full C++ interface), but they can be declared extern and called just like any other functions.
e.g.:
open Llvm
let () =
let c = create_context () in
let f32_t = float_type c in
let f32x4_t = vector_type f32_t 4 in
let m = create_module c "test" in
(* declare void @printv(<4 x float>)
* nonce extern which forces preservation of vector results *)
let printv =
declare_function "printv"
(function_type (void_type c) [|f32x4_t|]) m in
(* declare <4 x float> @llvm.x86.sse.sqrt.ps(<4 x float>) nounwind readnone *)
let sqrtps =
declare_function "llvm.x86.sse.sqrt.ps"
(function_type f32x4_t [|f32x4_t|]) m in
(* define i32 @main() { entry: *)
let main = define_function "main" (function_type i32_t [| |]) m in
let at_entry = builder_at_end c (entry_block main) in
(*%sqrtps = call <4 x float> @llvm.x86.sse.sqrt.ps(<4 x float> <float 1.000000e+00, float 2.000000e+00, float 3.000000e+00, float 4.000000e+00>)*)
let cv1234 = const_vector [| const_float f32_t 1.0; const_float f32_t 2.0;
const_float f32_t 3.0; const_float f32_t 4.0 |] in
let sqrt = build_call sqrtps [| cv1234 |] "sqrtps" at_entry in
(* call void printv(sqrtps) *)
ignore (build_call printv [| sqrt |] "" at_entry);
(* ret void *)
ignore (build_ret (const_null i32_t) at_entry);
(* Print .ll to stderr *)
dump_module m
produces:
; ModuleID = 'test'
declare void @printv(<4 x float>)
declare <4 x float> @llvm.x86.sse.sqrt.ps(<4 x float>) nounwind readnone
define i32 @main() {
entry:
%sqrtps = call <4 x float> @llvm.x86.sse.sqrt.ps(<4 x float> <float 1.000000e+00, float 2.000000e+00, float 3.000000e+00, float 4.000000e+00>)
call void @printv(<4 x float> %sqrtps)
ret i32 0
}
which compiles into x86 correctly invoking sqrtps
on the xmm
registers.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With