2015-11-23 14 views
16

Desidero poter chiamare il codice LLVM da Haskell senza il sovraccarico di una chiamata di funzione completa. Ad esempio:Esecuzione dell'uscita LLVM di GHC tramite il linker del codice a barre LLVM prima

-- 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 
} 

posso compilare e collegare questo per produrre un eseguibile funzionamento eseguendo:

ghc -O2 -fllvm Main.hs funcs.ll 

Infatti, eliminando anche -fllvm traduce ancora in un eseguibile funzionamento, ad esempio

ghc -O2 Main.hs funcs.ll 

Il che mi porta a forte sospetto GHC è il collegamento di questi file separatamente in entrambi i casi utilizzando ordinaria legame C.

In effetti, quando indago l'uscita intermedia utilizzando:

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

vedo quanto segue in Main.s:

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

Il che suggerisce ancora una volta che GHC è solo chiedendo LLVM per compilare i file separatamente e quindi semplicemente inviando i risultati al linker di sistema, che non avrebbe in linea le chiamate.

Invece, mi piacerebbe GHC per inviare i file iniziali LLVM (sia dal GHC e specificato dall'utente) al llvm-link, che a differenza di un linker sistema, semplicemente combina più file codice binario che LLVM in file di codice binario che uno LLVM. Sarebbe meglio se questo risultato venisse quindi compilato nel file oggetto del codice nativo e inviato al linker del sistema, invece di inviare più file oggetto al linker del sistema.

In effetti, quando ho provato questa operazione manualmente, assemblando i .ll file leggibili umane per LLVM .bc codice binario che, llvm-link ing del codice binario che risulta, quindi lo smontaggio del codice binario che in questo modo:

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

ho trovato quanto segue nella risultante Codice LLVM

%ln59M = add i64 %ln59L, 1 

direttamente dopo la chiamata da leggere, senza "chiamata" o ritorno. La funzione effettiva è ancora in LLVM, ma non è richiesta.

Così ho provato a istruire GHC a collegarsi con il linker LLVM aggiungendo -pgml llvm-link alla riga di comando, ma questo non è riuscito in modo spettacolare, con llvm-link restituendo molti errori sulle opzioni sconosciute. Questo non sorprende, poiché llvm-link non è un vero linker, ma combina solo file LLVM.

Quindi, è comunque necessario che GHC invii tutti i suoi file LLVM intermedi tramite il linker LLVM per abilitare le ottimizzazioni intermodule a livello LLVM?

risposta