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

[Arc] Add SplitFuncsPass #7027

Merged
merged 21 commits into from
May 15, 2024
Merged

[Arc] Add SplitFuncsPass #7027

merged 21 commits into from
May 15, 2024

Conversation

TaoBi22
Copy link
Contributor

@TaoBi22 TaoBi22 commented May 13, 2024

As proposed in #6298, this PR adds a pass that splits up large functions into smaller functions to (eventually - I haven't included it in the Arcilator pipeline in this PR, as we'll want to actually split up the compilation units when using the pass, which is still on the todo list) work around parts of the pipeline that scale very badly with large funcs. This uses some liveness analysis bits so that (only) the values that are needed further up the call stack are passed up.

@fabianschuiki fabianschuiki added the Arc Involving the `arc` dialect label May 13, 2024
Copy link
Contributor

@fabianschuiki fabianschuiki left a comment

Choose a reason for hiding this comment

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

This is very cool! Might we worth to add an option to arcilator that adds this pass to the pipeline 😃

@@ -46,6 +46,7 @@ std::unique_ptr<mlir::Pass> createLowerVectorizationsPass(
std::unique_ptr<mlir::Pass> createMakeTablesPass();
std::unique_ptr<mlir::Pass> createMuxToControlFlowPass();
std::unique_ptr<mlir::Pass> createSimplifyVariadicOpsPass();
std::unique_ptr<mlir::Pass> createSplitFuncsPass(unsigned splitBound = 20000);
Copy link
Contributor

Choose a reason for hiding this comment

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

I think you should be able to use the options struct that table-gen produces for you. That way you don't have to redefine the default split bound 🙂

Suggested change
std::unique_ptr<mlir::Pass> createSplitFuncsPass(unsigned splitBound = 20000);
std::unique_ptr<mlir::Pass> createSplitFuncsPass(const SplitFuncsOptions &options = {});

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Very nifty, the redefinition was bugging me! Thanks!

@TaoBi22
Copy link
Contributor Author

TaoBi22 commented May 14, 2024

@fabianschuiki added an Arcilator option to run the pass - occurred to me while checking it works correctly that since the pass currently operates on func.funcs the llvm.funcs that eventually get produced could potentially be a fair bit longer than the threshold given since some MLIR ops will be lowered to multiple LLVM ops. Guessing this is still probably fine since we can still use this to divide compilation units, but can always make the pass operate on llvm.funcs instead if we'd rather have more precise control!

@fabianschuiki
Copy link
Contributor

I think running on func.func as you're doing right now is great! LLVM funcs feels like they're just the very last step before we kick stuff over to LLVM, kind of like an export dialect, but we don't necessarily want to perform optimizations at that point. The size of the splits is probably going to be just a good guess anyway, so if the final LLVM functions end up being 50% larger we probably won't mind 😃.

Copy link
Member

@maerhart maerhart left a comment

Choose a reason for hiding this comment

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

Really cool to have this pass, thanks!
Just a few suggestions on how to make this a little more readable, but nothing super important 🙂

lib/Dialect/Arc/Transforms/SplitFuncs.cpp Outdated Show resolved Hide resolved
lib/Dialect/Arc/Transforms/SplitFuncs.cpp Outdated Show resolved Hide resolved
lib/Dialect/Arc/Transforms/SplitFuncs.cpp Outdated Show resolved Hide resolved
lib/Dialect/Arc/Transforms/SplitFuncs.cpp Outdated Show resolved Hide resolved
test/Dialect/Arc/split-funcs.mlir Show resolved Hide resolved
lib/Dialect/Arc/Transforms/SplitFuncs.cpp Outdated Show resolved Hide resolved
include/circt/Dialect/Arc/ArcPasses.h Outdated Show resolved Hide resolved
lib/Dialect/Arc/Transforms/SplitFuncs.cpp Outdated Show resolved Hide resolved
lib/Dialect/Arc/Transforms/SplitFuncs.cpp Outdated Show resolved Hide resolved
TaoBi22 and others added 2 commits May 15, 2024 16:10
Co-authored-by: Martin Erhart <maerhart@outlook.com>
@TaoBi22
Copy link
Contributor Author

TaoBi22 commented May 15, 2024

@maerhart thanks for the great review! Think that should be everything addressed, let me know if I missed anything before I merge!

Copy link
Member

@maerhart maerhart left a comment

Choose a reason for hiding this comment

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

Thanks!

return funcOp.emitError("Cannot split functions into functions of size 0.");
if (funcOp.getBody().getBlocks().size() > 1)
return funcOp.emitError("Regions with multiple blocks are not supported.");
assert(splitBound != 0 && "Cannot split functions into functions of size 0");
Copy link
Member

Choose a reason for hiding this comment

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

The if above makes this impossible to be triggered, so we could remove it.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oops, thought I'd dropped that, thanks for the catch!

opBuilder.create<ReturnOp>(funcOp->getLoc(), outValues);
}
// Create and populate new FuncOps
for (long unsigned i = 0; i < blocks.size() - 1; i++) {
Copy link
Member

Choose a reason for hiding this comment

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

Nit: inconsistent post and pre-increments, LLVM generally prefers pre-increment.


opBuilder.setInsertionPointToEnd(funcBlock);
for (auto [j, el] : llvm::enumerate(args))
replaceAllUsesInRegionWith(el, newFunc.getArgument(j++),
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
replaceAllUsesInRegionWith(el, newFunc.getArgument(j++),
replaceAllUsesInRegionWith(el, newFunc.getArgument(j),

@TaoBi22
Copy link
Contributor Author

TaoBi22 commented May 15, 2024

Happy for me to merge @maerhart?

@maerhart
Copy link
Member

Happy for me to merge @maerhart?

Of course, thanks for all the improvements!

@TaoBi22 TaoBi22 merged commit cb61e8f into llvm:main May 15, 2024
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Arc Involving the `arc` dialect
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants