Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does the LLVM OCaml binding include intrinsic support?

Tags:

llvm

ocaml

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.

like image 668
jrk Avatar asked May 13 '11 21:05

jrk


2 Answers

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.

like image 33
gasche Avatar answered Oct 14 '22 11:10

gasche


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.

like image 86
jrk Avatar answered Oct 14 '22 11:10

jrk