This is an archive of the discontinued LLVM Phabricator instance.

[mlir] Refactor SubElementInterface replace support
ClosedPublic

Authored by rriddle on Jul 26 2022, 11:02 AM.

Details

Summary

The current support was essentially the amount necessary
to support replacing SymbolRefAttrs, but suffers from various
deficiencies (both ergonomic and functional):

  • Replace crashes if unsupported This makes it really hard to use safely, given that you don't know if you are going to crash or not when using it.
  • Types aren't supported

This seems like a simple missed addition when the attribute replacement
support was originally added.

  • The ergonomics are weird

It currently uses an index based replacement, which makes the implementations
quite clunky.

This commit refactors support to be a bit more ergonomic, and also
adds support for types in the process. This was also a great oppurtunity
to greatly simplify how replacement is done in the symbol table.

Diff Detail

Event Timeline

rriddle created this revision.Jul 26 2022, 11:02 AM
rriddle requested review of this revision.Jul 26 2022, 11:02 AM
rriddle updated this revision to Diff 447766.Jul 26 2022, 11:05 AM
lattner accepted this revision.Jul 26 2022, 11:25 AM

Oh my, this is delightful, thank you for tackling this!

As a follow-on, it would also be amazing for aggregate types like FunctionType etc to implement these types. I'm also curious whether terminal types/attributes should implement these interfaces as well. It is convenient for clients if IntegerAttr knows it has no subattrs for example.

mlir/include/mlir/Dialect/LLVMIR/LLVMTypes.h
419

nice catch

mlir/test/lib/Dialect/Test/TestTypes.h
161

I'm not sure what this means? You can't mutate a type of course, you can only return a new one, just like attributes. For example, if I want to programmatically turn all index types into i64, then you'd replace { f32, index, f32} by returning {f32, i64, f32}. Does that make sense?

This revision is now accepted and ready to land.Jul 26 2022, 11:25 AM
rriddle marked an inline comment as done.Jul 26 2022, 11:51 AM
rriddle added inline comments.
mlir/test/lib/Dialect/Test/TestTypes.h
161

You can mutate them. There is a very niche feature that allows for having "mutable" components of an attribute or type: https://mlir.llvm.org/docs/AttributesAndTypes/#mutable-attributes-and-types

It was added many moons ago for LLVM struct type, but it hasn't been evolved much since.

lattner added inline comments.Jul 26 2022, 12:02 PM
mlir/test/lib/Dialect/Test/TestTypes.h
161

Aha, got it, it's logically immutable but needs to be mutated during set up. Makes sense!

rriddle marked an inline comment as done.Jul 26 2022, 1:04 PM

Oh my, this is delightful, thank you for tackling this!

As a follow-on, it would also be amazing for aggregate types like FunctionType etc to implement these types. I'm also curious whether terminal types/attributes should implement these interfaces as well. It is convenient for clients if IntegerAttr knows it has no subattrs for example.

At first it was simply intended for opt-in behavior, but if we have cases that are failing conservatively without it, it might make sense to shift to a similar model to side effects (i.e. NoSubElements or something).

Yeah good point, a trait like that would also nicely de-boilerplate a noop implementation.

Of course right now all attributes have types :-), so every attribute theoretically needs an impl of this. I think we can overlook that though.

rriddle updated this revision to Diff 447819.Jul 26 2022, 1:54 PM
This revision was automatically updated to reflect the committed changes.
csigg added a subscriber: csigg.Jul 28 2022, 1:37 AM

Hi River, I noticed a behavioral change that might or might not be intended:

gpu.module @foo {
  llvm.func @foo() { ... }
}
func.func @main() {
  gpu.launch_func @foo::@foo ...
}

SymbolTable::replaceAllSymbolUses(gpu_module_op, "bar", main_func_op) before this change updated the gpu.launch_func to @bar::@foo. After this change, it is updated to @bar::@bar.

It seems to me that SymbolTable::replaceAllSymbolUses(Operation* op, ...) should only update references to op, not all references that match op's symbol name. WDYT?

Hi River, I noticed a behavioral change that might or might not be intended:

gpu.module @foo {
  llvm.func @foo() { ... }
}
func.func @main() {
  gpu.launch_func @foo::@foo ...
}

SymbolTable::replaceAllSymbolUses(gpu_module_op, "bar", main_func_op) before this change updated the gpu.launch_func to @bar::@foo. After this change, it is updated to @bar::@bar.

It seems to me that SymbolTable::replaceAllSymbolUses(Operation* op, ...) should only update references to op, not all references that match op's symbol name. WDYT?

Yep, that's definitely a bug. Thanks for the repro: https://reviews.llvm.org/D130693