- Adds simple, non-atomic, non-volatile, non-synchronized direct load/store ops.
Details
Diff Detail
- Repository
- rG LLVM Github Monorepo
Event Timeline
Note: design discussion continuing on discourse: https://discourse.llvm.org/t/rfc-introduce-ml-program-dialect-and-top-level-ops-proposal-v2/60907/51
*breathes a sigh of relief that no ODS bugs were stepped on*
mlir/include/mlir/Dialect/MLProgram/IR/MLProgramOps.td | ||
---|---|---|
162 | It is possible to specify memory effects on symbol reference resources specifically, but ODS doesn't generate that code for you. Doing so should provide the benefit of being able to reorder/CSE certain reads and writes. | |
184 | I don't have context on this but does disallowing nested symbol references make sense for this dialect? | |
246 | Ditto with the symbol reference resource. | |
mlir/lib/Dialect/MLProgram/IR/MLProgramOps.cpp | ||
178 | add braces | |
229 | add braces | |
233 | add braces |
Haha - yes, this one was much easier! Thank you for all of your help on the previous patch.
Since the conversation on design is still happening on discourse, I'll leave this until that resolves before applying your suggestions. Thank you for the review!
mlir/include/mlir/Dialect/MLProgram/IR/MLProgramOps.td | ||
---|---|---|
162 | Oh, thank you for the tip -- I had wondered about this in the past! I can go reading, but do you have any reference to look at? |
mlir/include/mlir/Dialect/MLProgram/IR/MLProgramOps.td | ||
---|---|---|
162 |
mlir/include/mlir/Dialect/MLProgram/IR/MLProgramOps.td | ||
---|---|---|
162 | Oh, ODS does the work for you. I had never seen examples in TableGen before :P |
Nice, mostly looks good, clarification question (and sorry I jumped to the code while you may have been making update in discourse/my mind is clear after long weekend so may be asking things already discussed)
mlir/include/mlir/Dialect/MLProgram/IR/MLProgramOps.td | ||
---|---|---|
414 | Is this a pure compilation side type (e.g., same as shape.witness) or does it have a runtime value too? | |
mlir/include/mlir/Dialect/MLProgram/IR/MLProgramTypes.td | ||
19 | You can elide this (replace { ... } with just ; and it behaves the same). | |
24 | You can just elide description if nothing useful :) If this is meant to be compile time only, this could be useful part of description though. | |
mlir/lib/Dialect/MLProgram/IR/MLProgramOps.cpp | ||
24 | ah token and chains ... Mmm, bike shedding: could we have this be something like "after" instead? I'm not even sure if you need to have the mapping there for the tokens produced, that is captured in the type isn't it? Oh but not in the pretty print type. So it would need to be something like %token4, %token5 = ml_program.global_store @global_mutable_undef = %0 : tensor<?xi32> after (%token1, %token3) : (!ml_program.token, !ml_program.token) if not captured in mapping. But what does it mean for a store to produce multiple tokens? I'm not sure what it means from an ordering point of view. Why not always make it produce one token? %after_token = ml_program.global_store @global_mutable_undef = %0 after (%token1, %token3) : tensor<?xi32> |
mlir/include/mlir/Dialect/MLProgram/IR/MLProgramOps.td | ||
---|---|---|
414 | I don't think we care/specify: I have seen implementations that just use this for compile time support, and I have seen implementations that transform/surface such things across boundaries to "externalize" the ordering constraint as needed. | |
mlir/include/mlir/Dialect/MLProgram/IR/MLProgramTypes.td | ||
24 | Oh, I left it there because I meant to write the description. Sorry! |
mlir/lib/Dialect/MLProgram/IR/MLProgramOps.cpp | ||
---|---|---|
24 | Ok, made the result be one optional token (I meant to do that but got turned around when undoing the earlier tablegen experiment). I fiddled with it some more. Here are some examples: %token1 = ml_program.token %0, %token2 = ml_program.global_load @global_mutable_undef after (none -> !ml_program.token) : tensor<?xi32> %token3 = ml_program.global_store @global_mutable_undef = %0 after (%token1, %token2 -> !ml_program.token) : tensor<?xi32> ml_program.global_store @global_mutable_undef = %0 after (%token3) : tensor<?xi32> I don't love all of these but I think they convey the meaning in the expected common cases. Some considerations:
|
mlir/lib/Dialect/MLProgram/IR/MLProgramOps.cpp | ||
---|---|---|
24 | I'm not crazy about none. If there will be at most one token, what about %0, %token1 = ml_program.global_load @foo after (%token1) : tensor<...> %token2 = ml_program.global_store @bar = %0 after(%token1, %token0) : tensor<...> | |
39 | drop braces | |
mlir/test/Dialect/MLProgram/ops.mlir | ||
45 | extra // |
mlir/lib/Dialect/MLProgram/IR/MLProgramOps.cpp | ||
---|---|---|
24 | My edit didn't go through... it's meant to be after (() -> !ml_program.token) or maybe some other way of indicating the optional token since the type itself isn't needed. |
mlir/lib/Dialect/MLProgram/IR/MLProgramOps.cpp | ||
---|---|---|
24 | Switched to the '()' means nil form -- have a look. I had thought about some other way to avoid spelling out the return token type (since it is buildable and we don't technically need it). However, I expect that in the not too distant future, for interop, we're going to want to widen the allowable TokenTypes (since existing graph based dialects all have one and there is little practical reason to restrict them, if we can come up with some common API). | |
39 | Ok, I promise I'm trying and I've read this part of the style guide like 15 times -- and missing something. This case and the if directly above seem to satisfy this statement by my reading: "Maintainability is harmed if the body of an if ends with a (directly or indirectly) nested if statement with no else. Braces on the outer if would help to avoid running into a “dangling else” situation." (ftr - I really don't care much but am trying to comply and get the feel for how this codebase wants it so you all don't need to keep leaving these comments for me :) ) |
Looks good thanks!
mlir/lib/Dialect/MLProgram/IR/MLProgramOps.cpp | ||
---|---|---|
24 | Yes esp if we do "before -> after" then after as keyword is not accurate. I'm good with chaining, ordered-by or other words convenying it is a scheduling constraint. Re: ambiguity of after at end, if optional & op in dialect called after without return value is a thing. Also good point on potential different return types ... One could have the return type at end (rather than operand type) and avoid ambiguity ml_program.global_store @global_mutable_undef(%0 : tensor<?xi32>) after(%token3, %token4) : !ml_program.token and ml_program.global_store @global_mutable_undef(%0 : tensor<?xi32>) : None or ml_program.global_store @global_mutable_undef after(%token3, %token4 : !ml_program.token) = %0 : tensor<?xi32> But I'm not going to block about any of these, yours reads well enough and we can iterate. |
I ended up trying to use an "ordered-by" keyword but parseOptionalKeyword silently will not parse (presumably because of the dash). I ended up spelling it "ordering" but am open to change the spelling. Also added some comments to the custom directive functions.
Just one, otherwise braces LGTM
mlir/lib/Dialect/MLProgram/IR/MLProgramOps.cpp | ||
---|---|---|
39 | For me, it's been a journey of trial and getting nitted by River :P It also occasionally changes vs. older parts of the codebase... | |
53 | drop braces. The rule here is something like nested indents one line each are okay, i.e. if (foo) for (a in b) while (bar) if (c) do_something() is okay |
It is possible to specify memory effects on symbol reference resources specifically, but ODS doesn't generate that code for you. Doing so should provide the benefit of being able to reorder/CSE certain reads and writes.