Julia references at LLVM IR level

Hello
I’m coming to ask for your help today, because I have the following problem:
As a toy example, I have implemented a multiplication function below:

function mult!(res::Ref{Int16},a::Int16,b::Int16)
    res[]=a*b
    return nothing
end

In which, I am using an Int16 reference pass as a parameter to my function to store the result (this is required for my example).
Unfortunately at LLVM IR level in the function signature the reference is typed as ({}* nonnull align 2 dereferenceable(2) %0):

define void @julia_mult_276({}* nonnull align 2 dereferenceable(2) %0, i16 signext %1, i16 signext %2) #0 {
top:

   %3 = mul i16 %1, %2
   %4 = bitcast {}* %0 to i16*
   store i16 %3, i16* %4, align 2
  ret void
}

But I need to be able to generate an LLVM IR by using Julia where references are typed as pointers to the type of the reference in the functions signature. I will inject this IR later in another application.
So based on the example of my multiplication function above, I would like to have the following LLVM IR level result:

define void @julia_mult_276(i16* %0, i16 signext %1, i16 signext %2) #0 {
top:

   %3 = mul i16 %1, %2
   store i16 %3, i16* %0, align 2
  ret void
}

With the reference Int16 typed how this i16* %0 in the signature.
Is there any solution to force the typing in the signature at LLVM IR level by using flags or others at Julia code level ?

Thanks in advance for your help.

1 Like

Ref is a Julia object. Use regular Ptrs if you want pointers:

julia> mult!(res,a,b) = unsafe_store!(res, a*b)
mult! (generic function with 1 method)

julia> code_llvm(mult!, Tuple{Ptr{Int16},Int16,Int16})
;  @ REPL[1]:1 within `mult!`
define i64 @"julia_mult!_143"(i64 zeroext %0, i16 signext %1, i16 signext %2) #0 {
top:
; β”Œ @ int.jl:88 within `*`
   %3 = mul i16 %2, %1
; β””
; β”Œ @ pointer.jl:118 within `unsafe_store!` @ pointer.jl:118
   %4 = inttoptr i64 %0 to i16*
   store i16 %3, i16* %4, align 1
; β””
  ret i64 %0
}

The pointers are passed as integers. If you want actual pointers, use Core.LLVMPtr{T,AS} (but note that unsafe_store! etc doesn’t work on those by default, use LLVM.jl if you need that kind of functionality). Also note that those pointers will still be untyped, but LLVM is moving towards opaque pointers anyway.

julia> using LLVM

julia> mult!(res,a,b) = unsafe_store!(res, a*b)
mult! (generic function with 1 method)

julia> code_llvm(mult!, Tuple{Core.LLVMPtr{Int16,0},Int16,Int16})
;  @ REPL[2]:1 within `mult!`
define void @"julia_mult!_452"(i8* %0, i16 signext %1, i16 signext %2) #0 {
top:
; β”Œ @ int.jl:88 within `*`
   %3 = mul i16 %2, %1
; β””
; β”Œ @ /Users/tim/Julia/pkg/LLVM/src/interop/pointer.jl:84 within `unsafe_store!` @ /Users/tim/Julia/pkg/LLVM/src/interop/pointer.jl:84 @ /Users/tim/Julia/pkg/LLVM/src/interop/pointer.jl:84
; β”‚β”Œ @ /Users/tim/Julia/pkg/LLVM/src/interop/pointer.jl:44 within `pointerset`
; β”‚β”‚β”Œ @ /Users/tim/Julia/pkg/LLVM/src/interop/pointer.jl:44 within `macro expansion` @ /Users/tim/Julia/pkg/LLVM/src/interop/base.jl:40
     %4 = bitcast i8* %0 to i16*
     store i16 %3, i16* %4, align 1
; β””β””β””
  ret void
}
3 Likes