haskell llvm ghc

haskell - Ejecutar primero la salida LLVM de GHC a través del vinculador de código de bits LLVM



(1)

Quiero poder llamar al código LLVM de Haskell sin la sobrecarga de una llamada de función completa. Por ejemplo:

-- Main.hs -- {-# LANGUAGE MagicHash #-} {-# LANGUAGE UnboxedTuples #-} {-# LANGUAGE GHCForeignImportPrim #-} {-# LANGUAGE ForeignFunctionInterface #-} {-# LANGUAGE UnliftedFFITypes #-} {-# LANGUAGE BangPatterns #-} import GHC.Exts(Word(W#)) import GHC.Prim(Word#) foreign import ccall llvminc :: Word# -> Word# main = do line1 <- getLine let !(W# x1) = read line1 let !r1 = llvminc x1 print (W# r1) -- funcs.ll -- define fastcc i64 @llvminc(i64 inreg %x) { %r = add i64 %x, 1 ret i64 %r }

Puedo compilar y vincular esto para producir un ejecutable en funcionamiento ejecutando:

ghc -O2 -fllvm Main.hs funcs.ll

De hecho, incluso la eliminación de -fllvm todavía resulta en un ejecutable que funciona, por ejemplo

ghc -O2 Main.hs funcs.ll

Lo que me lleva a sospechar que GHC está vinculando estos archivos por separado en ambos casos utilizando un enlace C normal.

De hecho, cuando investigo la salida intermedia utilizando:

ghc -O2 -fllvm -keep-s-files Main.hs funcs.ll

Veo lo siguiente en Main.s:

callq suspendThread movq %rax, %rbp movq %rbx, %rdi callq llvminc movq %rax, %rbx movq %rbp, %rdi callq resumeThread

Lo que nuevamente sugiere que GHC solo está pidiendo a LLVM que compile los archivos por separado y luego simplemente envía los resultados al vinculador del sistema, lo que no alinearía las llamadas.

En su lugar, me gustaría que GHC envíe los archivos LLVM iniciales (tanto de GHC como los especificados por el usuario) al llvm-link , que a diferencia de un vinculador del sistema, simplemente combina varios archivos de código de bits LLVM en un archivo de código de bits LLVM. Sería mejor si este resultado se compilara en un archivo de objeto de código nativo y se enviara al vinculador del sistema, en lugar de que se enviaran múltiples archivos de objeto al vinculador del sistema.

De hecho, cuando intenté esto manualmente, .ll los archivos .ll humanos en el .bc bits .bc LLVM, llvm-link con el código de bits resultante, luego desmontando el código de bits de la siguiente manera:

llvm-as Main.ll llvm-as funcs.ll llvm-link funcs.bc Main.bc -o combined.bc llvm-dis combined.bc

Encontré lo siguiente en el código LLVM resultante

%ln59M = add i64 %ln59L, 1

directamente después de la llamada a leer, sin "llamar" o devolver. La función real aún está en el LLVM, pero está fuera de lugar.

Así que intenté indicarle a GHC que se vinculara con el enlazador LLVM agregando -pgml llvm-link a la línea de comandos, pero esto falló espectacularmente, con llvm-link devolviendo muchos errores sobre opciones desconocidas. Esto no es sorprendente, ya que llvm-link no es un verdadero enlazador, simplemente combina archivos LLVM.

Entonces, ¿hay alguna forma de hacer que GHC envíe todos sus archivos intermedios de LLVM a través del enlazador de LLVM para habilitar las optimizaciones intermodulares en el nivel de LLVM?