llvm-hs icon indicating copy to clipboard operation
llvm-hs copied to clipboard

(When) is loadLibraryPermanently needed?

Open jrp2014 opened this issue 4 years ago • 2 comments

The following code from arith in llvm-hs-examples (llvm-hs-12) works fine (either with or without the commented out JIT.loadLibraryPermanently Nothing on linux., when there are external symbols. Is there some guidance on when that call is actually needed?

-- | JIT-compile the given 'Expr'ession and use the resulting function.
withSimpleJIT ::
  NFData a =>
  Expr ->
  -- | what to do with the generated function
  ((Double -> Double) -> a) ->
  IO a
withSimpleJIT expr doFun = do
  putStrLn "*** Codegen ***"
  printCodegen expr
  JIT.withContext $ \context ->  -- (>>) (JIT.loadLibraryPermanently Nothing) $
      JIT.withModuleFromAST context (codegen expr) $ \mod' ->
              JIT.withHostTargetMachine Reloc.PIC CodeModel.Default CodeGenOpt.Default $ \tm ->
                JIT.withExecutionSession $ \es -> do

                  let dylibName = "myDylib"
                  dylib <- JIT.createJITDylib es dylibName

                  JIT.withClonedThreadSafeModule mod' $ \tsm -> do
                    objectLayer <- JIT.createRTDyldObjectLinkingLayer es
                    compileLayer <- JIT.createIRCompileLayer es objectLayer tm
                    JIT.addDynamicLibrarySearchGeneratorForCurrentProcess compileLayer dylib
                    JIT.addModule tsm dylib compileLayer

                    asm <- JIT.moduleLLVMAssembly mod'
                    printExpr expr
                    printIR asm

                    optimized <- PM.withPassManager passes $ flip PM.runPassManager mod'
                    when optimized $ putStrLn "*** Optimized ***"
                    optasm <- JIT.moduleLLVMAssembly mod'
                    printIR optasm

                    sym <- JIT.lookupSymbol es compileLayer dylib "f"
                    case sym of
                      Left (JIT.JITSymbolError err) -> do
                        print err
                        error "Execution aborted"
                      Right (JIT.JITSymbol fnAddr _) -> do
                        let fn =  mkDoubleFun . castPtrToFunPtr $ wordPtrToPtr fnAddr
                        liftIO (putStrLn "*** Result ***\n")
                        evaluate $ force (doFun fn)

The same code segfaults on macos on the last line (with or without the call to loadLibraryPermenently), because the pointer to fn seems to be invalid, but that is a different issue.

Here's some output from a run

; ModuleID = 'arith.ll'


 


declare external ccc  double @llvm.sin.f64(double)    


declare external ccc  double @llvm.sqrt.f64(double)    


define external ccc  double @f(double  %x_0)    {
  %x_1 = fmul        double 3.141593e0, %x_0 
  %x_2 = fdiv        double %x_1, 2.000000e0 
  %x_3 =  call ccc  double  @llvm.sin.f64(double  %x_2)  
  %x_4 =  call ccc  double  @llvm.sqrt.f64(double  %x_0)  
  %x_5 = fadd        double 1.000000e0, %x_4 
  %x_6 =  call ccc  double  @llvm.sqrt.f64(double  %x_0)  
  %x_7 = fadd        double 1.000000e0, %x_6 
  %x_8 = fmul        double %x_5, %x_7 
  %x_9 = fmul        double %x_3, %x_8 
  ret double %x_9 
}
*** Expression ***

\x -> sin(3.141592653589793 * x / 2.0) * (1.0 + sqrt(x)) * (1.0 + sqrt(x))

*** LLVM IR ***

; ModuleID = 'arith.ll'
source_filename = "<string>"

declare double @llvm.sin.f64(double)

declare double @llvm.sqrt.f64(double)

define double @f(double %x_0) {
  %x_1 = fmul double 0x400921FB54442D18, %x_0
  %x_2 = fdiv double %x_1, 2.000000e+00
  %x_3 = call double @llvm.sin.f64(double %x_2)
  %x_4 = call double @llvm.sqrt.f64(double %x_0)
  %x_5 = fadd double 1.000000e+00, %x_4
  %x_6 = call double @llvm.sqrt.f64(double %x_0)
  %x_7 = fadd double 1.000000e+00, %x_6
  %x_8 = fmul double %x_5, %x_7
  %x_9 = fmul double %x_3, %x_8
  ret double %x_9
}

*** Optimized ***

*** LLVM IR ***

; ModuleID = 'arith.ll'
source_filename = "<string>"

declare double @llvm.sin.f64(double)

declare double @llvm.sqrt.f64(double)

define double @f(double %x_0) local_unnamed_addr {
  %x_1 = fmul double %x_0, 0x400921FB54442D18
  %x_2 = fmul double %x_1, 5.000000e-01
  %x_3 = tail call double @llvm.sin.f64(double %x_2)
  %x_4 = tail call double @llvm.sqrt.f64(double %x_0)
  %x_5 = fadd double %x_4, 1.000000e+00
  %x_6 = tail call double @llvm.sqrt.f64(double %x_0)
  %x_7 = fadd double %x_6, 1.000000e+00
  %x_8 = fmul double %x_5, %x_7
  %x_9 = fmul double %x_3, %x_8
  ret double %x_9
}

*** Result ***

results match
[0.0,4.0,7.137764622384033e-16,-7.464101615137754,-2.204364238465236e-15,10.47213595499958,4.3716141420356565e-15,-13.291502622129181,-7.179787856884051e-15,16.0,1.0608230609850833e-14]

jrp2014 avatar May 21 '21 11:05 jrp2014

Looking more closely, I see that loadLibraryPermanently produces a success/failure Bool. In the case above, it actually returns false (so it failed to load the process symbols, yet the result of the process succeeds). This still leaves the question of when loadLibraryPermanently is neeeded.

jrp2014 avatar May 22 '21 10:05 jrp2014

I think addDynamicLibrarySearchGeneratorForCurrentProcess might be doing more or less the same thing in your case as loadLibraryPermanently. Try (a) removing both calls and (b) removing addDynamicLibrarySearchGeneratorForCurrentProcess but leaving loadLibraryPermanently and see if that confirms my hypothesis.

Also,

In the case above, it actually returns false (so it failed to load the process symbols, yet the result of the process succeeds).

Though this does not seem to be documented anywhere, loadLibraryPermanently returns True on failure; see the definition of static bool LoadLibraryPermanently in llvm/include/llvm/Support/DynamicLibrary.h.

UnkindPartition avatar Nov 02 '21 13:11 UnkindPartition