2013-04-24 14 views
5

Das Problem, das ich mit den LLVM-Haskell-Bindungen habe, ist, dass ich "doppelte" Namen bekomme. Ich denke, der beste Weg, um mein Problem zu erklären, ist mit einem kleinen konkreten Beispiel (beachten Sie, das Beispiel ist erfunden, und für solch ein kleines Beispiel gibt es einfache Wege um es herum ... aber es weist auf mein Problem).Haskell LLVM - Doppelte Funktionen erstellt

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 

Wenn Sie jetzt dieses Haskell-Programm ausführen (Sie werden einige Importe wie Data.Int/Word und LLVM.Core benötigen), erhalten Sie die folgende Ausgabe.

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

Das Problem ist, dass in der IR, die (extern) putchar zweimal deklariert wird, aber beim zweiten Mal mit dem Namen putchar1. Ich habe ein gutes Gespür dafür, warum das so ist, aber keinen guten Sinn für einen schönen allgemeinen Weg. I.e. Ich möchte nicht alles in ein riesiges CodeGenModul stecken.

Dies bringt mich zu einem anderen verwandten Problem. Ist die LLVM-Haskell-Bindung für das Erstellen des Back-Ends eines Compilers geeignet? Vielleicht mit einer vernünftigen Lösung für die oben genannten - Ich kann einen Weg, um es zu benutzen ... aber es scheint einfacher zu Hand schreiben Sie den IR-Code ...

Antwort

3

Sie rufen newNamedFunction "putchar" innerhalb der CodeGenModule Monad zweimal , was offensichtlich den Nebeneffekt hat, dass das Modul zweimal in das Modul putchar eingefügt wird. Die Tatsache, dass dies zu zwei Deklarationen anstatt zu einem Fehler führt, ist wahrscheinlich ein Fehler, bitte berichte darüber. Um dies zu beheben, machen Sie einfach putc einen Parameter von simple und easy. Dies wird ungefähr wie folgt aussehen (nicht getestet):

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

Das ist eine nette Lösung. –

+0

Wenn Sie die Bibliothek bitten, die Funktion "putchar" zweimal zu deklarieren, wird sie zweimal deklariert. Dies ist kein Fehler. Die hier vorgeschlagene Lösung ist genau der richtige Weg. Wenn Sie mehr Funktionen verwalten müssen, können Sie getModuleValues ​​verwenden, um die deklarierten Funktionen eines Moduls zu erhalten. Siehe llvm: example/Vector.hs. Aber hüte dich vor diesem Fehler: https://github.com/bos/llvm/issues/78 – Lemming