llvm-hs / llvm-hs-examples

Examples for Haskell bindings to LLVM
MIT License
70 stars 20 forks source link

Other Examples #2

Open sdiehl opened 7 years ago

sdiehl commented 7 years ago

Any ideas on what other simple use case examples I should make for the bindings. Was thinking about some of these:

cocreature commented 7 years ago

The last three seem to me like they are the most interesting and useful ones, probably in the order you listed them.

ckoparkar commented 7 years ago

I'm pretty new to llvm-hs, and llvm in general and this may sound dumb compared to the other ideas. But can you please help me by posting an example which generates printf ? I've been having a tough time using GetElementPtr to convert the char array to a pointer, and generate printf("%d", 42).

Also, what do you guys think about having a gitter channel ? Or a mailing list perhaps ? @sdiehl, thanks for the blog-post! It helped me a lot. But other than that, there aren't many resources available I guess. I mean, besides the Hackage documentation.

ckoparkar commented 7 years ago

I found a workaround, sort of. I'm just creating a "library" of functions like print_int, print_string etc, and using that when compiling my IR. Is this the best way to do this ?

cocreature commented 7 years ago

@cskksc One easy way to figure out how something is represented in LLVM is to take a look at the output of clang -flto -S. You can then use withModuleFromLLVMAssembly context <string representation of module> moduleAST to get the llvm-hs ast from that and print it to see how it looks.

A simplified example of this output can be seen in https://gist.github.com/cocreature/93625b5afac68eb7de8b2eaa44561ab6. This works fine if you just want to generate LLVM IR. You need to link against glibc to be able to actually run this. In JITed code you need to make sure that the symbol resolvers are able to find the printf symbol in your current process (since Haskell executables link against glibc I think it should already be available). I don’t remember the exact steps needed for that.

ckoparkar commented 7 years ago

@cocreature Thanks a lot! Right now I'm just generating the IR file and compiling it by hand using clang. So I was successfully able to run a toy print_int program, generated with llvm-hs. I was stuck on generating the IR for printing strings. But this helps a lot. And using withModuleFromLLVMAssembly is neat. That should help me figure out some other things too. Thanks again :-)

sdiehl commented 7 years ago

I'll make an example for compiling variadic functions like printf. It's a little tricky with LLVM and probably worthy of an example.

ckoparkar commented 7 years ago

@sdiehl Thanks!

ghost commented 6 years ago

It would be great to have an example of conditional branch where a symbol table is also kept. I am confused how to use the recursive do with StateT wrapped around IRBuilder.

sdiehl commented 6 years ago

Ok, I'll add some more IRBuilder examples. I was planning on just rewriting the Kaleidoscope tutorial to use it which should hit all the features.

ghost commented 6 years ago

Thanks, as a matter of fact I am working through the Kaleidoscope tutorial. What I am stuck at is how to keep environment, for example in entry block there is a new variable, and you want to refer to it in the if/else blocks. I looked at StateT, but it has no instance of MonadFix.

cocreature commented 6 years ago

@pavolzetor I don’t quite understand what problem you are running into, maybe you just need a phi node? Could you provide an example of the code you are trying to generate? Also StateT does have a MonadFix instance.

sdiehl commented 6 years ago

@cocreature This is actually an issue I'm hitting as well, I might need to add a function to forward declare references to blocks. The cbr requires us to create two blocks enter one, and then add instructions to the second one after finishing the first. This doesn't fit naturally into the IRBuilder model currently.

https://github.com/sdiehl/kaleidoscope/blob/master/src/chapter7/Emit.hs#L122

cocreature commented 6 years ago

@sdiehl Sorry I still don’t get it, why does the following example not work for your usecase? I feel like I’m missing something obvious here :)

simple :: Module
simple = buildModule "exampleModule" $ mdo
  function "f" [(AST.i32, "a")] AST.i32 $ \[a] -> mdo
    entry <- block `named` "entry"
    cond <- icmp P.EQ a (ConstantOperand (C.Int 32 0))
    condBr cond ifThen ifElse
    ifThen <- block
    trVal <- add a (ConstantOperand (C.Int 32 0))
    br ifExit
    ifElse <- block `named` "if.else"
    flVal <- add a (ConstantOperand (C.Int 32 0))
    br ifElse
    ifExit <- block `named` "if.exit"
    r <- phi [(trVal, ifThen), (flVal, ifElse)]
    ret r
ghost commented 6 years ago

@cocreature it should be ifExit. I can't find MonadFix instance in Foundation.Monad.State. Anyhow, here is a simple example that I do not know how to handle using IRBuilder.

int
main(void)
{
        int x = 10;
        if (x)
                x = 1;
        else
                x = 2;
        return x;
}

Code from Clang:

define i32 @main() #0 {
  %1 = alloca i32, align 4
  %2 = alloca i32, align 4
  store i32 0, i32* %1, align 4
  store i32 10, i32* %2, align 4
  %3 = load i32, i32* %2, align 4
  %4 = icmp ne i32 %3, 0
  br i1 %4, label %5, label %6

; <label>:5:                                      ; preds = %0
  store i32 1, i32* %2, align 4
  br label %7

; <label>:6:                                      ; preds = %0
  store i32 2, i32* %2, align 4
  br label %7

; <label>:7:                                      ; preds = %6, %5
  %8 = load i32, i32* %2, align 4
  ret i32 %8
}

The issue I am having is that I want to populate environment with declarations as I go and refer to them using that environment.

sdiehl commented 6 years ago

I can't find MonadFix instance in Foundation.Monad.State.

If you're using an alternative prelude that doesn't include MonadFix then this is the issue. You should request this upstream in Foundation in you need it.

cocreature commented 6 years ago

Until foundation adds the MonadFix instance you could also just be using StateT from transformers. Ofc the interface to that might deviate from the one in foundation but I doubt the differences are particularly large.

ghost commented 6 years ago

Thanks, that worked. I reported the issue and will think if there is a better way to solve the problem then rely on mdo, especially for back edges.

Here is a link to a subset of kaleidoscope https://github.com/pavolzetor/kaleidoscope-compiler. I may add custom operators and JIT later.

cocreature commented 6 years ago

will think if there is a better way to solve the problem then rely on mdo, especially for back edges.

What exactly is bothering you about mdo? IMHO this is pretty much the perfect usecase for MonadFix. While I completely agree that understanding MonadFix can be a bit tricky, ime using it generally tends to be quite straightforward and minus the occasional infinite loop it just works™.

ghost commented 6 years ago

Higher bar for beginners. I agree using MonadFix is elegant in this case and I need to study it more.

In general, if a feature is not that commonly used, it is very important to document the tought process so it is clear why it is necessary/useful. It took me while to understand why it was useful in this particular case :).