Skip to content

Conversation

@mtsamis
Copy link
Collaborator

@mtsamis mtsamis commented Oct 24, 2025

This PR implements parser inlining (#100).

The changes include generic infrastructure found in IRUtils and an inlining pass based on MLIR InliningUtils and the new SplitStateRewriter to handle parser rewrites. The implementation makes sure to leave the IR in its original state if the inlining fails at any part (e.g. due to an apply call being inside an if statement).

Although not necessary for correctness, parser locals are shared per instantiation to avoid creating too many new locals that will be hard to eliminate later on.

A number of tests are added, including the parser inlining tests from P4C. The latter are there only to check against potential crashes.

@mtsamis mtsamis requested a review from asl October 24, 2025 14:02
@asl
Copy link
Collaborator

asl commented Oct 24, 2025

Tagging @fruffy for visibility

Copy link
Collaborator

@fruffy fruffy left a comment

Choose a reason for hiding this comment

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

The lack of E2E testing and reference files makes it quite hard to tell whether the resulting semantic behavior is correct. Would be really nice to have a packet testing framework for this at some point.

@asl
Copy link
Collaborator

asl commented Oct 26, 2025

@fruffy I'm afraid this will only be possible if / when we will have some backend implementation...

Copy link
Collaborator

@asl asl left a comment

Choose a reason for hiding this comment

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

Made first sweep, check the comments below and above

llvm::StringRef varName = "promoted_local") {
// Create new variable to hold `val`.
auto newVar = rewriter.create<P4HIR::VariableOp>(
val.getLoc(), P4HIR::ReferenceType::get(val.getType()), varName);
Copy link
Collaborator

Choose a reason for hiding this comment

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

Add init attribute as the variable will be immediately initialized.

P4HIR::ParserStateOp IRUtils::createSubState(mlir::RewriterBase &rewriter,
P4HIR::ParserStateOp state, llvm::StringRef suffix) {
auto parser = state->getParentOfType<P4HIR::ParserOp>();
std::string basename = (llvm::Twine(state.getSymName()) + "_" + suffix).str();
Copy link
Collaborator

Choose a reason for hiding this comment

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

Do you really need Twine here? I'd suggest using SmallString here with pre-allocated buffer

std::string name = basename;

size_t counter = 0;
while (parser.lookupSymbol(name)) name = basename + "_" + std::to_string(counter++);
Copy link
Collaborator

Choose a reason for hiding this comment

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

Use mlir::SymbolTable::generateSymbolName. There are examples of usage in P4C/translate.cpp

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This made me realize that I merged an outdated version of IRUtils in this new branch. I will update it to the correct one.

void InlineParsersPass::runOnOperation() {
mlir::IRRewriter rewriter(&getContext());

// P4 guarantees that subparser definitions come before their use so inlining them
Copy link
Collaborator

Choose a reason for hiding this comment

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

This is true for P4 input source. But technically since we're referring things via symbols and symbol tables this might be not true anymore and this is not enforced in P4HIR. I would explicitly have a worklist and iterate until it is not empty

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Good point, I will re-evaluate the assumption and change the implementation as needed.

status = ssr->init();
if (status.failed()) break;

std::string prefix = instName.str();
Copy link
Collaborator

Choose a reason for hiding this comment

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

use SmallString here


// Move inlined operation `op` to its desired position.
void proccessInlinedOp(size_t index, mlir::Operation *op) {
// Remmap parser locals if needed.
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
// Remmap parser locals if needed.
// Remap parser locals if needed.


// Make the subparser's accept transition to the "post" state.
if (stateOp.isAccept()) {
auto acceptOp = mlir::cast<P4HIR::ParserAcceptOp>(stateOp.getNextTransition());
Copy link
Collaborator

Choose a reason for hiding this comment

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

Should we just userewriter.replaceOpWithNewOp<P4HIR::ParserTransitionOp>(acceptOp, ...)?

}
}

// Move inlined operation `op` to its desired position.
Copy link
Collaborator

Choose a reason for hiding this comment

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

I would probably suggest to expand the comment specifying the IR before this function (e..g how the states were split and where everything went into) and what should be do

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Good point, I'll add more details.

@mtsamis mtsamis force-pushed the mtsamis/inline-subparsers-new branch from 20299e1 to 6e60de6 Compare October 29, 2025 18:29
@mtsamis
Copy link
Collaborator Author

mtsamis commented Oct 29, 2025

In latest version:

  • Fix bug where updateNamesAndRefs symbol ref rewriting would not take into account if the root parser op matches the callee parser.
  • Iteratively inline subparsers until nothing new is inlined so we don't need to assume P4 parser order. A new test is also added which contains different parser order than what expected.
  • Use the location of the apply that failed inlining in notifyMatchFailure, so it's easier to track down the reason that a subparser was not inlined.
  • Preserve placement of inlined instantiations and variables with respect to the caller's top-level operations.
  • Update correct version of IRUtils, which includes the improvements that are part of Implement new remove-parser-control-flow optimization pass (#99) #221
  • Simplify some code, add some more comments.
  • Address all other review feedback.

@mtsamis
Copy link
Collaborator Author

mtsamis commented Nov 7, 2025

Superseded by #246.

@mtsamis mtsamis closed this Nov 7, 2025
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.

3 participants