Loading [MathJax]/extensions/tex2jax.js
CIRCT 21.0.0git
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
LongestPathAnalysis.h
Go to the documentation of this file.
1//===----------------------------------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file defines the longest path analysis for the AIG dialect.
10// The analysis computes the maximum delay through combinational paths in a
11// circuit where each AIG and-inverter operation is considered to have a unit
12// delay. It handles module hierarchies and provides detailed path information
13// including sources, sinks, delays, and debug points.
14//
15//===----------------------------------------------------------------------===//
16
17#ifndef CIRCT_ANALYSIS_AIG_ANALYSIS_H
18#define CIRCT_ANALYSIS_AIG_ANALYSIS_H
19
22#include "circt/Support/LLVM.h"
23#include "mlir/IR/BuiltinOps.h"
24#include "mlir/IR/MLIRContext.h"
25#include "llvm/ADT/ArrayRef.h"
26#include "llvm/ADT/ImmutableList.h"
27#include "llvm/ADT/SmallVector.h"
28#include "llvm/Support/JSON.h"
29#include <variant>
30
31namespace mlir {
32class AnalysisManager;
33} // namespace mlir
34namespace circt {
35namespace igraph {
36class InstanceGraph;
37} // namespace igraph
38namespace aig {
39
40// A class represents an object in the dataflow graph.
41// An Object identifies a specific bit of a value at a specific instance path.
42struct Object {
45 Object() = default;
46
47 bool operator==(const Object &other) const {
48 return instancePath == other.instancePath && value == other.value &&
49 bitPos == other.bitPos;
50 }
51
52 void print(llvm::raw_ostream &os) const;
55
57 Value value;
58 size_t bitPos;
59};
60
61// A debug point represents a point in the dataflow graph which carries delay
62// and optional comment. Debug points are used to track the history of a path
63// and provide context for debugging.
64struct DebugPoint {
65 DebugPoint(circt::igraph::InstancePath path, Value value, size_t bitPos,
66 int64_t delay = 0, StringRef comment = "")
67 : object(path, value, bitPos), delay(delay), comment(comment) {}
68
69 // Trait for ImmutableList.
70 void Profile(llvm::FoldingSetNodeID &ID) const {
71 for (auto &inst : object.instancePath) {
72 ID.AddPointer(inst.getAsOpaquePointer());
73 }
74 ID.AddPointer(object.value.getAsOpaquePointer());
75 ID.AddInteger(object.bitPos);
76 ID.AddInteger(delay);
77 }
78
79 void print(llvm::raw_ostream &os) const;
80
82 int64_t delay;
83 StringRef comment;
84};
85
86// An OpenPath represents a path from a fan-in with an associated
87// delay and history of debug points.
88struct OpenPath {
89 OpenPath(circt::igraph::InstancePath path, Value value, size_t bitPos,
90 int64_t delay = 0, llvm::ImmutableList<DebugPoint> history = {})
91 : fanIn(path, value, bitPos), delay(delay), history(history) {}
92 OpenPath() = default;
93
94 const Object &getFanIn() const { return fanIn; }
95 int64_t getDelay() const { return delay; }
96 const llvm::ImmutableList<DebugPoint> &getHistory() const { return history; }
97
98 void print(llvm::raw_ostream &os) const;
99 OpenPath &
101 llvm::ImmutableListFactory<DebugPoint> *debugPointFactory,
103
105 int64_t delay;
106 // History of debug points represented by linked lists.
107 // The head of the list is the farthest point from the fanIn.
108 llvm::ImmutableList<DebugPoint> history;
109};
110
111// A DataflowPath represents a complete timing path from a fanout to a fanin
112// with associated delay information. This is the primary result type for
113// longest path analysis, containing both endpoints and path history.
115public:
116 // FanOut can be either an internal circuit object or a module output port
117 // This flexibility allows representing both closed paths
118 // (register-to-register) and open paths (register-to-output) in a unified way
119 using OutputPort = std::pair<size_t, size_t>;
120 using FanOutType = std::variant<Object, OutputPort>;
121
122 // Constructor for paths with Object fanout (internal circuit nodes)
125
126 // Constructor for paths with port fanout (module output ports)
129
130 DataflowPath() = default;
131
132 int64_t getDelay() const { return path.delay; }
133 const Object &getFanIn() const { return path.fanIn; }
134 const FanOutType &getFanOut() const { return fanOut; }
135 const Object &getFanOutAsObject() const { return std::get<Object>(fanOut); }
137 return std::get<OutputPort>(fanOut);
138 }
139 hw::HWModuleOp getRoot() const { return root; }
140 const llvm::ImmutableList<DebugPoint> &getHistory() const {
141 return path.history;
142 }
143 const OpenPath &getPath() const { return path; }
144
145 // Get source location for the fanout point (for diagnostics)
146 Location getFanOutLoc();
147
148 void setDelay(int64_t delay) { path.delay = delay; }
149
150 void print(llvm::raw_ostream &os);
151 void printFanOut(llvm::raw_ostream &os);
152
153 // Path elaboration for hierarchical analysis
154 // Prepends instance path information to create full hierarchical paths
157 llvm::ImmutableListFactory<DebugPoint> *debugPointFactory,
159
160private:
161 FanOutType fanOut; // Either Object or (port_index, bit_index)
162 OpenPath path; // The actual timing path with history
163 hw::HWModuleOp root; // Root module for this path
164};
165
166// JSON serialization for DataflowPath
167llvm::json::Value toJSON(const circt::aig::DataflowPath &path);
168
169// Options for the longest path analysis.
173
174// This analysis finds the longest paths in the dataflow graph across modules.
175// Also be aware of the lifetime of the analysis, the results would be
176// invalid if the IR is modified. Currently there is no way to efficiently
177// update the analysis results, so it's recommended to only use this analysis
178// once on a design, and store the results in a separate data structure which
179// users can manage the lifetime.
181public:
182 // Entry points for analysis.
183 LongestPathAnalysis(Operation *moduleOp, mlir::AnalysisManager &am,
184 const LongestPathAnalysisOption &option = {});
186
187 // Return all longest paths to each Fanin for the given value and bit
188 // position.
189 LogicalResult getResults(Value value, size_t bitPos,
190 SmallVectorImpl<DataflowPath> &results) const;
191
192 // Return the maximum delay to the given value for all bit positions.
193 int64_t getMaxDelay(Value value) const;
194
195 // Return the average of the maximum delays across all bits of the given
196 // value, which is useful approximation for the delay of the value. For each
197 // bit position, finds all paths and takes the maximum delay. Then averages
198 // these maximum delays across all bits of the value.
199 int64_t getAverageMaxDelay(Value value) const;
200
201 // Return paths that are closed under the given module. Closed paths are
202 // typically register-to-register paths. A closed path is a path that starts
203 // and ends at sequential elements (registers/flip-flops), forming a complete
204 // timing path through combinational logic. The path may cross module
205 // boundaries but both endpoints are sequential elements, not ports.
206 LogicalResult getClosedPaths(StringAttr moduleName,
207 SmallVectorImpl<DataflowPath> &results,
208 bool elaboratePaths = false) const;
209
210 // Return input-to-internal timing paths for the given module.
211 // These are open paths from module input ports to internal sequential
212 // elements (registers/flip-flops).
214 StringAttr moduleName, SmallVectorImpl<DataflowPath> &results) const;
215
216 // Return internal-to-output timing paths for the given module.
217 // These are open paths from internal sequential elements to module output
218 // ports.
220 StringAttr moduleName, SmallVectorImpl<DataflowPath> &results) const;
221
222 // Get all timing paths in the given module including both closed and open
223 // paths. This is a convenience method that combines results from
224 // getClosedPaths, getOpenPathsFromInputPortsToInternal, and
225 // getOpenPathsFromInternalToOutputPorts. If elaboratedPaths is true, paths
226 // include full hierarchical instance information.
227 LogicalResult getAllPaths(StringAttr moduleName,
228 SmallVectorImpl<DataflowPath> &results,
229 bool elaboratePaths = false) const;
230
231 // Return true if the analysis is available for the given module.
232 bool isAnalysisAvailable(StringAttr moduleName) const;
233
234 // Return the top nodes that were used for the analysis.
235 llvm::ArrayRef<hw::HWModuleOp> getTopModules() const;
236
237 // This is the name of the attribute that can be attached to the module
238 // to specify the top module for the analysis. This is optional, if not
239 // specified, the analysis will infer the top module from the instance graph.
240 // However it's recommended to specify it, as the entire module tends to
241 // contain testbench or verification modules, which may have expensive paths
242 // that are not of interest.
243 static StringRef getTopModuleNameAttrName() {
244 return "aig.longest-path-analysis-top";
245 }
246
247 MLIRContext *getContext() const { return ctx; }
248
249private:
250 struct Impl;
252
253 mlir::MLIRContext *ctx;
254};
255
256// A wrapper class for the longest path analysis that also traces debug points.
257// This is necessary for analysis manager to cache the analysis results.
259public:
260 LongestPathAnalysisWithTrace(Operation *moduleOp, mlir::AnalysisManager &am)
261 : LongestPathAnalysis(moduleOp, am, {true}) {}
262};
263
264// A collection of longest paths. The data structure owns the paths, and used
265// for computing statistics and CAPI.
267public:
268 LongestPathCollection(MLIRContext *ctx) : ctx(ctx){};
269 const DataflowPath &getPath(unsigned index) const { return paths[index]; }
270 MLIRContext *getContext() const { return ctx; }
271 llvm::SmallVector<DataflowPath, 64> paths;
272
273 // Sort the paths by delay in descending order.
275
276 // Sort and drop all paths except the longest path per fanout point.
278
279private:
280 MLIRContext *ctx;
281};
282
283} // namespace aig
284} // namespace circt
285
286namespace llvm {
287// Provide DenseMapInfo for Object.
288template <>
291 std::tuple<circt::igraph::InstancePath, mlir::Value, size_t>>;
294 auto [path, value, bitPos] = Info::getEmptyKey();
295 return Object(path, value, bitPos);
296 }
297
299 auto [path, value, bitPos] = Info::getTombstoneKey();
300 return Object(path, value, bitPos);
301 }
302 static llvm::hash_code getHashValue(Object object) {
303 return Info::getHashValue(
304 {object.instancePath, object.value, object.bitPos});
305 }
306 static bool isEqual(const Object &a, const Object &b) {
307 return Info::isEqual({a.instancePath, a.value, a.bitPos},
308 {b.instancePath, b.value, b.bitPos});
309 }
310};
311} // namespace llvm
312#endif // CIRCT_ANALYSIS_AIG_ANALYSIS_H
const OpenPath & getPath() const
const OutputPort & getFanOutAsPort() const
const llvm::ImmutableList< DebugPoint > & getHistory() const
const Object & getFanOutAsObject() const
std::variant< Object, OutputPort > FanOutType
const FanOutType & getFanOut() const
DataflowPath & prependPaths(circt::igraph::InstancePathCache &cache, llvm::ImmutableListFactory< DebugPoint > *debugPointFactory, circt::igraph::InstancePath path)
DataflowPath(OutputPort fanOut, OpenPath fanIn, hw::HWModuleOp root)
const Object & getFanIn() const
DataflowPath(Object fanOut, OpenPath fanIn, hw::HWModuleOp root)
void printFanOut(llvm::raw_ostream &os)
std::pair< size_t, size_t > OutputPort
void print(llvm::raw_ostream &os)
hw::HWModuleOp getRoot() const
LongestPathAnalysisWithTrace(Operation *moduleOp, mlir::AnalysisManager &am)
LogicalResult getResults(Value value, size_t bitPos, SmallVectorImpl< DataflowPath > &results) const
LogicalResult getClosedPaths(StringAttr moduleName, SmallVectorImpl< DataflowPath > &results, bool elaboratePaths=false) const
int64_t getMaxDelay(Value value) const
int64_t getAverageMaxDelay(Value value) const
LogicalResult getAllPaths(StringAttr moduleName, SmallVectorImpl< DataflowPath > &results, bool elaboratePaths=false) const
LogicalResult getOpenPathsFromInternalToOutputPorts(StringAttr moduleName, SmallVectorImpl< DataflowPath > &results) const
llvm::ArrayRef< hw::HWModuleOp > getTopModules() const
bool isAnalysisAvailable(StringAttr moduleName) const
LogicalResult getOpenPathsFromInputPortsToInternal(StringAttr moduleName, SmallVectorImpl< DataflowPath > &results) const
const DataflowPath & getPath(unsigned index) const
llvm::SmallVector< DataflowPath, 64 > paths
This graph tracks modules and where they are instantiated.
An instance path composed of a series of instances.
Definition aig.py:1
llvm::json::Value toJSON(const circt::aig::DataflowPath &path)
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
void Profile(llvm::FoldingSetNodeID &ID) const
DebugPoint(circt::igraph::InstancePath path, Value value, size_t bitPos, int64_t delay=0, StringRef comment="")
void print(llvm::raw_ostream &os) const
circt::igraph::InstancePath instancePath
Object & prependPaths(circt::igraph::InstancePathCache &cache, circt::igraph::InstancePath path)
bool operator==(const Object &other) const
void print(llvm::raw_ostream &os) const
Object(circt::igraph::InstancePath path, Value value, size_t bitPos)
const Object & getFanIn() const
void print(llvm::raw_ostream &os) const
OpenPath(circt::igraph::InstancePath path, Value value, size_t bitPos, int64_t delay=0, llvm::ImmutableList< DebugPoint > history={})
OpenPath & prependPaths(circt::igraph::InstancePathCache &cache, llvm::ImmutableListFactory< DebugPoint > *debugPointFactory, circt::igraph::InstancePath path)
llvm::ImmutableList< DebugPoint > history
const llvm::ImmutableList< DebugPoint > & getHistory() const
A data structure that caches and provides paths to module instances in the IR.
static llvm::hash_code getHashValue(Object object)
static bool isEqual(const Object &a, const Object &b)