llvm-hs-examples icon indicating copy to clipboard operation
llvm-hs-examples copied to clipboard

Other Examples

Open sdiehl opened this issue 9 years ago • 19 comments

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

  • Read and writing IR, Bytecode from disk.
  • Optimizer pass customization
  • libffi integration
  • Target customization

sdiehl avatar Jan 18 '17 15:01 sdiehl

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

cocreature avatar Jan 18 '17 17:01 cocreature

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 avatar Jan 29 '17 13:01 ckoparkar

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 ?

ckoparkar avatar Jan 29 '17 14:01 ckoparkar

@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 avatar Jan 29 '17 16:01 cocreature

@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 :-)

ckoparkar avatar Jan 29 '17 16:01 ckoparkar

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 avatar Jan 29 '17 21:01 sdiehl

@sdiehl Thanks!

ckoparkar avatar Jan 29 '17 23:01 ckoparkar

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.

ghost avatar Feb 20 '18 01:02 ghost

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.

sdiehl avatar Feb 20 '18 07:02 sdiehl

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.

ghost avatar Feb 22 '18 02:02 ghost

@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 avatar Feb 22 '18 06:02 cocreature

@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 avatar Feb 22 '18 07:02 sdiehl

@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 avatar Feb 22 '18 11:02 cocreature

@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.

ghost avatar Feb 23 '18 02:02 ghost

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.

sdiehl avatar Feb 23 '18 07:02 sdiehl

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.

cocreature avatar Feb 23 '18 17:02 cocreature

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.

ghost avatar Feb 25 '18 01:02 ghost

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™.

cocreature avatar Feb 26 '18 12:02 cocreature

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 :).

ghost avatar Feb 28 '18 03:02 ghost