Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
114 commits
Select commit Hold shift + click to select a range
1bcf3a6
Main
QinYuan2000 Oct 15, 2025
a15919b
Add temporary debug outputs
QinYuan2000 Oct 18, 2025
d25207e
Update
QinYuan2000 Oct 21, 2025
34dd7ea
small
QinYuan2000 Oct 21, 2025
d3f5cab
Weird, why we still need this
QinYuan2000 Oct 21, 2025
0322161
add comments
QinYuan2000 Oct 21, 2025
4ed8487
update
QinYuan2000 Oct 21, 2025
5f774c4
small fix
QinYuan2000 Oct 21, 2025
1b9af88
update
QinYuan2000 Oct 21, 2025
09df431
Temp Update
QinYuan2000 Dec 6, 2025
7842b89
temp
QinYuan2000 Dec 6, 2025
fe44fc0
a correct version
QinYuan2000 Dec 7, 2025
93c9927
debuglog option
QinYuan2000 Dec 7, 2025
aac1113
format
QinYuan2000 Jan 13, 2026
09bc30a
initial
QinYuan2000 Jan 20, 2026
a00caba
update
QinYuan2000 Jan 22, 2026
e85d37e
update
QinYuan2000 Jan 22, 2026
9d4aa15
Chained mux conditions and remove new_supp
QinYuan2000 Jan 28, 2026
cd95c5d
[FTD] Support Multi-Exit Loops (#604)
zeinabPourgheisari Oct 27, 2025
fabafb9
fix-on-merge
QinYuan2000 Feb 13, 2026
b93346c
MU condition
QinYuan2000 Feb 13, 2026
cab72ca
clear up
QinYuan2000 Feb 14, 2026
9bd6468
clean up bddtocircuit
QinYuan2000 Feb 14, 2026
32e26f2
solve same value on condition and data inputs
QinYuan2000 Feb 14, 2026
e191bcb
safely change distribution base
QinYuan2000 Feb 15, 2026
aaedb14
main supGSA logic with bugs
QinYuan2000 Feb 15, 2026
01244e9
fix bugs, not polished
QinYuan2000 Feb 17, 2026
a5dc410
two important fixes
QinYuan2000 Feb 17, 2026
9189793
small update
QinYuan2000 Feb 17, 2026
fa335ee
fix mux condition bug
QinYuan2000 Feb 21, 2026
c872bb5
refine
QinYuan2000 Feb 27, 2026
9d8945f
clang-format
QinYuan2000 Feb 27, 2026
bead007
fix cycleanalysis small
QinYuan2000 Feb 27, 2026
b8945e9
small bug fix
QinYuan2000 Feb 27, 2026
2040d2e
simplify logic
QinYuan2000 Feb 28, 2026
d623deb
acyclic start block --to test
QinYuan2000 Feb 28, 2026
3db6bf4
identify midcycle for gamma conds -- to test
QinYuan2000 Feb 28, 2026
7d3643f
dep set and polishment
QinYuan2000 Mar 1, 2026
d27bc01
small bug fix
QinYuan2000 Mar 1, 2026
336e7fc
format
QinYuan2000 Mar 1, 2026
cf3ee07
polish
QinYuan2000 Mar 1, 2026
0ba08d2
cyclesup initial
QinYuan2000 Mar 4, 2026
2251543
refactor and cyclesupp MU cond
QinYuan2000 Mar 4, 2026
d7f8adb
regen update
QinYuan2000 Mar 4, 2026
cc41006
condition supp
QinYuan2000 Mar 5, 2026
8a63606
peephole opt
QinYuan2000 Mar 7, 2026
ba0db0a
debuglines temp
QinYuan2000 Mar 7, 2026
c250ebe
Merge commit 'fcc7ad8045814e7b396abc72eb59fcd22ccfeaac' into flattenfix
QinYuan2000 Mar 13, 2026
928e45e
all
QinYuan2000 Mar 17, 2026
7879f71
Merge remote-tracking branch 'origin/flattenfix' into ftd-updates
QinYuan2000 Mar 17, 2026
2afb763
temp workaround --must go back
QinYuan2000 Mar 17, 2026
0412ae4
incomplete fix
QinYuan2000 Mar 22, 2026
89ff1a9
precise dominator halfways
QinYuan2000 Mar 27, 2026
61682d2
small fix
QinYuan2000 Mar 27, 2026
9e73fa4
update
QinYuan2000 Mar 27, 2026
d3e79ed
fix
QinYuan2000 Mar 27, 2026
0a47b45
Merge remote-tracking branch 'upstream/main' into ftd-updates
QinYuan2000 Mar 27, 2026
c6d1dcc
restore notop
QinYuan2000 Mar 27, 2026
7cb113b
Merge remote-tracking branch 'upstream/main' into new-ftd
QinYuan2000 Mar 29, 2026
71c46a5
disable debug log
QinYuan2000 Mar 29, 2026
a0589a1
temp fix S2Q
QinYuan2000 Mar 31, 2026
a12aa6c
Added cyce extraction + backward edge identification logic and integr…
AyaElAkhras Apr 8, 2026
525ecc1
Convert constant should come later and should not involve source trig…
AyaElAkhras Apr 9, 2026
be7932e
Merge branch 'new-ftd' into new-ftd-smart-buffer
AyaElAkhras Apr 9, 2026
675d300
Replaced all cycle detection approaches with direct backedge detecti…
AyaElAkhras Apr 10, 2026
b1db61e
Removing Johnson from CMake because it is not needed
AyaElAkhras Apr 10, 2026
8776202
Added loop exit peephole optimization
AyaElAkhras Apr 11, 2026
fc446b7
Fixed choice of BBs in peephole optimizations
AyaElAkhras Apr 11, 2026
e01afb9
Changed legacy constant triggering for consistency + changed suppress…
AyaElAkhras Apr 11, 2026
3338e98
Run FTD even in the absence of LSQs on constants previously triggerd …
AyaElAkhras Apr 11, 2026
d6e9d05
Fixed bugs in join generator
AyaElAkhras Apr 12, 2026
9189a9f
Updated the logic of a self-dependency in groups
AyaElAkhras Apr 12, 2026
efb6abf
Added a peephole optimization for lazy forks
AyaElAkhras Apr 12, 2026
99251c1
Fixed a bug in restoreCfStructure
AyaElAkhras Apr 12, 2026
d69fe4b
Adjusted constant triggering and bitwidth optimization to be consiste…
AyaElAkhras Apr 13, 2026
3e79bba
Reverted back the lazy fork self-dependency
AyaElAkhras Apr 13, 2026
cf1e239
Generalized backedge detection to Inits
AyaElAkhras Apr 13, 2026
56d7fa9
[verilog-beta] Support noti unit (#856)
delaram-mz Apr 15, 2026
cadcf3e
Fixes in buffer placement and constant triggering
AyaElAkhras Apr 28, 2026
dafa11e
sort condition variables
QinYuan2000 May 4, 2026
7fa0eb2
fix ordering for all expressions
QinYuan2000 May 5, 2026
2876827
Fix bugs on multiple nesting loops on decision graph
QinYuan2000 May 6, 2026
fc073e4
MUX two data inputs same value optimization
QinYuan2000 May 6, 2026
4268134
Refactor
QinYuan2000 May 25, 2026
abd7bf0
Merge same processs
QinYuan2000 May 25, 2026
f273b3a
formalize debuglogs
QinYuan2000 May 25, 2026
57d5757
small fix on comments
QinYuan2000 May 25, 2026
5dc1668
Enable sourcable constants in FTD conversion
AyaElAkhras Jun 2, 2026
3e0c083
Update steering logic simplifications
AyaElAkhras Jun 2, 2026
23d6004
Update straight-to-queue fork handling
AyaElAkhras Jun 3, 2026
94748fd
update log
QinYuan2000 Jun 4, 2026
f168655
Merge remote-tracking branch 'upstream/new-ftd-smart-buffer' into new…
QinYuan2000 Jun 5, 2026
dfeaa1c
Apply changes from PR 786
QinYuan2000 Jun 5, 2026
648eb49
fix the previous merge
QinYuan2000 Jun 5, 2026
87232e4
Merge remote-tracking branch 'upstream/main' into new-ftd-smart-buffer
QinYuan2000 Jun 5, 2026
d758d04
fix the previous merge
QinYuan2000 Jun 5, 2026
4a03557
clean up handshakecombinesteeringlogic
QinYuan2000 Jun 6, 2026
1e47d25
refinement
QinYuan2000 Jun 7, 2026
342d1f2
add loop filter and dominator judgement, refine comments initially
QinYuan2000 Jun 7, 2026
c04e31a
refine comments
QinYuan2000 Jun 8, 2026
df93987
full logic
QinYuan2000 Jun 22, 2026
60415b9
update comments on main func
QinYuan2000 Jun 22, 2026
a93c432
clang-format
QinYuan2000 Jun 22, 2026
ff51311
comment update
QinYuan2000 Jun 22, 2026
c84cf1a
finalize main function comments
QinYuan2000 Jun 23, 2026
0508b8c
format
QinYuan2000 Jun 23, 2026
65475c0
format
QinYuan2000 Jun 23, 2026
851a689
temp fix
QinYuan2000 Jun 23, 2026
6031e5d
new fix
QinYuan2000 Jun 25, 2026
d986ef3
Merge remote-tracking branch 'upstream/main' into new-ftd-smart-buffer
QinYuan2000 Jun 29, 2026
8ff6e91
update
QinYuan2000 Jun 29, 2026
1746080
update
QinYuan2000 Jun 29, 2026
477b0a1
update
QinYuan2000 Jun 29, 2026
2ab4940
Merge branch 'init' into new-ftd-smart-buffer
QinYuan2000 Jun 29, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions data/rtl-config-vhdl.json
Original file line number Diff line number Diff line change
Expand Up @@ -458,6 +458,16 @@
"name": "handshake.shrsi",
"generator": "python $DYNAMATIC/tools/unit-generators/vhdl/vhdl-unit-generator.py -n $MODULE_NAME -o $OUTPUT_DIR/$MODULE_NAME.vhd -t shrsi -p bitwidth=$BITWIDTH extra_signals=$EXTRA_SIGNALS"
},
{

@AyaElAkhras AyaElAkhras Jun 25, 2026

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.

This is related to the definition of a new operation for the INIT. I suggest moving this to a separate PR along with its VHDL file.

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.

Sure. In PR #989.

"name": "handshake.init",
"parameters": [
{
"name": "INITIAL_VALUE",
"type": "unsigned"
}
],
"generator": "python $DYNAMATIC/tools/unit-generators/vhdl/vhdl-unit-generator.py -n $MODULE_NAME -o $OUTPUT_DIR/$MODULE_NAME.vhd -t init -p bitwidth=$BITWIDTH extra_signals=$EXTRA_SIGNALS initial_value=$INITIAL_VALUE"
},
{
"name": "handshake.shrui",
"generator": "python $DYNAMATIC/tools/unit-generators/vhdl/vhdl-unit-generator.py -n $MODULE_NAME -o $OUTPUT_DIR/$MODULE_NAME.vhd -t shrui -p bitwidth=$BITWIDTH extra_signals=$EXTRA_SIGNALS"
Expand Down
59 changes: 41 additions & 18 deletions experimental/include/experimental/Support/FtdImplementation.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@
//
//===----------------------------------------------------------------------===//
//
// Declares the core functions to run the Fast Token Delivery algorithm,
// according to the original FPGA'22 paper by Elakhras et al.
// (https://ieeexplore.ieee.org/document/10035134).
// Declares the top-level steps of the Fast Token Delivery (FTD) algorithm:
// converting phi functions to GSA gates, regeneration, suppression dispatch,
// and condition placeholders. The suppression circuit construction itself
// lives in FtdSuppression.h.
//
//===----------------------------------------------------------------------===//

Expand All @@ -18,45 +19,67 @@
#include "dynamatic/Dialect/Handshake/HandshakeOps.h"
#include "dynamatic/Support/Backedge.h"
#include "experimental/Analysis/GSAAnalysis.h"
#include "experimental/Support/FtdSupport.h"
#include "mlir/Dialect/Func/IR/FuncOps.h"

namespace dynamatic {
namespace experimental {
namespace ftd {

// ShadowCFG is declared in FtdSupport.h

/// Create SourceOp condition placeholders for every conditional block in the
/// region. Must be called before addGsaGates.
void createAllCondPlaceholders(Region &region, OpBuilder &builder);

/// After addBranchOps (multi-block, handshake ConditionalBranchOps exist),
/// replace each condition placeholder with NotIOp(realCond) that captures
/// the actual handshake condition value.
void resolveCondPlaceholders(handshake::FuncOp funcOp, OpBuilder &builder,
ShadowCFG &shadow);

/// After addRegen/addSupp, short-circuit all NotIOp condition placeholders
/// and erase them along with their source+constant operands.
void finalizeCondPlaceholders(handshake::FuncOp funcOp);

/// This function implements the regeneration mechanism over a pair made of a
/// producer and a consumer (see `addRegen` description).
void addRegenOperandConsumer(PatternRewriter &rewriter,
dynamatic::handshake::FuncOp &funcOp,
Operation *consumerOp, Value operand);
void addRegenOperandConsumer(mlir::OpBuilder &builder,
handshake::FuncOp &funcOp,
mlir::Operation *consumerOp, mlir::Value operand,
ShadowCFG &shadow);

/// This function implements the suppression mechanism over a pair made of a
/// producer and a consumer (see `addSupp` description).
void addSuppOperandConsumer(PatternRewriter &rewriter,
handshake::FuncOp &funcOp, Operation *consumerOp,
Value operand);
void addSuppOperandConsumer(mlir::OpBuilder &builder, handshake::FuncOp &funcOp,
Operation *consumerOp, Value operand,
ShadowCFG &shadow);

/// When the consumer is in a loop while the producer is not, the value must
/// be regenerated as many times as needed. This function is in charge of
/// adding some merges to the network, to that this can be done. The new
/// merge is moved inside of the loop, and it works like a reassignment
/// (cfr. FPGA'22, Section V.C).
void addRegen(handshake::FuncOp &funcOp, PatternRewriter &rewriter);
/// adding some merges to the network, so that this can be done. The new
/// merge is moved inside of the loop, and it works like a reassignment.
void addRegen(handshake::FuncOp &funcOp, mlir::OpBuilder &builder,
ShadowCFG &shadow);

/// Given each pairs of producers and consumers within the circuit, the
/// producer might create a token which is never used by the corresponding
/// consumer, because of the control decisions. In this scenario, the token
/// must be suppressed. This function inserts a `SUPPRESS` block whenever it
/// is necessary, according to FPGA'22 (IV.C and V)
void addSupp(handshake::FuncOp &funcOp, PatternRewriter &rewriter);
/// is necessary.
void addSupp(handshake::FuncOp &funcOp, mlir::OpBuilder &builder,
ShadowCFG &shadow);

/// Starting from the information collected by the gsa analysis pass,
/// instantiate some mux operations at the beginning of each block which
/// work as explicit phi functions. If `removeTerminators` is true, the `cf`
/// terminators in the function are modified to stop feeding the successive
/// blocks.
LogicalResult addGsaGates(Region &region, PatternRewriter &rewriter,
const gsa::GSAAnalysis &gsa, Backedge startValue,
bool removeTerminators = true);
LogicalResult addGsaGates(
Region &region, PatternRewriter &rewriter, const gsa::GSAAnalysis &gsa,
Backedge startValue,
DenseMap<Value, SmallVector<Backedge, 2>> *pendingMuxOperands = nullptr,
bool removeTerminators = true);

/// For each non-init merge in the IR, run the GSA analysis to obtain its GSA
/// equivalent, then use `addGsaGates` to instantiate such operations in the IR.
Expand Down
125 changes: 119 additions & 6 deletions experimental/include/experimental/Support/FtdSupport.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@
//
//===----------------------------------------------------------------------===//
//
// Declares some utility functions which are useful for both the fast token
// delivery algorithm and for the GSA analysis pass. All the functions are about
// analyzing relationships between blocks and handshake operations.
// Declares utility functions and data structures shared across the FTD
// algorithm. Includes CFG analysis helpers, type utilities, annotation
// constants, and the ShadowCFG bridge between the original CFG and the
// flattened handshake IR.
//
//===----------------------------------------------------------------------===//

Expand All @@ -18,11 +19,88 @@
#include "dynamatic/Dialect/Handshake/HandshakeOps.h"
#include "experimental/Support/BooleanLogic/BoolExpression.h"
#include "mlir/Analysis/CFGLoopInfo.h"
#include "mlir/Dialect/Func/IR/FuncOps.h"

namespace dynamatic {
namespace experimental {
namespace ftd {

// ===--------------------------------------------------------------------=== //
// Annotation constants used throughout the FTD algorithm.
// ===--------------------------------------------------------------------=== //

/// Annotation to use in the IR when an operation needs to be skipped by the FTD
/// algorithm.
constexpr llvm::StringLiteral FTD_OP_TO_SKIP("ftd.skip");
/// Annotation to identify muxes inserted with the `addGsaGates`
/// functionalities.
constexpr llvm::StringLiteral FTD_EXPLICIT_MU("ftd.MU");
constexpr llvm::StringLiteral FTD_EXPLICIT_GAMMA("ftd.GAMMA");
/// Temporary annotation to be used with merges created with the
/// `createPhiNetwork` functionality, which will then be converted into muxes.
constexpr llvm::StringLiteral NEW_PHI("nphi");
/// Annotation to use for initial merges and initial false constants.
constexpr llvm::StringLiteral FTD_INIT_MERGE("ftd.imerge");
/// Annotation to use for regeneration multiplexers.
constexpr llvm::StringLiteral FTD_REGEN("ftd.regen");
/// Annotation for condition variable placeholders.
constexpr llvm::StringLiteral FTD_COND_VAR("ftd.cvar");

// ===--------------------------------------------------------------------=== //
// ShadowCFG
// ===--------------------------------------------------------------------=== //

/// A temporary shadow of the original CFG, built after CfToHandshake
/// conversion flattens everything. Encapsulates the shadow Region
/// (with real CF terminators) plus a condition-value map that bridges
/// shadow analysis to real handshake Values.
///
/// All analysis infrastructure (BlockIndexing, CFGLoopInfo, path
/// enumeration, dominance) operates on getRegion() as if the original
/// CFG were still alive. The only thing the shadow cannot provide
/// natively is the real handshake condition Value for each cond_br
/// block — getCondition() provides that.
struct ShadowCFG {
mlir::func::FuncOp shadowFunc;
llvm::DenseMap<unsigned, mlir::Value> conditionMap;

mlir::Region &getRegion() { return shadowFunc.getBody(); }

mlir::Block *getBlock(unsigned bbIdx) {
for (auto [i, blk] : llvm::enumerate(getRegion()))
if (i == bbIdx)
return &blk;
llvm_unreachable("BB index out of range in shadow CFG");
}

unsigned getBlockIndex(mlir::Block *block) {
for (auto [i, blk] : llvm::enumerate(getRegion()))
if (&blk == block)
return i;
llvm_unreachable("Block not found in shadow CFG");
}

/// Get the real handshake condition Value for the cond_br in block bbIdx.
/// Returns nullptr if the block had an unconditional branch.
mlir::Value getCondition(unsigned bbIdx) {
auto it = conditionMap.find(bbIdx);
return (it != conditionMap.end()) ? it->second : nullptr;
}

mlir::Value getCondition(mlir::Block *block) {
return getCondition(getBlockIndex(block));
}

void destroy() {
if (shadowFunc)
shadowFunc.erase();
}
};

// ===--------------------------------------------------------------------=== //
// BlockIndexing
// ===--------------------------------------------------------------------=== //

/// Class to associate an index to each block, so that if block Bi dominates
/// block Bj then i < j. While this is guaranteed by the MLIR CFG construction,
/// it cannot really be given for granted, thus it is more convenient to have a
Expand All @@ -49,10 +127,10 @@ class BlockIndexing {
/// Get the index of a block.
std::optional<unsigned> getIndexFromBlock(Block *bb) const;

/// Return true if the index of bb1 is greater than then index of bb2.
/// Return true if the index of bb1 is greater than the index of bb2.
bool isGreater(Block *bb1, Block *bb2) const;

/// Return true if the index of bb1 is smaller than then index of bb2.
/// Return true if the index of bb1 is smaller than the index of bb2.
bool isLess(Block *bb1, Block *bb2) const;

/// Given a block whose name is `^BBN` (where N is an integer) return a string
Expand All @@ -61,6 +139,10 @@ class BlockIndexing {
std::string getBlockCondition(Block *block) const;
};

// ===--------------------------------------------------------------------=== //
// CFG Analysis Utilities
// ===--------------------------------------------------------------------=== //

/// Checks if the source and destination are in a loop
/// (including any of their ancestor loops).
bool isSameLoopBlocks(Block *source, Block *dest, const mlir::CFGLoopInfo &li);
Expand Down Expand Up @@ -92,12 +174,43 @@ getPathExpression(ArrayRef<Block *> path, DenseSet<unsigned> &blockIndexSet,
const DenseSet<Block *> &deps = DenseSet<Block *>(),
bool ignoreDeps = true);

/// A lightweight DFS to check if 'end' is reachable from 'start'.
bool isReachable(Block *start, Block *end);

// ===--------------------------------------------------------------------=== //
// Type Utilities
// ===--------------------------------------------------------------------=== //

/// Return the channelified version of the input type.
Type channelifyType(Type type);

/// Get an array of `size` elements all identical to the
/// Get an array of `size` elements all identical to the channelified type.
SmallVector<Type> getListTypes(Type inputType, unsigned size = 2);

// ===--------------------------------------------------------------------=== //
// IR Attribute Utilities
// ===--------------------------------------------------------------------=== //

/// Compute the positional index of `block` in its parent region and set
/// the handshake.bb attribute on `op`.
void setBBAttr(Operation *op, Block *block, OpBuilder &builder);

/// Set the handshake.bb attribute on `op` from an existing attribute.
void setBBAttr(Operation *op, IntegerAttr bbAttr);

/// Set the handshake.bb attribute on `op`, preferring `bbAttr` if available,
/// otherwise computing from `block`.
void setBBAttrWithFallback(Operation *op, IntegerAttr bbAttr, Block *block,
OpBuilder &builder);

/// Build a `handshake.bb` IntegerAttr (32-bit unsigned) for `bbIdx`.
IntegerAttr getBBIndexAttr(MLIRContext *ctx, unsigned bbIdx);

/// Get or create a SourceOp placeholder in `condBlock` representing the
/// condition of that block's terminator. Reuses existing placeholder if one
/// exists. Tagged with FTD_COND_VAR and FTD_OP_TO_SKIP so that FTD skips it.
Value getOrCreateCondPlaceholder(Block *condBlock, OpBuilder &builder);

} // namespace ftd
} // namespace experimental
} // namespace dynamatic
Expand Down
Loading
Loading