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

[HW] Add pass to outline certain ops: hw-outline-ops #7991

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

teqdruid
Copy link
Contributor

This pass outlines all of the selected operations into separate modules,
uniquifying the modules. This is useful for debugging and cutting down RTL
size for certain high level ops.

Notes:

  • Does not support ops with regions.
  • In uniquifying the modules, dialect attributes are ignored. Only
    properties are respected.
  • Dialect attributes are, however, inherited by the module instances.

@teqdruid teqdruid added the HW Involving the `hw` dialect label Dec 13, 2024
@teqdruid teqdruid marked this pull request as ready for review December 13, 2024 22:16
@teqdruid teqdruid requested a review from darthscsi as a code owner December 13, 2024 22:16
This pass outlines all hw::HWModuleOp operations into separate modules,
uniquifying the modules.  This is useful for debugging and cutting down RTL
size for certain high level ops.

Notes:
- Does not support ops with regions.
- In uniquifying the modules, dialect attributes are ignored. Only
  properties are observed.
- Dialect attributes are, however, inherited by the module
  instances.
@teqdruid
Copy link
Contributor Author

Tagging a few people as I don't know who's working this week.

@teqdruid teqdruid requested a review from mikeurbach December 19, 2024 00:41
Copy link
Contributor

@mortbopet mortbopet left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re. the region constriant: technically, it should be perfectly legal to outline operations with regions that are IsolatedFromAbove. I think this would be a great addition which would apply to e.g. the pipeline ops (which currently online has an inline lowering.

Regarding dialect attributes - i assume the reason why you didn't include this is because you can't generate a pretty (module) name for them. To expand capabilities, would it make sense to keep the existing name generation mechanism, but then additionally just hash the set of dialect/"other" attributes and append that to the module name?
If you opt not to do this, i think there should be some tests where the targeted ops have dialect attributes, to verify that everything works correctly.

In any case, this seems like a useful tool that may come in handy here or there when debugging RTL to force some more hierarchy into the trace.


let options = [
ListOption<"opNames", "op-names", "std::string",
"List of operation names to outline. If empty, this pass is a no-op.">
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just to foolproof this, show an example as well (to remove ambiguity about whether or not to include the dialect name (${dialect}.${opname}).


// Append only the inherent attributes to the module name.
nameOS << "_attrs";
if (auto regOp = op->getRegisteredInfo()) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: A bit misleading to call this regOp - how about registeredOpName?

@teqdruid
Copy link
Contributor Author

Re. the region constriant: technically, it should be perfectly legal to outline operations with regions that are IsolatedFromAbove. I think this would be a great addition which would apply to e.g. the pipeline ops (which currently online has an inline lowering.

Problem with that is hashing and comparing regions would be expensive.

Regarding dialect attributes - i assume the reason why you didn't include this is because you can't generate a pretty (module) name for them.

No. It's because dialect attributes like sv.namehint don't mean anything as far as the operation is concerned and could/will be different in a way which is meaningless as far as outlining is concerned. It's also why I propagate them to the instances.

@darthscsi
Copy link
Contributor

technically, it should be perfectly legal to outline operations with regions that are IsolatedFromAbove

For how we use regions, yes. For the general MLIR notion, no. They could be all sorts of things (Exception landing pads?) which have semantics based on simply being in their parent, not based on name resolution of SSA values.

Copy link
Contributor

@darthscsi darthscsi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor nits, but otherwise is fine.

size for certain high level ops.

Notes:
- Does not support ops with regions.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see how this is in general safe. There is no reason to believe a dialect attribute can be moved from a module to an instance. Take any lowering options or name hints, for example.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only they're not being moved from the module to the instance. They're being kept on the operation which is being replaced by an instance. So the dialect attributes aren't moving -- the underlying op is being moved into its own module. The name hints are the primary reason I did this.

};

/// Compare two OpInfos.
struct OpInfoEqual {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this better than just specializing std::equal_to?

};
} // namespace

namespace {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: member definitions don't need to be in a namespace.

struct OpInfoEqual {
size_t operator()(const OpInfo &a, const OpInfo &b) const {
return a.name == b.name && a.operandTypes == b.operandTypes &&
a.resultTypes == b.resultTypes && a.attributes == b.attributes;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On second thought, isn't this just the same as the default operator== that would be generated for the type and used by the default std::equal_to?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was unaware that any operation== was automatically generated.

os << "_";
std::string typeName;
llvm::raw_string_ostream(typeName) << type;
if (typeName[0] == '!')
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getName()[0]?
Shouldn't need std::string

};

// Create the module name.
std::string name;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

super nit: SmallString might be sizable to prevent allocation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
HW Involving the `hw` dialect
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants