Coder Social home page Coder Social logo

llvm-hs / llvm-hs-pretty Goto Github PK

View Code? Open in Web Editor NEW
66.0 5.0 35.0 190 KB

Pretty printer for LLVM AST to Textual IR

License: MIT License

Haskell 33.41% Nix 1.38% LLVM 65.21%
llvm haskell-bindings llvm-hs llvm-ir pretty-printer code-generation llvm-ast

llvm-hs-pretty's Introduction

llvm-hs-pretty

Build Status Hackage

A pretty printer for llvm-hs-pure. Goal is to be able to pretty print a sufficiently large subset of the LLVM AST from pure Haskell without having to go through the C++ API.

Note: It is possible to construct llvm-hs-pure ASTs that are invalid ASTs and as such there is no meaningful way to print them. Always run the LLVM verifier on your AST to test it is sound. If you encounter incomplete pattern matches using this library you likely have constructed invalid IR.

Usage

There is a single function ppllvm that maps a LLVM.AST.Module to a Text.

import LLVM.AST
import LLVM.Pretty (ppllvm)

ppllvm :: Module -> Text

Individual LLVM elements (constants, instructions) can be printed using the the polymorphic ppll function for any LLVM structure that implements the PP typeclass.

Tests

# This is only necessary for running the test suite
sudo apt-get install llvm-9-dev

The test suite currently consists of round tripping a LLVM IR from correct IR outputted by the llc toolchain, parsing into llvm-hs AST and then printing it back out and comparing it with the original textual form to see if the pretty printer faithfully preserves the structure. The sample modules are in tests/.

Using stack:

$ stack build
$ stack test

Using cabal:

$ cabal run
$ cabal run -- tests/simple.ll

If you're using Nix then:

$ nix-shell
$ cabal run

Example

To try out the standalone example run:

$ stack repl
$ :load Example.hs
main

Consider the basic example LLVM module.

; ModuleID = 'example-llvm-module'

define i8 @f(i8 %x){
entry:
  ret i8 %x
}

Using the LLVM.AST we construct the type and feed it to the pretty printer.

module Standalone where

-- Pretty Printer
import LLVM.Pretty (ppllvm)

-- AST
import qualified LLVM.AST as AST
import qualified LLVM.AST.Linkage as Linkage
import qualified LLVM.AST.Visibility as Visibility
import qualified LLVM.AST.CallingConvention as Convention

import Data.Text.Lazy.IO as TIO

astModule :: AST.Module
astModule = AST.Module
    { AST.moduleName         = "example-llvm-module"
    , AST.moduleDataLayout   = Nothing
    , AST.moduleTargetTriple = Nothing
    , AST.moduleDefinitions  =
        [ AST.GlobalDefinition
            (AST.Function
                Linkage.External
                Visibility.Default
                Nothing
                Convention.C
                []
                (AST.IntegerType 8)
                (AST.Name "f")
                ([AST.Parameter (AST.IntegerType 8) (AST.Name "x") []], False)
                []
                Nothing
                Nothing
                0
                Nothing
                Nothing
                [ AST.BasicBlock
                    (AST.Name "entry")
                    []
                    (AST.Do
                        (AST.Ret
                            (Just
                                (AST.LocalReference
                                    (AST.IntegerType 8)
                                    (AST.Name "x")
                                )
                            )
                            []
                        )
                    )
                ]
            )
        ]
    }

main :: IO ()
main = TIO.putStrLn (ppllvm astModule)

License

Released under the MIT License.

Copyright (c) 2014-2020, Stephen Diehl Copyright (c) 2015 Cedric Shock

llvm-hs-pretty's People

Contributors

abhiroop avatar aherrmann avatar cocreature avatar ekmett avatar fugue-brett avatar jcpetruzza avatar lemmih avatar luc-tielen avatar lukel97 avatar minad avatar mrkgnao avatar nomeata avatar ollef avatar sdiehl avatar songwithoutwords avatar vjoki avatar yogeshsajanikar avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

llvm-hs-pretty's Issues

Extractvalue in global constant not supported?

Hey,

Thanks for maintaining the LLVM IR pretty printer!

Is it me or is the ExtractValue constant not supported?

instance Pretty C.Constant where
seems to err with "Non-function argument. (Malformed AST)" upon meeting one. As far as I can tell, it seems to be valid syntax. E.g:

%Age = type {i32}

@answer = private unnamed_addr constant i32 extractvalue (%Age {i32 42}, 0)

Thanks!

Inconsistent with llvm-hs when using 'Null'

(First time submitting issues, sorry for any inconvenience in advance)

When using (ppllvm) llvm-hs-pretty-0.1.0.0 and expressing 'Null' from LLVM.AST.Constant, the output would be different from the one

when I use (moduleLLVMAssembly) llvm-hs (I don't remember the version, but in cabal file, I denote "llvm-hs >= 4.0.0.0", so I believe it's the latest version in hackage) with the same LLVM.AST.Module.

More specifically,
Null (IntegerType 8)
would be translated into a pointer in llvm-hs but a "i8 zeroinitializer" in llvm-hs-pretty.

I am not sure which one is the real meaning for 'Null' constructor, but I think llvm-hs is doing correctly.

Consider adding extra newline after blocks

Hello! I'm really excited you all have built this project. It is much nicer to debug LLVM IR issues in my compiler when I can see it printed, versus when I make a mistake and just see a segfault from the C++ LLVM library 😄

I noticed that when I print my LLVM IR using moduleLLVMAssembly, I get wonderful newlines after each block:

; ModuleID = 'amy-module'
source_filename = "<string>"

define i64 @main() {
entry:
  %0 = call i64 @fib(i64 10)
  ret i64 %0
}

define private i64 @fib(i64 %x) {
entry:
  switch i64 %x, label %case.default.0 [
    i64 0, label %case.0.0
    i64 1, label %case.1.0
  ]

case.default.0:                                   ; preds = %entry
  %0 = sub i64 %x, 1
  %1 = call i64 @fib(i64 %0)
  %2 = sub i64 %x, 2
  %3 = call i64 @fib(i64 %2)
  %4 = add i64 %1, %3
  br label %case.end.0

case.0.0:                                         ; preds = %entry
  br label %case.end.0

case.1.0:                                         ; preds = %entry
  br label %case.end.0

case.end.0:                                       ; preds = %case.1.0, %case.0.0, %case.default.0
  %end.0 = phi i64 [ %4, %case.default.0 ], [ 0, %case.0.0 ], [ 1, %case.1.0 ]
  ret i64 %end.0
}

When I use llvm-hs-pretty, those newlines are gone:

; ModuleID = 'amy-module'


define external ccc i64 @main(){
entry:
  %0 = call ccc i64 @fib(i64 10)
  ret i64 %0
}

define private ccc i64 @fib(i64 %x){
entry:
  switch i64 %x, label %case.default.0 [i64 0, label %case.0.0 i64 1, label %case.1.0]
case.default.0:
  %1 = sub i64 %x, 1
  %2 = call ccc i64 @fib(i64 %1)
  %3 = sub i64 %x, 2
  %4 = call ccc i64 @fib(i64 %3)
  %5 = add i64 %2, %4
  br label %case.end.0
case.0.0:
  br label %case.end.0
case.1.0:
  br label %case.end.0
case.end.0:
  %end.0 = phi i64 [%5, %case.default.0], [0, %case.0.0], [1, %case.1.0]
  ret i64 %end.0
}

Do you think those newlines are nice enough to add to llvm-hs-pretty? If not, feel free to close this issue. I'm mostly just popping in with a suggestion.

Update llvm-hs-pretty to use the new monadic typeOf machinery in llvm-hs

The old non-monadic typeOf could not access types defined by the user via typedef since these are only available inside MonadModuleBuilder. The new monadic typeOf works correctly with user defined types, for example, the typeOf a NamedTypeReference is the referent type, not just the name. However, this means that llvm-hs-pretty needs an update to thread the monadic context through the pretty-printing code.

Pretty printing of floating point operations doesn't include fast math flags

FAdd {..} -> "fadd" <+> ppTyped operand0 `cma` pp operand1 <+> ppInstrMeta metadata
FSub {..} -> "fsub" <+> ppTyped operand0 `cma` pp operand1 <+> ppInstrMeta metadata
FMul {..} -> "fmul" <+> ppTyped operand0 `cma` pp operand1 <+> ppInstrMeta metadata
FDiv {..} -> "fdiv" <+> ppTyped operand0 `cma` pp operand1 <+> ppInstrMeta metadata
FRem {..} -> "frem" <+> ppTyped operand0 `cma` pp operand1 <+> ppInstrMeta metadata
FCmp {..} -> "fcmp" <+> pp fpPredicate <+> ppTyped operand0 `cma` pp operand1 <+> ppInstrMeta metadata

The testsuite doesn't do a full print/parse/print round trip.

The test suite doesn't check if the pretty-printed IR code matches the original code. As such, it only checks that the pretty-printer generates syntactically valid code.

I tried changing it to do a full round trip but this was easier said than done. Converting between a C++ module and a Haskell module changes things slightly (metadata gets shuffled, etc) which makes it difficult to verify that (parse.print) = id.

Nonexhaustive pattern

Thanks for the library! Unfortunately, it quickly fails for me.

	llvm-hs-pretty/src/LLVM/Pretty.hs:(248,3)-(261,26): Non-exhaustive patterns in function pp

`ppllvm . LLVM.Internal.Module.moduleAST` fails

The error message is: Expecting aggregate type. (Malformed AST)

I produced the .ll file with

clang++ -S -emit-llvm -o testfile.ll -c testfile.cc

Test files are attached.

If I just show the AST, it looks like it was parsed OK...
testfile.cc
testfile.ll

I'm using llvm 9.0.1

I suspect this has something to do with the fact that the latest available versions of llvm-hs-pretty and llvm-hs are 9.0.0 and 9.0.1, respectively (i.e. something needs updating).

Non-exhaustive patterns

src/LLVM/Pretty.hs:530:13-48: Non-exhaustive patterns in PointerType argTy _

I got this error when buiding some IR with llvm-hs-pretty

Unable to pretty print functions

Found this module failing with a pattern match error even though I can compile it just fine.

*** Exception: src/LLVM/Pretty.hs:485:7-66: Irrefutable pattern failed for pattern functionType@(FunctionType {..})
Module
{ moduleName = "calc"
, moduleSourceFileName = "<string>"
, moduleDataLayout = Nothing
, moduleTargetTriple = Nothing
, moduleDefinitions =
      [ GlobalDefinition
            (Function
             { linkage = External
             , visibility = Default
             , dllStorageClass = Nothing
             , callingConvention = C
             , returnAttributes = []
             , returnType = IntegerType {typeBits = 64}
             , name = Name "a"
             , parameters =
                   ( [Parameter (IntegerType {typeBits = 64}) (Name "x") []]
                   , False)
             , functionAttributes = []
             , section = Nothing
             , comdat = Nothing
             , alignment = 0
             , garbageCollectorName = Nothing
             , prefix = Nothing
             , basicBlocks =
                   [ BasicBlock
                         (Name "entry")
                         []
                         (Do
                              (Ret
                               { returnOperand =
                                     Just
                                         (LocalReference
                                              (IntegerType {typeBits = 64})
                                              (Name "x"))
                               , metadata' = []
                               }))
                   ]
             , personalityFunction = Nothing
             })
      , GlobalDefinition
            (Function
             { linkage = External
             , visibility = Default
             , dllStorageClass = Nothing
             , callingConvention = C
             , returnAttributes = []
             , returnType = IntegerType {typeBits = 64}
             , name = Name "main"
             , parameters =
                   ( [Parameter (IntegerType {typeBits = 64}) (Name "argv") []]
                   , False)
             , functionAttributes = []
             , section = Nothing
             , comdat = Nothing
             , alignment = 0
             , garbageCollectorName = Nothing
             , prefix = Nothing
             , basicBlocks =
                   [ BasicBlock
                         (Name "entry")
                         [ UnName 0 :=
                           Call
                           { tailCallKind = Nothing
                           , callingConvention = C
                           , returnAttributes = []
                           , function =
                                 Right
                                     (ConstantOperand
                                          (GlobalReference
                                               (IntegerType {typeBits = 64})
                                               (Name "a")))
                           , arguments =
                                 [ ( ConstantOperand
                                         (Int
                                          {integerBits = 64, integerValue = 4})
                                   , [])
                                 ]
                           , functionAttributes = []
                           , metadata = []
                           }
                         ]
                         (Do
                              (Ret
                               { returnOperand =
                                     Just
                                         (LocalReference
                                              (IntegerType {typeBits = 64})
                                              (UnName 0))
                               , metadata' = []
                               }))
                   ]
             , personalityFunction = Nothing
             })
      ]
}

Integral operations missing 'nuw', 'nsw' and 'exact' keywords

Add {..} -> "add" <+> ppTyped operand0 `cma` pp operand1 <+> ppInstrMeta metadata
Sub {..} -> "sub" <+> ppTyped operand0 `cma` pp operand1 <+> ppInstrMeta metadata
Mul {..} -> "mul" <+> ppTyped operand0 `cma` pp operand1 <+> ppInstrMeta metadata
Shl {..} -> "shl" <+> ppTyped operand0 `cma` pp operand1 <+> ppInstrMeta metadata
AShr {..} -> "ashr" <+> ppTyped operand0 `cma` pp operand1 <+> ppInstrMeta metadata
LShr {..} -> "lshr" <+> ppTyped operand0 `cma` pp operand1 <+> ppInstrMeta metadata
And {..} -> "and" <+> ppTyped operand0 `cma` pp operand1 <+> ppInstrMeta metadata
Or {..} -> "or" <+> ppTyped operand0 `cma` pp operand1 <+> ppInstrMeta metadata
Xor {..} -> "xor" <+> ppTyped operand0 `cma` pp operand1 <+> ppInstrMeta metadata
SDiv {..} -> "sdiv" <+> ppTyped operand0 `cma` pp operand1 <+> ppInstrMeta metadata
UDiv {..} -> "udiv" <+> ppTyped operand0 `cma` pp operand1 <+> ppInstrMeta metadata
SRem {..} -> "srem" <+> ppTyped operand0 `cma` pp operand1 <+> ppInstrMeta metadata
URem {..} -> "urem" <+> ppTyped operand0 `cma` pp operand1 <+> ppInstrMeta metadata

llvm-hs-pretty 0.2.1.0 build failure

As seen on the Stackage build server:

[1 of 2] Compiling LLVM.Pretty      ( src/LLVM/Pretty.hs, dist/build/LLVM/Prett$
.o )

src/LLVM/Pretty.hs:558:13: error:
    Not in scope: type constructor or class ‘MetadataNode’
    Perhaps you meant ‘MetadataNodeID’ (imported from LLVM.AST)
    |
558 | instance PP MetadataNode where
    |             ^^^^^^^^^^^^

src/LLVM/Pretty.hs:559:7: error:
    Not in scope: data constructor ‘MetadataNode’
    Perhaps you meant one of these:
      ‘MetadataNodeID’ (imported from LLVM.AST),
      ‘MetadataType’ (imported from LLVM.AST.Type)
    |
559 |   pp (MetadataNode xs) = "!" <> braces (commas (fmap ppMetadata xs))
    |       ^^^^^^^^^^^^

src/LLVM/Pretty.hs:560:7: error:
    Not in scope: data constructor ‘MetadataNodeReference’
    |
560 |   pp (MetadataNodeReference ref) = pp ref
    |       ^^^^^^^^^^^^^^^^^^^^^

It appears to be a build failure with llvm-hs-pure-0.6.2.

Fix Test Suite

Test cases to be completed before 0.1 stability.

  • comparison.ll
  • debug.ll
  • float.ll
  • for.ll
  • full.ll
  • hello.ll
  • if.ll
  • intrinsic.ll
  • loopnest.ll
  • multiple.ll
  • pair.ll
  • phi.ll
  • printf.ll
  • range.ll
  • record.ll
  • saxpy.ll
  • simple.ll
  • while.ll
  • cast.ll

Instruction Metadata

Currently most of the pretty printers toss out the optional instruction-level metadata. This should be as simple as writing a pretty printer for the InstructionMetadata instance and propagating it to the instruction printers.

Finish Instructions

Remaining instrutions to write pretty printers for:

  • CleanupRet instructions
  • CatchRet instructions
  • CatchSwitch instructions
  • AtomicRMW instructions
  • CmpXchg instructions
  • VAArg instructions
  • LandingPad instructions
  • CatchPad instructions
  • CleanupPad instructions
  • Invoke instructions

Null constant appears to be unnecessarily limited to certain types

ppNullInitializer :: Type -> Doc
ppNullInitializer PointerType {..} = "zeroinitializer"
ppNullInitializer StructureType {..} = "zeroinitializer"
ppNullInitializer FunctionType {..} = "zeroinitializer"
ppNullInitializer ArrayType {..} = "zeroinitializer"
ppNullInitializer _ = error "Non-pointer argument. (Malformed AST)"

From the language reference:

The string ‘zeroinitializer‘ can be used to zero initialize a value to zero of any type, including scalar and aggregate types. This is often used to avoid having to print large zero initializers (e.g. for large arrays) and is always exactly equivalent to using explicit zero initializers.
https://llvm.org/docs/LangRef.html#complex-constants

Test failures

stack test fails for me. I have no local changes and is using the current master.

$ llc --version
LLVM (http://llvm.org/):
  LLVM version 4.0.0
  Optimized build.
  Default target: x86_64-unknown-linux-gnu
  Host CPU: skylake

This is the complete build log.

Test: tests/input/intrinsic.ll
================================================================================
tests/input/intrinsic.ll
================================================================================
Module
  { moduleName = "<string>"
  , moduleSourceFileName = "<string>"
  , moduleDataLayout = Nothing
  , moduleTargetTriple = Nothing
  , moduleDefinitions =
      [ GlobalDefinition
          Function
            { linkage = External
            , visibility = Default
            , dllStorageClass = Nothing
            , callingConvention = C
            , returnAttributes = []
            , returnType =
                FloatingPointType { typeBits = 64 , floatingPointFormat = IEEE }
            , name = Name "llvm.sqrt.f64"
            , parameters =
                ( [ Parameter
                      FloatingPointType { typeBits = 64 , floatingPointFormat = IEEE }
                      (UnName 0)
                      []
                  ]
                , False
                )
            , functionAttributes = [ Left (GroupID 0) ]
            , section = Nothing
            , comdat = Nothing
            , alignment = 0
            , garbageCollectorName = Nothing
            , prefix = Nothing
            , basicBlocks = []
            , personalityFunction = Nothing
            }
      , GlobalDefinition
          Function
            { linkage = External
            , visibility = Default
            , dllStorageClass = Nothing
            , callingConvention = C
            , returnAttributes = []
            , returnType =
                FloatingPointType { typeBits = 64 , floatingPointFormat = IEEE }
            , name = Name "main"
            , parameters = ( [] , False )
            , functionAttributes = []
            , section = Nothing
            , comdat = Nothing
            , alignment = 0
            , garbageCollectorName = Nothing
            , prefix = Nothing
            , basicBlocks =
                [ BasicBlock
                    (Name "entry")
                    [ UnName 0 :=
                        Call
                          { tailCallKind = Nothing
                          , callingConvention = C
                          , returnAttributes = []
                          , function =
                              Right
                                (ConstantOperand
                                   (GlobalReference
                                      PointerType
                                        { pointerReferent =
                                            FunctionType
                                              { resultType =
                                                  FloatingPointType
                                                    { typeBits = 64 , floatingPointFormat = IEEE }
                                              , argumentTypes =
                                                  [ FloatingPointType
                                                      { typeBits = 64 , floatingPointFormat = IEEE }
                                                  ]
                                              , isVarArg = False
                                              }
                                        , pointerAddrSpace = AddrSpace 0
                                        }
                                      (Name "llvm.sqrt.f64")))
                          , arguments =
                              [ ( ConstantOperand Float { floatValue = Double 2.0 } , [] ) ]
                          , functionAttributes = []
                          , metadata = []
                          }
                    ]
                    (Do
                       Ret
                         { returnOperand =
                             Just
                               (LocalReference
                                  FloatingPointType { typeBits = 64 , floatingPointFormat = IEEE }
                                  (UnName 0))
                         , metadata' = []
                         })
                ]
            , personalityFunction = Nothing
            }
      , FunctionAttributes (GroupID 0) [ NoUnwind , ReadNone ]
      ]
  }
; ModuleID = '<string>'

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

define external double @main(){
entry:
  %0 = call double @"llvm.sqrt.f64"(double 2.000000e0)
  ret double %0
}

attributes #0 = {nounwind readnone}
Round Tripped!
Test: tests/input/comparison.ll
================================================================================
tests/input/comparison.ll
================================================================================
Error reading input:
<string>:7:18: error: expected comma after load's type
  %0 = load i32* %x.addr
                 ^

Metadata printed twice for SExt, ZExt, FPExt, Trunc and FPTrunc

SExt {..} -> "sext" <+> ppTyped operand0 <+> "to" <+> pp type' <+> ppInstrMeta metadata <+> ppInstrMeta metadata
ZExt {..} -> "zext" <+> ppTyped operand0 <+> "to" <+> pp type' <+> ppInstrMeta metadata <+> ppInstrMeta metadata
FPExt {..} -> "fpext" <+> ppTyped operand0 <+> "to" <+> pp type' <+> ppInstrMeta metadata <+> ppInstrMeta metadata
Trunc {..} -> "trunc" <+> ppTyped operand0 <+> "to" <+> pp type' <+> ppInstrMeta metadata <+> ppInstrMeta metadata
FPTrunc {..} -> "fptrunc" <+> ppTyped operand0 <+> "to" <+> pp type' <+> ppInstrMeta metadata <+> ppInstrMeta metadata

llvm-dev-5.0 needed?

The README.md says

Usage

sudo apt-get install llvm-dev-5.0

There is a single function ppllvm that maps a LLVM.AST.Module to a String.

without explaining why the C package needs to be installed. This is confusing, since it also says

Goal is to be able to pretty print a sufficiently large subset of the LLVM AST from pure Haskell without having to go through the C++ API.

Is it only needed for the tests maybe?

Hackage maintainer

@sdiehl Hi Stephen, could I ask you to add me (Hackage user account andrew_wja) to the maintainers of llvm-hs-pretty on Hackage? I know (from asking questions on llvm.discourse.group) that the LLVM devs tend to treat the textual IR as a second-class citizen after the bitcode representation, but I've found it incredibly useful in my own work with LLVM, so I'd like to make a matching llvm-hs-pretty-9.0.1.1 release on Hackage to accompany the upcoming llvm-hs-9.0.1.1 bugfix/improvement release.

I don't think hackage is up to date for this package...

Something weird but I got an error building this package as a dependency from Hackage... and I just cabal updated -- building from the head was ok, but package version seems the same in both cases.

Anyway the error was:

Building library for llvm-hs-pretty-0.5.0.0..
[1 of 2] Compiling LLVM.Pretty      ( src/LLVM/Pretty.hs, dist/build/LLVM/Pretty.o )

src/LLVM/Pretty.hs:852:10: error:
    Not in scope: data constructor ‘None’
    |
852 |   pretty None = "CSK_None"
    |          ^^^^

But that has gone away if I build this package from the head (should there be a version bump?)
I got a bunch of incomplete-uni-patterns warnings but it all seems to work.

I'm using ghc --version The Glorious Glasgow Haskell Compilation System, version 8.4.4 on OSX if that's any help and cabal new-* cabal --version cabal-install version 2.4.0.0 compiled using version 2.4.0.1 of the Cabal library sans stack -- which might be a problem?

llvm-hs-pretty 0.3 from tarball fails test suite

As seen on the Stackage build server.

> /tmp/stackage-build12/llvm-hs-pretty-0.3.0.0$ dist/build/test/test
test: tests/input/: getDirectoryContents:openDirStream: does not exist (No such file or directory)

I will mark this as an expected test failure on Stackage until the issue is resolved.

Build error on type checking on the llvm-12 branch

The build for llvm-hs-pretty on the llvm12 branch fails (I have tried a few different commits). The error is:

llvm-hs-pretty> configure
llvm-hs-pretty> Configuring llvm-hs-pretty-12.0.0...
llvm-hs-pretty> build
llvm-hs-pretty> Preprocessing library for llvm-hs-pretty-12.0.0..
llvm-hs-pretty> Building library for llvm-hs-pretty-12.0.0..
llvm-hs-pretty> [1 of 1] Compiling LLVM.Pretty
llvm-hs-pretty>
llvm-hs-pretty> /tmp/stack-08f048299826d3a9/llvm-hs-pretty-12.0.0/src/LLVM/Pretty.hs:538:11: error:
llvm-hs-pretty> • Couldn't match expected type ‘m7 (Either String Type)’
llvm-hs-pretty> with actual type ‘Type’
llvm-hs-pretty> • In the pattern: PointerType argTy_ _
llvm-hs-pretty> In a case alternative: PointerType argTy_ _ -> argTy_
llvm-hs-pretty> In the expression:
llvm-hs-pretty> case typeOf address of
llvm-hs-pretty> PointerType argTy_ _ -> argTy_
llvm-hs-pretty> _ -> error "invalid load of non-pointer type. (Malformed AST)"
llvm-hs-pretty> |
llvm-hs-pretty> 538 | PointerType argTy_ _ -> argTy_
llvm-hs-pretty> | ^^^^^^^^^^^^^^^^^^^^
llvm-hs-pretty>
llvm-hs-pretty> /tmp/stack-08f048299826d3a9/llvm-hs-pretty-12.0.0/src/LLVM/Pretty.hs:553:38: error:
llvm-hs-pretty> • Couldn't match expected type ‘Type’
llvm-hs-pretty> with actual type ‘m8 (Either String Type)’
llvm-hs-pretty> • In the second argument of ‘($)’, namely ‘typeOf address’
llvm-hs-pretty> In the expression: getElementType $ typeOf address
llvm-hs-pretty> In an equation for ‘argTy’: argTy = getElementType $ typeOf address
llvm-hs-pretty> |
llvm-hs-pretty> 553 | where argTy = getElementType $ typeOf address
llvm-hs-pretty> | ^^^^^^^^^^^^^^
llvm-hs-pretty>
llvm-hs-pretty> /tmp/stack-08f048299826d3a9/llvm-hs-pretty-12.0.0/src/LLVM/Pretty.hs:1133:9: error:
llvm-hs-pretty> • Couldn't match expected type ‘m6 (Either String Type)’
llvm-hs-pretty> with actual type ‘Type’
llvm-hs-pretty> • In the pattern: PointerType argTy_ _
llvm-hs-pretty> In a case alternative: PointerType argTy_ _ -> argTy_
llvm-hs-pretty> In the expression:
llvm-hs-pretty> case typeOf address of
llvm-hs-pretty> PointerType argTy_ _ -> argTy_
llvm-hs-pretty> _ -> error "invalid load of non-pointer type. (Malformed AST)"
llvm-hs-pretty> |
llvm-hs-pretty> 1133 | PointerType argTy_ _ -> argTy_
llvm-hs-pretty> | ^^^^^^^^^^^^^^^^^^^^
llvm-hs-pretty>
llvm-hs-pretty> /tmp/stack-08f048299826d3a9/llvm-hs-pretty-12.0.0/src/LLVM/Pretty.hs:1319:44: error:
llvm-hs-pretty> • Couldn't match expected type ‘Type’
llvm-hs-pretty> with actual type ‘m4 (Either String Type)’
llvm-hs-pretty> • In the first argument of ‘referencedType’, namely ‘(typeOf f)’
llvm-hs-pretty> In the expression: (referencedType (typeOf f))
llvm-hs-pretty> In the expression:
llvm-hs-pretty> case (referencedType (typeOf f)) of
llvm-hs-pretty> fty@FunctionType {..} -> fty
llvm-hs-pretty> _ -> error "Calling non function type. (Malformed AST)"
llvm-hs-pretty> |
llvm-hs-pretty> 1319 | functionType = case (referencedType (typeOf f)) of
llvm-hs-pretty> | ^^^^^^^^
llvm-hs-pretty>
llvm-hs-pretty> /tmp/stack-08f048299826d3a9/llvm-hs-pretty-12.0.0/src/LLVM/Pretty.hs:1362:43: error:
llvm-hs-pretty> • Couldn't match expected type ‘Type’
llvm-hs-pretty> with actual type ‘m5 (Either String Type)’
llvm-hs-pretty> • In the first argument of ‘referencedType’, namely ‘(typeOf f)’
llvm-hs-pretty> In the expression: referencedType (typeOf f)
llvm-hs-pretty> In the expression:
llvm-hs-pretty> case referencedType (typeOf f) of
llvm-hs-pretty> fty@FunctionType {..} -> fty
llvm-hs-pretty> _ -> error "Invoking non-function type. (Malformed AST)"
llvm-hs-pretty> |
llvm-hs-pretty> 1362 | functionType = case referencedType (typeOf f) of
llvm-hs-pretty> | ^^^^^^^^
llvm-hs-pretty>
Progress 1/2

-- While building package llvm-hs-pretty-12.0.0 (scroll up to its section to see the error) using:
/home/jdgallag/.stack/setup-exe-cache/x86_64-linux-tinfo6/Cabal-simple_mPHDZzAJ_3.2.1.0_ghc-8.10.4 --builddir=.stack-work/dist/x86_64-linux-tinfo6/Cabal-3.2.1.0 build --ghc-options " -fdiagnostics-color=always"
Process exited with code: ExitFailure 1

In the Stack.yaml file, I have

extra-deps:
  (...)
  - git: https://github.com/llvm-hs/llvm-hs-pretty.git
    commit: c26764e2dcef78d640bbbc18518eaabda92603c0

(this isn't the latest commit here, but the issue seems to exist on multiple commits, at least for me).

And in the Package.yaml file I have

dependencies:
  (...)
 - llvm-hs-pretty

I also tried without and without combinations of the following options in Stack.yaml:

ghc-options:
llvm-hs: -optcxx=-std=c++14 -optcxx=-lstdc++ -optcxx=-fno-rtti

flags:
llvm-hs:
shared-llvm: true

Is the build indeed failing, or am I missing something obvious here. The llvm-hs and llvm-hs-pure packages both succeed on the llvm-12 branch.

invalid load of non-pointer type

ready> def f(x) x; f(2);
[Function "f" ["x"] (Var "x"),Call "f" [Float 2.0]]
; ModuleID = 'my'


define external ccc  double @f(double  %x)    {
entry:
  %1 = alloca double
  store  kaleidoscope-haskell-exe: invalid load of non-pointer type. (Malformed AST)
CallStack (from HasCallStack):
  error, called at src/LLVM/Pretty.hs:534:16 in llvm-hs-pretty-0.9.0.0-GQL9cTVWwSMGcQCiKyIMt7:LLVM.Pretty

Support for Inline Assembly

I suppose this is a feature/extension request.

Trying to pretty print a Call AST node where the function is Left (IA.InlineAssembly {...}) currently isn't implemented and gives "Non-callable argument. (Malformed AST)" despite llvm-hs having support for it.

I've got it "working" in my fork. I can PR it if it's helpful, though to be honest, I didn't really know what I was doing.

`llvm-hs-pretty` produces invalid IR where `llvm-hs` produces valid IR

I noticed two cases where llvm-hs accepts and seemingly implicitly corrects an LLVM.AST.Module that is in principle ill-formed.
llvm-hs-pretty on the other hand produces IR that will then be rejected by the LLVM parser.

The following code demonstrates those two cases:

{-# LANGUAGE OverloadedStrings #-}

import Control.Exception
import Data.ByteString (ByteString)
import qualified Data.ByteString.Lazy
import qualified Data.Text.Lazy.Encoding

import LLVM.AST as AST
import LLVM.AST.Constant
import LLVM.AST.Global
import LLVM.AST.Type

import LLVM.Context
import LLVM.Exception
import LLVM.Module

import LLVM.Pretty

example1 :: AST.Module
example1 = defaultModule
  { moduleDefinitions =
      [ GlobalDefinition functionDefaults
          { name = "test"
          , returnType = void
          , basicBlocks =
              [ BasicBlock "entry"
                  [ UnName 0 := Alloca i32 Nothing 0 []
                  , UnName 1 := Store False (LocalReference (ptr i32) (UnName 0)) (ConstantOperand (Int 32 42)) Nothing 0 []
                  ]
                  (Do $ Ret Nothing [])
              ]
          }
      ]
  }

example2 :: AST.Module
example2 = defaultModule
  { moduleDefinitions =
      [ GlobalDefinition functionDefaults
          { name = "test"
          , returnType = void
          , basicBlocks =
              [ BasicBlock "entry"
                  [ UnName 0 := Alloca (ptr $ FunctionType void [] False) Nothing 0 []
                  , Do $ Store False
                      (LocalReference (ptr $ ptr $ FunctionType void [] False) (UnName 0))
                      (ConstantOperand $ GlobalReference (FunctionType void [] False) "test")
                      Nothing 0 []
                  ]
                  (Do $ Ret Nothing [])
              ]
          }
      ]
  }


prettyLLVMAssembly :: AST.Module -> ByteString
prettyLLVMAssembly = Data.ByteString.Lazy.toStrict . Data.Text.Lazy.Encoding.encodeUtf8 . ppllvm


llvmAssembly :: AST.Module -> IO ByteString
llvmAssembly ast =
  withContext $ \ctx ->
  withModuleFromAST ctx ast moduleLLVMAssembly


parseLLVMAssembly :: ByteString -> IO (Either ParseFailureException ())
parseLLVMAssembly s = try $
  withContext $ \ctx ->
  withModuleFromLLVMAssembly ctx s $ \_ ->
  pure ()


main :: IO ()
main = do
  putStrLn "Example 1: Instructions returning void are implicitly un-named" 
  putStrLn $ replicate 50 '='
  putStrLn "Using llvm-hs:"
  printResult =<< parseLLVMAssembly =<< llvmAssembly example1
  putStrLn $ replicate 50 '-'
  putStrLn "Using llvm-hs-pretty:"
  printResult =<< parseLLVMAssembly (prettyLLVMAssembly example1)

  putStrLn ""
  
  putStrLn "Example 2: Global references to functions are implicitly cast to pointers" 
  putStrLn $ replicate 50 '='
  putStrLn "Using llvm-hs:"
  printResult =<< parseLLVMAssembly =<< llvmAssembly example2
  putStrLn $ replicate 50 '-'
  putStrLn "Using llvm-hs-pretty:"
  printResult =<< parseLLVMAssembly (prettyLLVMAssembly example2)

  where
    printResult (Right ()) = putStrLn "OK" 
    printResult (Left (ParseFailureException err)) = putStr err

In the first example an instruction that produces void is named, which is illegal.
In the second example a global reference to a function is not typed as function pointer, which it should be.

The above code produces the following output:

Example 1: Instructions returning void are implicitly un-named
==================================================
Using llvm-hs:
OK
--------------------------------------------------
Using llvm-hs-pretty:
<string>:6:3: error: instructions returning void cannot have a name
  %1 = store i32 42, i32* %0
  ^

Example 2: Global references to functions are implicitly cast to pointers
==================================================
Using llvm-hs:
OK
--------------------------------------------------
Using llvm-hs-pretty:
<string>:6:17: error: functions are not values, refer to them as pointers
  store void () @test, void ()** %0
                ^

I'm actually not sure at what stage those implicit corrections happen.
It might well be that this happens within llvm itself (i.e. outside of llvm-hs).
I'm also not sure if llvm-hs-pretty should even try to emulate those implicit corrections.
However, in any case its a pitfall to be aware of.

Build failure due to syntax error in as-pattern

llvm-hs-pretty> /tmp/stack-04e76048a098e482/llvm-hs-pretty-0.9.0.0/src/LLVM/Pretty.hs:480:7: error:
llvm-hs-pretty>     Found a binding for the ‘@’ operator in a pattern position.
llvm-hs-pretty>     Perhaps you meant an as-pattern, which must not be surrounded by whitespace
llvm-hs-pretty>     |
llvm-hs-pretty> 480 |     e @ Invoke {..} ->
llvm-hs-pretty>     |       ^

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.