Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Should there be a higher level API? #18

Draft
wants to merge 11 commits into
base: main
Choose a base branch
from

Conversation

jumerckx
Copy link
Collaborator

Inspired by Beaver I've been thinking about the possiblity of a higher level API to write MLIR IR. At the lowest level, adding operations to a block could be achieved by using a similar mechanism as the context in thread local storage:

@Block begin # pushes a block to a block-stack in thread-local storage
  c = arith.constant(123) # each operation function returns its result value, internally it pushes the operation itself to the block in the thread-local storage.
  d = c
  for _ in 1:10
    d = rand() > 0.5 ? :  arith.addi(c, d) : arith.muli(c, d)
  end
end

using esc in the macro would make sure that the created values are available outside the @Block expression, enabling other blocks to reference those values as well.

Things fall apart when introducing control flow. cf.br needs to be able to reference blocks that are yet to be created. I tried writing @Region and @Block which I believe is a dumbed-down version of how things work in Beaver (I don't really understand Elixir, code). This is the code in this PR but it isn't meant for merging, rather for showing what I tried and didn't work very well.

using MLIR: IR
using MLIR.Dialects: Func, Arith, CF
using MLIR.Builder

ctx = IR.Context()

myregion = @Region begin
    b1 = @Block begin
        Arith.constant(2)
        println("b1")
        CF.br(b2)
    end
    b2 = @Block begin
        println("b2")
    end
end

Here, @Block pushes the code it encompasses on a stack and first creates all blocks. Only at the end is the actual code from within each block run. I got this working using eval which isn't good all variables are then visible in module scope.
Also, even if this approach worked, I believe it's not entirely correct because blocks that are dominated by a block can access its values, this doesn't necessarily mean that those values are defined in order in code. e.g. if bb3 dominates bb2, bb2 can access it's values.
Lastly, block arguments aren't accounted for here but I imagine these could be added to the macro (@Block arg::argtype begin )

At this point I think it might not be worth it to try writing an all-encompassing high-level API that is quickly becoming riddled by magic (which I've already been warned of by @maleadt, who mentors my master thesis). But maybe there is some middleground such as operation functions returning their value or perhaps even using the automatic pushing to the block on the thread-local stack?
Any feedback would be greatly appreciated!

Jules

@jumerckx jumerckx changed the base branch from main to pb/ir_api August 19, 2023 18:18
@vchuravy
Copy link
Collaborator

I think long-term the answer is yes, but I would for now focus on getting the fundamentals in. #14 and #15 would be more impactful for now.
I don't have time to work on that so if that's something that interest you, you should go for it.

@vchuravy vchuravy deleted the branch JuliaLLVM:main September 29, 2023 13:39
@vchuravy vchuravy closed this Sep 29, 2023
@vchuravy vchuravy reopened this Sep 29, 2023
@vchuravy vchuravy changed the base branch from pb/ir_api to main September 29, 2023 13:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants