Skip to content

[Formal][Property Annotation] Annotate Reconvergent-paths using flow variables#716

Merged
Basmet0 merged 50 commits intoEPFL-LAP:mainfrom
Basmet0:invariant-flow
Apr 1, 2026
Merged

[Formal][Property Annotation] Annotate Reconvergent-paths using flow variables#716
Basmet0 merged 50 commits intoEPFL-LAP:mainfrom
Basmet0:invariant-flow

Conversation

@Basmet0
Copy link
Copy Markdown
Collaborator

@Basmet0 Basmet0 commented Jan 27, 2026

Each operation has local properties on how tokens are distributed between inputs and outputs. For example, a join operation expects the same number of tokens coming from each input, and sends them to its output. By extracting all of these local equations from a circuit, and then performing Gaussian elimination, one gets equations that describe properties of paths using only the internal states of the operations, rather than having to keep track of how many tokens are sent across each channel.

Comment on lines +328 to +332
// channel metadata
CPVar i1 = CPVar(llvm::formatv("#x1{0}", getUniqueName(&op)).str(),
VarType::INTEGER);
CPVar i2 = CPVar(llvm::formatv("#x2{0}", getUniqueName(&op)).str(),
VarType::INTEGER);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Here we should describe the model that we assume:

every unit is a cascade of: merge/join/mux -(internal_channel1)-> [slot]* -(internal_channel2)-> fork

Rename i1 -> lambda_internal_channel1

}

LogicalResult
HandshakeAnnotatePropertiesPass::annotateReconvergentPathFlow(ModuleOp modOp) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Split this function into multiple smaller ones:

  • createFlowVariables
  • addEquations
  • solveGaussian
  • ...

@Jiahui17
Copy link
Copy Markdown
Member

Jiahui17 commented Feb 4, 2026

We could do a separate PR for class HandshakeOpInternalState

- <forkOp> fork1 -> { fork1.sent1, fork1.sent2, ... }
- fork1.sent2 -> { "it is a sent", "the second one" }
- parse
- print
- write smv

struct HandshakeOpInternalState {
  StringRef writeSmv() virtual = 0;
  /// This is the same as the "handshake.name" of the operation
  std::string name;
  static std::optional<HandshakeOpInternalState> parse() virtual = 0;
  Operation * getOperation(NameAnalysis& namer) {
    namer.findOepration(this->name)
  }
};


struct EagerForkSent : public HandshakeOpInternalState {
  Operation * op;
  unsigned outputId;
  StringRef writeSmv() override {

  }

  // Validate that there is an op with a matching name
  std::optional<HandshakeOpInternalState> parse(NameAnalysis& namer) override {
    

  }
};

if (auto state = EagerForkSent::parse(name)) {
  ...
} else if (auto state = BufferFull::parse(name)) {
  ...
} 

...

@Jiahui17 Jiahui17 marked this pull request as draft February 10, 2026 13:09
@Jiahui17 Jiahui17 self-requested a review March 26, 2026 14:11
@Jiahui17 Jiahui17 marked this pull request as ready for review March 26, 2026 14:37
@Jiahui17
Copy link
Copy Markdown
Member

Jiahui17 commented Mar 27, 2026

@Basmet0 could you please add one CI/CD example to test this PR? we can invent a new kernel without any memory accesses

auto slots = cmergeOp.getInternalSlotStateNamers();
std::shared_ptr<InternalStateNamer> slotNamer =
std::make_shared<BufferSlotFullNamer>(slots[0]);
FlowVariable slot(slotNamer);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

if we do not use shared ptr here, we could just do

FlowVariable slot(cmergeOp.getInternalSlotStateNamers()[0]);

Which is much more readable IMO. I think here we should focus on more the readbility of the APIs

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

It needs to be a pointer as InternalStateNamer is a virtual class. I created a wrapper around it that hides the shared pointer creation, and the API now looks similar to your example.

}

// Utility functions for handling flow variables with index tokens
inline bool isIndex() const { return indexTokenConstraint.has_value(); }
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

-> hasIndexConstraint?

Add an example of what we are talking about here

Bas Niekel added 24 commits March 31, 2026 17:24
…hers, instead of using default handling where it could lead to incorrect output
…ndividually, rather than grouping most operations into one big case.

Moving equation extraction into FlowExpression.cpp
Copy link
Copy Markdown
Member

@Jiahui17 Jiahui17 left a comment

Choose a reason for hiding this comment

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

Awesome, thanks for the nice work!

@Basmet0 Basmet0 merged commit b3590c9 into EPFL-LAP:main Apr 1, 2026
8 checks passed
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.

2 participants