Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Validity of ccalling with the ORC JIT? #153

Closed
chriselrod opened this issue Feb 14, 2024 · 2 comments
Closed

Validity of ccalling with the ORC JIT? #153

chriselrod opened this issue Feb 14, 2024 · 2 comments

Comments

@chriselrod
Copy link
Contributor

Code like this works as intended (so long as you only have a single argument #152):

using LLVM, StaticCompiler, SpecialFunctions
ccall_mod = StaticCompiler.native_llvm_module(erf, (Float64,); demangle=true)


function codegen!(mod::LLVM.Module, name)
  param_types = [LLVM.DoubleType()]
  ret_type = LLVM.DoubleType()

  tm = LLVM.JITTargetMachine(Sys.MACHINE, Sys.CPU_NAME)
  triple!(mod, triple(tm))

  ft = LLVM.FunctionType(ret_type, param_types)
  fn = LLVM.Function(mod, name, ft)

  # generate IR
  @dispose builder = IRBuilder() begin
    entry = BasicBlock(fn, "entry")
    position!(builder, entry)

    ccalltype = LLVM.FunctionType(LLVM.DoubleType(), [LLVM.DoubleType()])
    ccallname = StaticCompiler.fix_name(erf)
    fnccall = LLVM.Function(mod, ccallname, ccalltype)
    LLVM.linkage!(fnccall, LLVM.API.LLVMExternalLinkage)
    params = [parameters(fn)[1]]
    tmp = call!(builder, ccalltype, fnccall, params)
    ret!(builder, tmp)
  end

  verify(mod)
  println(string(mod))
  mod
end

function compile()
  tm = LLVM.JITTargetMachine(Sys.MACHINE, Sys.CPU_NAME)
  jit = LLJIT(; tm)
  @dispose ts_ctx = ThreadSafeContext() begin
    ts_mod = LLVM.ThreadSafeModule("ccall_caller")
    name = "ccall_example"
    ts_mod() do mod
      codegen!(mod, name)
    end
    ts_mod() do tsmod
      LLVM.link!(tsmod, copy(ccall_mod))
    end

    jd = JITDylib(jit)
    add!(jit, jd, ts_mod)
    if true
      prefix = LLVM.get_prefix(jit)
      dg = LLVM.CreateDynamicLibrarySearchGeneratorForProcess(prefix)
      LLVM.add!(jd, dg)
    end
    let addr = pointer(lookup(jit, name))
      x -> ccall(addr, Float64, (Float64,), x)
    end
  end
end


erf2 = compile()
erf(1.2), erf2(1.2)
erf(-1.2), erf2(-1.2)
erf(0.4), erf2(0.4)

I get

julia> erf(1.2), erf2(1.2)
(0.9103139782296353, 0.9103139782296353)

julia> erf(-1.2), erf2(-1.2)
(-0.9103139782296353, -0.9103139782296353)

julia> erf(0.4), erf2(0.4)
(0.42839235504666845, 0.42839235504666845)

However, it also emits the warning

julia> ccall_mod = StaticCompiler.native_llvm_module(erf, (Float64,); demangle=true)
┌ Warning: Found pointer references to julia data
│   llvm instruction = %1 = call double inttoptr (i64 140261382491264 to double (double)*)(double %0)
│   name = :erf
│   file = Symbol("/home/chriselrod/Documents/languages/juliarelease/usr/bin/../lib/libopenlibm.so")
│   line = -1
│   fromC = true
│   inlined = false
└ @ StaticCompiler ~/.julia/packages/StaticCompiler/Uki9T/src/pointer_warning.jl:59
┌ Warning: LLVM function generated warnings due to raw pointers embedded in the code. This will likely cause errors or undefined behaviour.
│   func =
│    define double @erf(double %0) local_unnamed_addr #0 {
│    top:%1 = call double inttoptr (i64 140261382491264 to double (double)*)(double %0)
│      ret double %1
│    }
│    
└ @ StaticCompiler ~/.julia/packages/StaticCompiler/Uki9T/src/pointer_warning.jl:33
; ModuleID = 'start'
source_filename = "start"
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-redhat-linux"

define double @erf(double %0) local_unnamed_addr #0 {
top:
  %1 = call double inttoptr (i64 140261382491264 to double (double)*)(double %0)
  ret double %1
}

attributes #0 = { "frame-pointer"="all" }

!llvm.module.flags = !{!0, !1}

!0 = !{i32 2, !"Dwarf Version", i32 4}
!1 = !{i32 2, !"Debug Info Version", i32 3}

because it is using a literal pointer in the generated code.

It seems like this should be okay with the ORC JIT, as we're using it in the same process as the host Julia process, so that pointer should be valid and stable.

But I'd like to check whether this should really be okay and the warning is spurious for this use case, or if there is something else I ought to be doing.

@vchuravy
Copy link
Contributor

Yes as long as you are in the same process this is okay. (But then you don't need StaticCompiler and can just use the native target in GPUCompiler)

@chriselrod
Copy link
Contributor Author

Thanks, you're right. I dropped the StaticCompiler dep and am now just using GPUCompiler directly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants