-
Notifications
You must be signed in to change notification settings - Fork 11
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
MLIR bindings change: improve Attribute Julia types #660
Conversation
Attributes are now typed using Julia type system, reducing the usage of direct C API. There are currently limitations from Tablegen files (custom C++ parser/printer for instance). My next idea is to use "Dialect" IRDL dialect to do the code generation directly in Julia. struct DotAlgorithm
lhs_precision_type::IR.Type
rhs_precision_type::IR.Type
accumulation_type::IR.Type
lhs_component_count::Int64
rhs_component_count::Int64
num_primitive_operations::Int64
allow_imprecise_accumulation::Bool
end
[...]
function dot_general(lhs::Value, rhs::Value; result::IR.Type, dot_dimension_numbers::Dot, precision_config::Union{Vector{Precision.T}, Nothing}=nothing, algorithm::Union{DotAlgorithm, Nothing}=nothing, location::Location=Location())
op_ty_results = IR.Type[result, ]
operands = Value[lhs, rhs, ]
owned_regions = Region[]
successors = Block[]
attributes = NamedAttribute[namedattribute("dot_dimension_numbers", dot_dimension_numbers), ]
!isnothing(precision_config) && push!(attributes, namedattribute("precision_config", precision_config))
!isnothing(algorithm) && push!(attributes, namedattribute("algorithm", algorithm))
create_operation(
"stablehlo.dot_general", location;
operands, owned_regions, successors, attributes,
results=op_ty_results,
result_inference=false
)
end |
src/mlir/IR/Attribute.jl
Outdated
struct DenseElements{T} | ||
attr::Attribute | ||
DenseElements(a::AbstractArray{T}) where {T} = new{T}(IR.DenseElementsAttribute(a)) | ||
end | ||
Attribute(d::DenseElements) = d.attr | ||
|
||
function DenseArrayAttribute(values::Vector{<:Enum}) | ||
return Attribute([Attribute(value) for value in values]) | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not just create an Attribute
when you pass a DenseArray
to Attribute
?
What's the difference between DenseElementsAttribute
and DenseElements
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I force DenseElements
type in MLIR calls such as Convolution
:
function convolution(
[...]
padding::Union{IR.DenseElements{Int64},Nothing}=nothing,
[...]
location::Location=Location(),
)
Because I cannot get Attribute name from the Attribute type.
src/mlir/Dialects.jl
Outdated
c(a::AbstractArray) = isempty(a) ? "[]" : a | ||
c(x) = x |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
mmm would you mind giving a more descriptive name?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For the moment, I add this function to all struct attributes; I will prefer a one character to not challenging Julia formatter too much. I will add a comment for this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
in general i like this PR and anything that makes the MLIR interface more idiomatic but I have some doubts:
-
I don't think that adding so many type constraints to methods is a good idea (specially adding the
::Any
because it's redudant).
i guess that the type contraints are there to avoid C-side crashes by adding a type check (and i'm ok with that), but that can turn impractical already with things like "accept aVector
or aTuple
" -
What is the purpose of
FlatSymbol
and how it's different toFlatSymbolRefAttribute
? IMHO MLIR.IR types should have a annotation in the name to remind that it's another type of object (so if it's an attribute, it should haveAttribute
in the name to remind you it's a MLIR Attribute wrapper).
src/mlir/Dialects/Affine.jl
Outdated
@@ -353,11 +363,11 @@ func.func @pad_edges(%I : memref<10x10xf32>) -> (memref<12x12xf32) { | |||
""" | |||
function if_( | |||
operand_0::Vector{Value}; | |||
results::Vector{IR.Type}, | |||
condition, | |||
results::Union{Vector{IR.Type},Tuple{Vararg{IR.Type}}}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you can use AbstractVecOrTuple
, but at this point I think is better to maybe not use type constraints?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't know about that one! I don't see why we would want to remove type constraints, these calls can be easily misused.
src/mlir/Dialects/Affine.jl
Outdated
map, | ||
location=Location(), | ||
result::Union{Nothing,IR.Type}=nothing, | ||
map::Any, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I prefer if we put no type constraint here because is more legible and it's completely equivalent to Any
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I use Any
as a fallback when an attribute Julia type cannot be created
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah, but maybe we could just don't put anything? or is it more complicated?
sounds cool but what do you mean? |
Basically, get Dialect definitions as a .mlir. Process this file in Julia with MLIR.jl capabilities and emitting files such as 'Affine.jl' and friends directly there. Several benefits from this: simplify generator code, "easy" runtime dialect bindings generation. |
Thank for the feedback! |
do you mean to bypass the limitations of the C++ tablegen @jumerckx was facing? sounds super cool, didn't know this could be done. does IRDL have all we need for this?
i like it, but how about this:
i believe that the reason why we put only one wdyt? |
Mathieu Fehr has designed a dialect for this! It's still wip but it can give us much more information than tablegen. And it has really great benefit to inspect dialect for analysis or fuzzing.
Really nice! We discussed this design yesterday with Jules, adding the 'Attribute' suffix seems logical to limit cognitive overhead between Julia and C-API. There is still an open question regarding verification of Attributes that cannot be created from Julia: for now, I will use the raw |
Cool! do you have a link to it?
yeah, the MLIR C-API is quite limited and not very actively developed... we discussed this with @makslevental. using |
https://mlir.llvm.org/docs/Dialects/IRDL/#irdltype-irdltypeop
Right! |
ups sorry, i mean how you get a mlir of a dialect. like irdl manages the tablegen or? |
Yes like that! I haven't test the tool, but a wip .td -> .mlir seems to exist. |
src/mlir/IR/Attribute.jl
Outdated
end | ||
|
||
function DenseElementsAttribute(values::AbstractArray) | ||
shaped_type = TensorType(size(values), Type(eltype(values))) | ||
return Attribute( | ||
return DenseElementsAttribute{:unknown}(Attribute( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
mmm i think it may be better to put here eltype(values)
return DenseElementsAttribute{:unknown}(Attribute( | |
return DenseElementsAttribute{eltype(values)}(Attribute( |
src/mlir/IR/Attribute.jl
Outdated
function Base.reshape(attr::Attribute, shape) | ||
@assert isdenseelements(attr) "attribute $(attr) is not a dense elements attribute" | ||
function Base.reshape(attr::DenseElementsAttribute, shape) | ||
attr = attr.attr |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
attr = attr.attr | |
attr = Attribute(attr) |
src/mlir/IR/Attribute.jl
Outdated
@@ -746,6 +770,38 @@ function Base.length(attr::Attribute) | |||
end | |||
end | |||
|
|||
function Base.getindex(attr::DenseElementsAttribute, i) | |||
attr = attr.attr |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
attr = attr.attr | |
attr = Attribute(attr) |
@mofeing I'm running into segmentation fault in CI. And I cannot reproduce them locally because of cuda. Do you have ideas to debug this? Last working commit is bc846e3.
(https://buildkite.com/julialang/reactant-dot-jl/builds/4214#0194c925-1ac0-46a8-a16a-c134be86ad6b) |
do you mind finding which is the first test that fails? also, once you find it, do you mind showing the MLIR if |
It's the first one in
Using stacktrace, I get :
|
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
i'm not familiar with the CUDA lowering, sorry |
Thanks a lot for the feebacks, I think I've found it! CI debugging & code_hlo helps! |
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #660 +/- ##
===========================================
+ Coverage 21.66% 33.93% +12.26%
===========================================
Files 46 73 +27
Lines 8048 14723 +6675
===========================================
+ Hits 1744 4996 +3252
- Misses 6304 9727 +3423 ☔ View full report in Codecov by Sentry. |
I close #447, and apply change to Reactant code.
result_
toresult
result_layouts=nothing::Union{Attribute, Nothing}
doesn't constraintresult_layouts
so change to :result_layouts::Union{Attribute, Nothing} =nothing
EnumAttr
: using Attr parsing (MLIR doesn't expose methods in C to easily construct arbitrary attribute) and discriminant.conv