Open sdiehl opened 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.
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.
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 ?
@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.
@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 :-)
I'll make an example for compiling variadic functions like printf. It's a little tricky with LLVM and probably worthy of an example.
@sdiehl Thanks!
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.
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.
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.
@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.
@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
@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
@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.
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.
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.
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.
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™.
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 :).
Any ideas on what other simple use case examples I should make for the bindings. Was thinking about some of these: