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

[NFC] change ModulePortInfo to store in a single array and get rid of redundant APIs. This is preparation for not splitting inputs and outputs. #5680

Merged
merged 10 commits into from
Jul 25, 2023

Conversation

darthscsi
Copy link
Contributor

No description provided.

else
inputs.push_back(port);
}
explicit ModulePortInfo(ArrayRef<PortInfo> inputs,
Copy link
Contributor

Choose a reason for hiding this comment

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

I thought part of the reason to switch to ModuleType (name?) which is presumably the shift which this preparing for is to preserve module port ordering amongst inputs/outputs? If so, isn't sorting them here antithetical to that?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is just a storage format change for the current class, so it is preserving existing behavior. Getting everything going through some iterators is the main point.

Copy link
Contributor

Choose a reason for hiding this comment

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

If it's to facilitate efficient computation of at_input, based on a quick skim of these changes, I don't see any uses of at_input or at_output.

Copy link
Contributor

Choose a reason for hiding this comment

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

shit... didn't see your comment. fucking gh.

Copy link
Contributor

Choose a reason for hiding this comment

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

This is just a storage format change for the current class, so it is preserving existing behavior. Getting everything going through some iterators is the main point.

I'm not noticing any places where inputs or outputs are randomly accessed... all the places you modified work through iterators, afaict.

Copy link
Contributor

Choose a reason for hiding this comment

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

though preserving existing behavior for the sake of incrementalism is reasonable.

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'm not noticing any places where inputs or outputs are randomly accessed

There are a couple places where things are deleted. Annoying,.

Copy link
Contributor

@teqdruid teqdruid left a comment

Choose a reason for hiding this comment

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

Thanks for taking this on! Moving to a non-ordered list of ports is future work, yes? It could break a bunch of stuff, in particular tests I'd imagine.

@@ -307,7 +307,7 @@ static LogicalResult convertExtMemoryOps(HWModuleOp mod) {
OpBuilder b(mod);

auto getMemoryIOInfo = [&](Location loc, Twine portName, unsigned argIdx,
ArrayRef<hw::PortInfo> info,
ArrayRef<hw::PortInfo *> info,
Copy link
Contributor

Choose a reason for hiding this comment

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

Why was it necessary to move to a pointer here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

consequence of ArrayRef from a serquential container's iterators.

@@ -1674,8 +1674,8 @@ verifyPrimitiveOpType(PrimitiveOp instance,
<< "'.";

// Verify the instance result ports with those of its referenced component.
SmallVector<hw::PortInfo> primitivePorts = referencedPrimitive.getAllPorts();
size_t numPorts = primitivePorts.size();
auto primitivePorts = getModulePortInfo(referencedPrimitive);
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: plz don't use auto here.

os << bitWidth.getName().str();
} else {
unsigned int bitWidth = port.type.getIntOrFloatBitWidth();
os << bitWidth;
}

if (i + 1 < e)
if (i + 1 < std::distance(ports.begin(), ports.end()))
Copy link
Contributor

Choose a reason for hiding this comment

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

This seems less efficient. Perhaps calculate e outside of the loop?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It's just a subtract, and probably is hoisted, but I moved it.

Copy link
Contributor

Choose a reason for hiding this comment

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

Wouldn't surprise me if the compiler wasn't able to do either optimization and defaulted to iterating through with a counter (which would be necessary if it were a linked list). I don't think smallvector.begin() returns a random_access_iterator...

but whatever.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

no, vector's model random_access_iterator whose specialized distance is arithmatic. It's not accidental or guessing that it's a subtration.

@@ -81,8 +81,7 @@ void ESILowerTypesPass::runOnOperation() {
auto isWindowPort = [](hw::PortInfo p) {
return hw::type_isa<WindowType>(p.type);
};
return !(llvm::any_of(mod.getPorts().inputs, isWindowPort) ||
llvm::any_of(mod.getPorts().outputs, isWindowPort));
return !(llvm::any_of(mod.getPorts(), isWindowPort));
Copy link
Contributor

Choose a reason for hiding this comment

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

Nice! Good demonstration of how this is useful.

for (auto [i, barg] : llvm::enumerate(bodyRegion.getArguments())) {
inputIdx[info.inputs[i].name.str()] = i;
inputIdx[info.at(i).name.str()] = i;
Copy link
Contributor

Choose a reason for hiding this comment

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

This should probably be at_input to be not so reliant on the internal ordering.

Copy link
Contributor

Choose a reason for hiding this comment

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

Or even better, switch to using an iterator.

for (auto i : llvm::reverse(argReplacementsIdxs))
wrapperModPortInfo.inputs.erase(wrapperModPortInfo.inputs.begin() + i);
for (auto i : llvm::reverse(argReplacementsIdxs)) {
wrapperModPortInfo.ports.erase(wrapperModPortInfo.begin_input() + i);
Copy link
Contributor

Choose a reason for hiding this comment

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

it's generally bad practice to rely on code outside of a class to make necessary modifications to synchronized internal datastructures.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Indeed. I was trying to avoid having mutation options at all, but a few places were doing things like this.

@@ -54,7 +54,7 @@ StringRef circt::msft::getValueName(Value v, const SymbolCache &syms,
if (auto blockArg = v.dyn_cast<BlockArgument>()) {
auto portInfo =
getModulePortInfo(blockArg.getOwner()->getParent()->getParentOp());
return portInfo.inputs[blockArg.getArgNumber()].getName();
return (portInfo.begin_input() + blockArg.getArgNumber())->getName();
Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah, this is another case where at_input is the more efficient way...

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It didn't exist yet when I wrote that. But it isn't actually anymore efficient, just more concise.

Copy link
Contributor

Choose a reason for hiding this comment

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

ahh... yeah. I was thinking that if ports allowed mixed order inputs/outputs the input iterator would have to iterate through from the beginning. So this'll be problematic perf in the future. Not relevant for now.

const PortInfo &at_output(size_t idx) const { return ports[idx + numInputs]; }

/// This contains a list of all ports. Input first.
SmallVector<PortInfo> ports;
Copy link
Contributor

Choose a reason for hiding this comment

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

Why are the member variables public? Since they must be kept in sync, it's probably better to keep them private.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

there were a few places that were modifying things directly, but I've issolated those.

Copy link
Contributor

Choose a reason for hiding this comment

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

I'd be supportive of a completely immutable ModulePortInfo and requiring anything doing mutation to have a local mutated list of ports and recreate the ModulePortInfo from that.

@darthscsi darthscsi merged commit bf7d93f into main Jul 25, 2023
3 of 5 checks passed
@darthscsi darthscsi deleted the dev/darthscsi/modtmp1 branch April 11, 2024 17:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants