-
Notifications
You must be signed in to change notification settings - Fork 9
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
WIP tblgen #19
WIP tblgen #19
Conversation
This looks great! Should we use modules for names pacing instead of name prefixes? |
Yes definitely, removing the prefix is already easily done using |
I added optional attributes by optionally pushing them in an attributes array. The gist with output for LLVMOps is updated. function Load(location, type_0, addr_, alignment_, syncscope_)
attributes = []
(alignment_ != nothing) && push!(attributes, NamedAttribute("alignment", Attribute(alignment_)))
(syncscope_ != nothing) && push!(attributes, NamedAttribute("syncscope", Attribute(syncscope_)))
create_operation(
"llvm.load", location,
results = [type_0],
operands = [addr_]
owned_regions = [],
successors = [],
attributes = attributes,
result_inference=false
)
end Still to-do is making the arguments for optional attributes kwargs with default value nothing. function Load(location, type_0, addr_; alignment_=nothing, syncscope_=nothing)
... When this is done, the generator should hopefully be useful already. A nice improvement would be to add types to the attribute arguments which can be done using something similar to this I haven't had a lot of time to work on this the past week, and the coming two weeks I'm on holiday but I'll pick up where I left off when I return. |
Yeah I am unsure if each new attribute should get its own type, but maybe there are classes of attributes we can group together? Probably looking at what the Python MLIR tools do would make sense |
Example output for an function AtomicCmpXchg(location::Location, type_0::MLIRType, ptr_::Value, cmp_::Value, val_::Value, success_ordering_::Union{NamedAttribute, Attribute}, failure_ordering_::Union{NamedAttribute, Attribute}, syncscope_=nothing::Union{Nothing, Union{NamedAttribute, String}}, alignment_=nothing::Union{Nothing, Union{NamedAttribute, Int64}}, weak_=nothing::Union{Nothing, Union{NamedAttribute, Attribute}}, volatile__=nothing::Union{Nothing, Union{NamedAttribute, Attribute}}, access_groups_=nothing::Union{Nothing, Union{NamedAttribute, Attribute}}, alias_scopes_=nothing::Union{Nothing, Union{NamedAttribute, Attribute}}, noalias_scopes_=nothing::Union{Nothing, Union{NamedAttribute, Attribute}}, tbaa_=nothing::Union{Nothing, Union{NamedAttribute, Attribute}})
attributes = [make_named_attribute("success_ordering", success_ordering_), make_named_attribute("failure_ordering", failure_ordering_)]
(syncscope_ != nothing) && push!(attributes, make_named_attribute("syncscope", syncscope_))
(alignment_ != nothing) && push!(attributes, make_named_attribute("alignment", alignment_))
(weak_ != nothing) && push!(attributes, make_named_attribute("weak", weak_))
(volatile__ != nothing) && push!(attributes, make_named_attribute("volatile_", volatile__))
(access_groups_ != nothing) && push!(attributes, make_named_attribute("access_groups", access_groups_))
(alias_scopes_ != nothing) && push!(attributes, make_named_attribute("alias_scopes", alias_scopes_))
(noalias_scopes_ != nothing) && push!(attributes, make_named_attribute("noalias_scopes", noalias_scopes_))
(tbaa_ != nothing) && push!(attributes, make_named_attribute("tbaa", tbaa_))
create_operation(
"llvm.cmpxchg", location,
results = [type_0],
operands = [ptr_, cmp_, val_],
owned_regions = [],
successors = [],
attributes = attributes,
result_inference=false
)
end
The gist is updated, I also included the output from Python's tblgen generator. I didn't yet look closely at how owned_regions and successors are handled as these don't occur very much but this seems like the logical next step. As always, feedback is appreciated! |
The c++ is not very pretty, but it now generates wrappers for all operations in a host of dialects I tried (Arith, Func, CF, GPU, LLVM, and PDL. All added to the gist). Currently supported attributes (can be easily extended):
Some operations expect an attribute that has no CAPI function to create it, it seems that we're out of luck for those and need to implement CAPI functions ourselves. Should generated wrappers for in-tree dialects be added to the source? |
Does Should this code be included as is or should I also generate and include the wrappers for different dialects and LLVM versions? |
I rewrote the generator from scratch here, with the generated output for some dialects here. Most of everything in one big function but the result is more than half as short and does a bit more. Some refactoring might be useful but I personally think the code is already a bit easier to follow than before.
I did a quick smoke test to see whether result inference and operand segment size attributes are correct, and they seem to be. Smoke test code sampleusing MLIR
using MLIR: IR, API
ctx = IR.Context()
function registerAllDialects!()
ctx = IR.context()
registry = API.mlirDialectRegistryCreate()
API.mlirRegisterAllDialects(registry)
API.mlirContextAppendDialectRegistry(ctx, registry)
API.mlirDialectRegistryDestroy(registry)
API.mlirContextLoadAllAvailableDialects(ctx)
return registry
end
registerAllDialects!();
API.mlirRegisterAllPasses()
API.mlirRegisterAllLLVMTranslations(ctx.context)
b0 = IR.Block()
cond = IR.push_argument!(b0, IR.MLIRType(Bool), IR.Location())
a = IR.get_result(push!(b0, MLIR.Dialects.Arith.constant(; value=IR.Attribute(42))))
b = IR.get_result(push!(b0, MLIR.Dialects.Arith.constant(; value=IR.Attribute(Int32(43)))))
b1 = IR.Block()
IR.push_argument!(b1, IR.MLIRType(Int), IR.Location())
b2 = IR.Block()
IR.push_argument!(b2, IR.MLIRType(Int), IR.Location())
IR.push_argument!(b2, IR.MLIRType(Int32), IR.Location())
push!(b0, MLIR.Dialects.ControlFlow.cond_br(cond, [a], [a, b]; trueDest=b1, falseDest=b2))
r = IR.Region()
push!.(Ref(r), [b0, b1, b2])
@show MLIR.Dialects.Builtin.module_(; bodyRegion=r)
# "builtin.module"() ({
# ^bb0(%arg0: i1):
# %0 = "arith.constant"() <{value = 42 : i64}> : () -> i64
# %1 = "arith.constant"() <{value = 43 : i32}> : () -> i32
# "cf.cond_br"(%arg0, %0, %0, %1)[^bb1, ^bb2] <{operandSegmentSizes = array<i32: 1, 1, 2>}> : (i1, i64, i64, i32) -> ()
# ^bb1(%2: i64): // pred: ^bb0
# ^bb2(%3: i64, %4: i32): // pred: ^bb0
# }) : () -> () (pinging @Pangoraw RE: #21 (comment)) |
Ah great! I just started yesterday to rewrite it from scratch (https://github.com/mofeing/MLIR.jl/tree/pretty-tblgen) to get something like you just have done, but I'll stop if you already have it done. Anyways, you may find relevant these commits for better docstring formatting.
|
Co-authored-by: mofeing <sergio.sanchez.ramirez+git@bsc.es>
Oh, sorry for the duplicated work!
Thanks a lot, I added these changes and I reset this branch to keep this pr alive. If you have further comments or nits, don't hesitate to let me know! This PR also includes the output for some dialects in the src/dialects directory but this is more so for easier reviewing. Dialects such as I also just noticed the module name for the |
Codecov ReportAttention:
❗ Your organization needs to install the Codecov GitHub app to enable full functionality. Additional details and impacted files@@ Coverage Diff @@
## main #19 +/- ##
==========================================
- Coverage 41.04% 7.08% -33.96%
==========================================
Files 6 20 +14
Lines 614 3542 +2928
==========================================
- Hits 252 251 -1
- Misses 362 3291 +2929 ☔ View full report in Codecov by Sentry. |
Nah, don't worry. Happy this advances!
The problem with this is that different LLVM versions have different dialects available, so depending on the Julia version, some dialects might error? (In reality, it shouldn't error because One suggestion: Wouldn't it be more practical to keep the original name of the dialects? E.g. |
I see, I haven't really been considering older MLIR versions as everything evolves so quickly. E.g. the generated output for
I opted for a capital first letter to align closer the naming convention for Julia modules https://docs.julialang.org/en/v1/manual/style-guide/#Use-naming-conventions-consistent-with-Julia-base/. But I see the advantage of staying with MLIR's naming convention here as well... Either way, I don't have any strong preference. edit: the dialect's |
That's not how BinaryBuilder or Yggdrasil works: it only provides the external binaries. The bindings are delegated to other packages (like this one). In my opinion, the generator script should be run during the build step (i.e. in
This can be easily be solved with |
The original Haskell bindings use |
Ok, module naming is updated, thanks for the pointer.
I didn't realise this was something that was possible but sounds like a much better approach :) |
Can we automatically call arith.constant(value=1f0) # %cst = arith.constant 1.000000e+00 : f32
arith.constant(value=12) # %c12_i64 = arith.constant 12 : i64 One drawback is that it can be a bit of a confusing API. |
…te` automatically.
@jumerckx I've opened jumerckx#1 in your fork that runs the binding generator on build. |
MLIR doesn't name operands, it can be confusing. It should be something like: arith.constant(1f0) # %cst = arith.constant 1.000000e+00 : f32
arith.constant(12) # %c12_i64 = arith.constant 12 : i64 |
|
Now that my PR has been merged, dialect bindings are generated on the fly! There are some some things left to do:
Maybe we could merge this PR and open PRs for these tasks. |
I could look into this today already, haven't yet checked what's actually going wrong. |
So is it ok if I merge this? Anyone wanna give me the go-ahead? :) |
A few more things that come to my mind:
|
The build step is run automatically. See https://pkgdocs.julialang.org/v1/creating-packages/#Adding-a-build-step-to-the-package CI is currently failing on Julia 1.9 because Julia 1.9 uses LLVM 14 and I've fixed Fixing the Select the LLVM_full_jl version corresponding to the running Julia version check would solve it. |
Ahh I think selecting the |
We should not be depending on LLVM_full_jll, rather I would do something similar to what we do in https://github.com/JuliaLabs/MLIR.jl/blob/26157615dda7e09bc2e3bd33cd81aeb715453a9e/res/wrap.jl#L21 and pre-generate and version the Julia files (and avoid any build steps) Then MLIR.jl Oly has to check what version of LLVM Julia is using |
Not at all finished, but I'm including it here if someone would like to provide feedback. Most notably, it's missing optional attributes. Also, attribute arguments to operation functions are simply expected to be of the right type, in contrast to the haskell code where different attribute types are declared.
example output for the LLVM dialect:
https://gist.github.com/jumerckx/bf892d88021aa5cf4ae037b98c21b0fa