Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
6 changes: 4 additions & 2 deletions include/circt-c/Dialect/Synth.h
Original file line number Diff line number Diff line change
Expand Up @@ -99,9 +99,11 @@ MLIR_CAPI_EXPORTED int64_t
synthLongestPathDataflowPathGetDelay(SynthLongestPathDataflowPath dataflowPath);

MLIR_CAPI_EXPORTED SynthLongestPathObject
synthLongestPathDataflowPathGetFanIn(SynthLongestPathDataflowPath dataflowPath);
synthLongestPathDataflowPathGetStartPoint(
SynthLongestPathDataflowPath dataflowPath);

MLIR_CAPI_EXPORTED SynthLongestPathObject synthLongestPathDataflowPathGetFanOut(
MLIR_CAPI_EXPORTED SynthLongestPathObject
synthLongestPathDataflowPathGetEndPoint(
SynthLongestPathDataflowPath dataflowPath);

MLIR_CAPI_EXPORTED SynthLongestPathHistory
Expand Down
66 changes: 34 additions & 32 deletions include/circt/Dialect/Synth/Analysis/LongestPathAnalysis.h
Original file line number Diff line number Diff line change
Expand Up @@ -90,15 +90,15 @@ struct DebugPoint {
StringRef comment;
};

// An OpenPath represents a path from a fan-in with an associated
// An OpenPath represents a path from a start point with an associated
// delay and history of debug points.
struct OpenPath {
OpenPath(circt::igraph::InstancePath path, Value value, size_t bitPos,
int64_t delay = 0, llvm::ImmutableList<DebugPoint> history = {})
: fanIn(path, value, bitPos), delay(delay), history(history) {}
: startPoint(path, value, bitPos), delay(delay), history(history) {}
OpenPath() = default;

const Object &getFanIn() const { return fanIn; }
const Object &getStartPoint() const { return startPoint; }
int64_t getDelay() const { return delay; }
const llvm::ImmutableList<DebugPoint> &getHistory() const { return history; }

Expand All @@ -108,54 +108,56 @@ struct OpenPath {
llvm::ImmutableListFactory<DebugPoint> *debugPointFactory,
circt::igraph::InstancePath path);

Object fanIn;
Object startPoint;
int64_t delay;
// History of debug points represented by linked lists.
// The head of the list is the farthest point from the fanIn.
// The head of the list is the farthest point from the start point.
llvm::ImmutableList<DebugPoint> history;
};

// A DataflowPath represents a complete timing path from a fanout to a fanin
// with associated delay information. This is the primary result type for
// longest path analysis, containing both endpoints and path history.
// A DataflowPath represents a complete timing path from a end point to a
// start point with associated delay information. This is the primary result
// type for longest path analysis, containing both end points and path history.
class DataflowPath {
public:
// FanOut can be either an internal circuit object or a module output port
// end point can be either an internal circuit object or a module output port
// This flexibility allows representing both closed paths
// (register-to-register) and open paths (register-to-output) in a unified way
using OutputPort = std::tuple<hw::HWModuleOp, size_t, size_t>;
using FanOutType = std::variant<Object, OutputPort>;
using EndPointType = std::variant<Object, OutputPort>;

// Constructor for paths with Object fanout (internal circuit nodes)
DataflowPath(Object fanOut, OpenPath fanIn, hw::HWModuleOp root)
: fanOut(fanOut), path(fanIn), root(root) {}
// Constructor for paths with Object end point (internal circuit nodes)
DataflowPath(Object endPoint, OpenPath startPoint, hw::HWModuleOp root)
: endPoint(endPoint), path(startPoint), root(root) {}

// Constructor for paths with port fanout (module output ports)
DataflowPath(OutputPort fanOut, OpenPath fanIn, hw::HWModuleOp root)
: fanOut(fanOut), path(fanIn), root(root) {}
// Constructor for paths with port end point (module output ports)
DataflowPath(OutputPort endPoint, OpenPath startPoint, hw::HWModuleOp root)
: endPoint(endPoint), path(startPoint), root(root) {}

DataflowPath() = default;

int64_t getDelay() const { return path.delay; }
const Object &getFanIn() const { return path.fanIn; }
const FanOutType &getFanOut() const { return fanOut; }
const Object &getFanOutAsObject() const { return std::get<Object>(fanOut); }
const OutputPort &getFanOutAsPort() const {
return std::get<OutputPort>(fanOut);
const Object &getStartPoint() const { return path.startPoint; }
const EndPointType &getEndPoint() const { return endPoint; }
const Object &getEndPointAsObject() const {
return std::get<Object>(endPoint);
}
const OutputPort &getEndPointAsPort() const {
return std::get<OutputPort>(endPoint);
}
hw::HWModuleOp getRoot() const { return root; }
const llvm::ImmutableList<DebugPoint> &getHistory() const {
return path.history;
}
const OpenPath &getPath() const { return path; }

// Get source location for the fanout point (for diagnostics)
Location getFanOutLoc();
// Get source location for the end point (for diagnostics)
Location getEndPointLoc();

void setDelay(int64_t delay) { path.delay = delay; }

void print(llvm::raw_ostream &os);
void printFanOut(llvm::raw_ostream &os);
void printEndPoint(llvm::raw_ostream &os);

// Path elaboration for hierarchical analysis
// Prepends instance path information to create full hierarchical paths
Expand All @@ -165,9 +167,9 @@ class DataflowPath {
circt::igraph::InstancePath path);

private:
FanOutType fanOut; // Either Object or (port_index, bit_index)
OpenPath path; // The actual timing path with history
hw::HWModuleOp root; // Root module for this path
EndPointType endPoint; // Either Object or (port_index, bit_index)
OpenPath path; // The actual timing path with history
hw::HWModuleOp root; // Root module for this path
};

// JSON serialization for DataflowPath
Expand Down Expand Up @@ -198,7 +200,7 @@ struct LongestPathAnalysisOptions {
/// are queried. Disables parallel processing.
bool lazyComputation = false;

/// Keep only the maximum delay path per fanout point.
/// Keep only the maximum delay path per end point.
/// Focuses on finding maximum delays, discarding non-critical paths.
/// Significantly faster and uses less memory when only delay bounds
/// are needed rather than complete path enumeration.
Expand All @@ -225,7 +227,7 @@ class LongestPathAnalysis {
const LongestPathAnalysisOptions &option = {});
~LongestPathAnalysis();

// Return all longest paths to each Fanin for the given value and bit
// Return all longest paths to each start point for the given value and bit
// position.
LogicalResult computeGlobalPaths(Value value, size_t bitPos,
SmallVectorImpl<DataflowPath> &results);
Expand All @@ -248,7 +250,7 @@ class LongestPathAnalysis {
// typically register-to-register paths. A closed path is a path that starts
// and ends at sequential elements (registers/flip-flops), forming a complete
// timing path through combinational logic. The path may cross module
// boundaries but both endpoints are sequential elements, not ports.
// boundaries but both end points are sequential elements, not ports.
LogicalResult getClosedPaths(StringAttr moduleName,
SmallVectorImpl<DataflowPath> &results,
bool elaboratePaths = false) const;
Expand Down Expand Up @@ -344,8 +346,8 @@ class LongestPathCollection {
// Sort the paths by delay in descending order.
void sortInDescendingOrder();

// Sort and drop all paths except the longest path per fanout point.
void sortAndDropNonCriticalPathsPerFanOut();
// Sort and drop all paths except the longest path per end point.
void sortAndDropNonCriticalPathsPerEndPoint();

// Merge another collection into this one.
void merge(const LongestPathCollection &other);
Expand Down
2 changes: 1 addition & 1 deletion include/circt/Dialect/Synth/Transforms/SynthPasses.td
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ def PrintLongestPathAnalysis
This pass performs longest path analysis on AIG circuits and outputs detailed
timing information including:
- Delay distribution statistics showing timing levels and path counts
- Critical path details for the top N fanout points
- Critical path details for the top N end points
- Path history with intermediate debug points for detailed analysis

The analysis considers each AIG and-inverter operation to have unit delay and
Expand Down
2 changes: 1 addition & 1 deletion integration_test/Bindings/Python/dialects/synth.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ def build_top(module):
for p in collection[:2]:
# CHECK-NEXT: delay 2 : out2[{{[0-9]+}}]
# CHECK-NEXT: delay 2 : out2[{{[0-9]+}}]
print("delay", p.delay, ":", p.fan_out)
print("delay", p.delay, ":", p.end_point)

# CHECK-NEXT: minus index slice: True
print("minus index slice:", len(collection[:-2]) == len(collection) - 2)
Expand Down
8 changes: 4 additions & 4 deletions lib/Bindings/Python/SynthModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -99,13 +99,13 @@ void circt::python::populateDialectSynthSubmodule(nb::module_ &m) {
[](SynthLongestPathDataflowPath &self) {
return synthLongestPathDataflowPathGetDelay(self);
})
.def_prop_ro("fan_in",
.def_prop_ro("start_point",
[](SynthLongestPathDataflowPath &self) {
return synthLongestPathDataflowPathGetFanIn(self);
return synthLongestPathDataflowPathGetStartPoint(self);
})
.def_prop_ro("fan_out",
.def_prop_ro("end_point",
[](SynthLongestPathDataflowPath &self) {
return synthLongestPathDataflowPathGetFanOut(self);
return synthLongestPathDataflowPathGetEndPoint(self);
})
.def_prop_ro("history",
[](SynthLongestPathDataflowPath &self) {
Expand Down
25 changes: 13 additions & 12 deletions lib/Bindings/Python/dialects/synth.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,12 +116,12 @@ def from_dict(cls, data: Dict[str, Any]) -> "DebugPoint":
@dataclass
class DataflowPath:
"""
Represents a complete dataflow path from fan-out to fan-in.
Represents a complete dataflow path from end point to start point.
A dataflow path captures the complete timing path through a circuit,
from an output point (fan-out) back to an input point (fan-in), including
from an output point (end-point) back to an input point (start-point), including
all intermediate debug points and the total delay.
Attributes:
fan_out: The output signal/object where this path ends
end_point: The output signal/object where this path ends
path: The OpenPath containing the detailed path information
root: The root module name for this analysis
"""
Expand All @@ -134,14 +134,14 @@ def delay(self) -> int:
return self._path.delay

@property
def fan_in(self) -> Object:
def start_point(self) -> Object:
"""Get the input signal/object where this path begins."""
return Object(self._path.fan_in)
return Object(self._path.start_point)

@property
def fan_out(self) -> Object:
def end_point(self) -> Object:
"""Get the output signal/object where this path ends."""
return Object(self._path.fan_out)
return Object(self._path.end_point)

@property
def history(self) -> List[DebugPoint]:
Expand Down Expand Up @@ -172,11 +172,12 @@ def to_flamegraph(self) -> str:
prefix = f"top:{self.root}"

# Build hierarchy strings for start and end points
fan_in_hierarchy = self._build_hierarchy_string(self.fan_in, prefix)
fan_out_hierarchy = self._build_hierarchy_string(self.fan_out, prefix)
start_point_hierarchy = self._build_hierarchy_string(
self.start_point, prefix)
end_point_hierarchy = self._build_hierarchy_string(self.end_point, prefix)

# Track current position and delay for incremental output
current_hierarchy = fan_in_hierarchy
current_hierarchy = start_point_hierarchy
current_delay = 0

# Process debug history points in reverse order (from input to output)
Expand All @@ -192,10 +193,10 @@ def to_flamegraph(self) -> str:
current_hierarchy = history_hierarchy
current_delay = debug_point.delay

# Add final segment to fan-out if there's remaining delay
# Add final segment to end-point if there's remaining delay
if current_delay != self.delay:
final_delay = self.delay - current_delay
trace.append(f"{fan_out_hierarchy} {final_delay}")
trace.append(f"{end_point_hierarchy} {final_delay}")

return "\n".join(trace)

Expand Down
12 changes: 6 additions & 6 deletions lib/CAPI/Dialect/Synth.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -176,19 +176,19 @@ synthLongestPathDataflowPathGetDelay(SynthLongestPathDataflowPath path) {
}

SynthLongestPathObject
synthLongestPathDataflowPathGetFanIn(SynthLongestPathDataflowPath path) {
synthLongestPathDataflowPathGetStartPoint(SynthLongestPathDataflowPath path) {
auto *wrapper = unwrap(path);
auto &fanIn = wrapper->getFanIn();
return wrap(const_cast<Object *>(&fanIn));
auto &startPoint = wrapper->getStartPoint();
return wrap(const_cast<Object *>(&startPoint));
}

SynthLongestPathObject
synthLongestPathDataflowPathGetFanOut(SynthLongestPathDataflowPath path) {
synthLongestPathDataflowPathGetEndPoint(SynthLongestPathDataflowPath path) {
auto *wrapper = unwrap(path);
if (auto *object = std::get_if<Object>(&wrapper->getFanOut())) {
if (auto *object = std::get_if<Object>(&wrapper->getEndPoint())) {
return wrap(object);
}
auto *ptr = std::get_if<DataflowPath::OutputPort>(&wrapper->getFanOut());
auto *ptr = std::get_if<DataflowPath::OutputPort>(&wrapper->getEndPoint());
return wrap(ptr);
}

Expand Down
Loading