2013-04-24 10 views
5

Il problema che sto avendo con i binding LLVM-Haskell è che ottengo nomi "duplicati". Penso che il modo migliore per spiegare il mio problema sia con un piccolo esempio concreto (si noti che l'esempio è artificioso, e per un piccolo esempio ci sono modi semplici per aggirarlo ... comunque sottolinea il mio problema).Haskell LLVM - Funzioni duplicate create

putc :: TFunction (Int32 -> IO Word32) 
putc = newNamedFunction ExternalLinkage "putchar" 

simple :: TFunction (Int32 -> IO Word32) 
simple = do 
    internalputc <- putc 
    createNamedFunction ExternalLinkage "simple" $ \x -> do 
     call internalputc x 
     call internalputc x 
     ret (0 :: Word32) 

easy :: TFunction (Int32 -> IO Word32) 
easy = do 
    internalputc <- putc 
    internalsimple <- simple 
    createNamedFunction ExternalLinkage "easy" $ \x -> do 
     call internalsimple x 
     y <- add x (42 :: Int32) 
     call internalputc y 
     ret (0 :: Word32) 

main :: IO() 
main = do 
    m <- newNamedModule "Main" 
    defineModule m easy 
    writeBitcodeToFile "SillyLib" m 

Se ora si esegue questo programma Haskell (avrete bisogno di alcune importazioni come Data.Int/Word, e LLVM.Core), si otterrà il seguente risultato.

; ModuleID = 'SillyLib' 

declare i32 @putchar(i32) 

declare i32 @putchar1(i32) 

define i32 @simple(i32) { 
_L1: 
    %1 = call i32 @putchar1(i32 %0) 
    %2 = call i32 @putchar1(i32 %0) 
    ret i32 0 
} 

define i32 @easy(i32) { 
_L1: 
    %1 = call i32 @simple(i32 %0) 
    %2 = add i32 %0, 42 
    %3 = call i32 @putchar(i32 %2) 
    ret i32 0 
} 

Il problema è che in IR, la (esterno) putchar è dichiarato due volte, ma la seconda volta con il nome putchar1. Ho un buon senso sul perché questo sia, ma non è un buon senso per un buon modo generale. Cioè Non voglio dover mettere tutto all'interno di un gigantesco CodeGenModule.

Questo mi porta ad un altro problema correlato. Il binding LLVM-Haskell è appropriato per la creazione del back-end di un compilatore. Forse con una soluzione ragionevole a quanto sopra - posso capire un modo per usarlo ... ma sembra più semplice scrivere a mano il codice IR ...

risposta

3

Stai chiamando newNamedFunction "putchar" all'interno dello CodeGenModule monad due volte , che ovviamente ha l'effetto collaterale di aggiungere putchar al modulo due volte. Il fatto che questo si traduca in due dichiarazioni invece di un errore è probabilmente un bug, per favore considera di segnalarlo. Per risolvere questo problema, è sufficiente impostare putc come parametro simple e easy. Questo apparirà approssimativamente come segue (non testato):

simple :: Function (Int32 -> IO Word32) -> TFunction (Int32 -> IO Word32) 
simple putc = 
    createNamedFunction ExternalLinkage "simple" $ \x -> do 
     call putc x 
     call putc x 
     ret (0 :: Word32) 

easy :: Function (Int32 -> IO Word32) -> Function (Int32 -> IO Word32) 
     -> TFunction (Int32 -> IO Word32) 
easy putc simple' = 
    createNamedFunction ExternalLinkage "easy" $ \x -> do 
     call simple' x 
     y <- add x (42 :: Int32) 
     call putc y 
     ret (0 :: Word32) 

main :: IO() 
main = do 
    m <- newNamedModule "Main" 
    defineModule m $ do 
     putc <- newNamedFunction ExternalLinkage "putchar" 
     simple' <- simple putc 
     easy putc simple' 
    writeBitcodeToFile "SillyLib" m 
+0

Questa è una bella soluzione. –

+0

Se si chiede alla libreria di dichiarare la funzione "putchar" due volte, viene dichiarata due volte. Questo non è un bug. La soluzione suggerita qui è giusta. Se si dispone di più funzioni da mantenere, è possibile utilizzare getModuleValues ​​per ottenere le funzioni dichiarate di un modulo. Vedi llvm: example/Vector.hs. Ma fai attenzione a questo bug: https://github.com/bos/llvm/issues/78 – Lemming