[FIRRTL] Add alternative constraint-based InferWidths pass#9173
[FIRRTL] Add alternative constraint-based InferWidths pass#9173
Conversation
There was a problem hiding this comment.
Please collect all the tests to a single file and put them in the appropriate tests folder with the normal LIT headers and directives and checks.
|
|
||
| // Width inference creates canonicalization opportunities. | ||
| pm.nest<firrtl::CircuitOp>().addPass(firrtl::createInferWidths()); | ||
| //pm.nest<firrtl::CircuitOp>().addPass(firrtl::createInferWidths()); |
There was a problem hiding this comment.
Please either add a cmdline control over this or remove the old line. Don't leave commented out code in the file.
| auto cs_duration = std::chrono::duration_cast<std::chrono::microseconds>(cs_time - start); | ||
| auto solve_duration = std::chrono::duration_cast<std::chrono::microseconds>(update_time - solve_time); | ||
| auto update_duration = std::chrono::duration_cast<std::chrono::microseconds>(end - update_time); | ||
| // std::cout << "generate constraint time : " << cs_duration.count() / 1000.0 << " ms\n"; |
There was a problem hiding this comment.
Please don't commit commented out code. I might suggest adding some performance counters from MLIR to track and report these.
| if (mapping.areAllModulesSkipped()) | ||
| return markAllAnalysesPreserved(); | ||
|
|
||
| auto solve_time = std::chrono::high_resolution_clock::now(); |
There was a problem hiding this comment.
See if MLIR's timing mechanisms are sufficient.
|
|
||
| // 输出结果 | ||
| if (solution.has_value()) { | ||
| // LLVM_DEBUG(llvm::dbgs() << "可行解找到:\n"; |
There was a problem hiding this comment.
Please don't commit commented out code. It looks like the LLVM_DEBUG guard is sufficient to have the code in.
| // bab | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| using Bounds = std::unordered_map<FieldRef, std::pair<int, int>, FieldRef::Hash>; |
There was a problem hiding this comment.
I haven't checked, but unordered_map is a red flag for deterministic behavior. The code might be fine, but it needs to be carefully checked.
| return success(); | ||
|
|
||
| bool mappingFailed = false; | ||
| TypeSwitch<Operation *>(op) |
There was a problem hiding this comment.
Consider using an OpVisitor.
| #include "llvm/ADT/SetVector.h" | ||
| #include "llvm/Support/Debug.h" | ||
| #include "llvm/Support/ErrorHandling.h" | ||
| #include <boost/graph/adjacency_list.hpp> |
There was a problem hiding this comment.
LLVM has a dim view of adding external dependencies. These would have to be very carefully considered.
| #include "llvm/Support/ErrorHandling.h" | ||
| #include <boost/graph/adjacency_list.hpp> | ||
| #include <boost/graph/floyd_warshall_shortest.hpp> | ||
| #include <boost/graph/strong_components.hpp> |
There was a problem hiding this comment.
There is a SCC implementation in MLIR which should likely be used.
| #include <boost/graph/floyd_warshall_shortest.hpp> | ||
| #include <boost/graph/strong_components.hpp> | ||
| #include <iostream> | ||
| #include <iomanip> |
There was a problem hiding this comment.
Please use MLIR/LLVM streams rather than the standard library.
| //===----------------------------------------------------------------------===// | ||
|
|
||
| // 节点类型 | ||
| using Node = std::variant<Zero, FieldRef>; |
There was a problem hiding this comment.
consider using a sentinel FieldRef. I think one already exists (value null).
c9aaa58 to
2f3745a
Compare
|
PR Update Summary Hi maintainers, I've comprehensively updated this PR to address all previous feedback:
@llvm/circt-maintainers @seldridge @darthscsi Could you please re-run CI and review when convenient? |
3c15856 to
221639e
Compare
1fe9115 to
b837c49
Compare
|
@schulyer Hi! I have resolved the conflict in Firtool.cpp, please re-run again! |
|
@seldridge @darthscsi Hi! I have resolved the conflict in Firtool.cpp, please re-run again! |
b837c49 to
0f16622
Compare
|
@seldridge Hi! I have resolved the build error. I think the reason for the error is that my local environment is different from the Docker test environment. Please re-run again! |
0f16622 to
d1856cc
Compare
|
@seldridge @darthscsi Dear reviewers, |
| } | ||
| }; | ||
|
|
||
| #include <list> |
There was a problem hiding this comment.
nit: Please include header at the top of file
| std::deque<Node> nodes; | ||
| DenseMap<FieldRef, Node *> nodeMap; | ||
|
|
There was a problem hiding this comment.
Isn't nodes reallocated when deque size is modified? If so I think nodeMap could refer to invalided node addresses. Certainly using bump allocator or unique_ptr is better here.
| LLVM_DEBUG(llvm::dbgs() << "initial matrix:\n"); | ||
| for (int i = 0; i < n; i++) { | ||
| for (int j = 0; j < n; j++) { | ||
| if (graph[i][j] == INF) | ||
| LLVM_DEBUG(llvm::dbgs() << " INF "); | ||
| else | ||
| LLVM_DEBUG(llvm::dbgs() << " " << graph[i][j] << " "); | ||
| } | ||
| LLVM_DEBUG(llvm::dbgs() << "\n"); | ||
| } |
There was a problem hiding this comment.
nit: you can put entire for loops under LLVM_DEBUG
| LLVM_DEBUG(llvm::dbgs() << "initial matrix:\n"); | |
| for (int i = 0; i < n; i++) { | |
| for (int j = 0; j < n; j++) { | |
| if (graph[i][j] == INF) | |
| LLVM_DEBUG(llvm::dbgs() << " INF "); | |
| else | |
| LLVM_DEBUG(llvm::dbgs() << " " << graph[i][j] << " "); | |
| } | |
| LLVM_DEBUG(llvm::dbgs() << "\n"); | |
| } | |
| LLVM_DEBUG({ | |
| lvm::dbgs() << "initial matrix:\n"; | |
| for (int i = 0; i < n; i++) { | |
| for (int j = 0; j < n; j++) { | |
| if (graph[i][j] == INF) | |
| llvm::dbgs() << " INF "; | |
| else | |
| llvm::dbgs() << " " << graph[i][j] << " "; | |
| } | |
| llvm::dbgs() << "\n"; | |
| } | |
| }); |
| //===- InferWidths_new.cpp - Infer width of types -------------------*- C++ | ||
| //-*-===// |
There was a problem hiding this comment.
| //===- InferWidths_new.cpp - Infer width of types -------------------*- C++ | |
| //-*-===// | |
| //===----------------------------------------------------------------------===// |
|
Could you add to and see if it passes? |
42ace46 to
db8244b
Compare
|
Hi @uenoku @seldridge 👋, ✅ Implemented Suggestions:
➡️ Next Steps:
|
…idth inference, but I don't find 'firrtl.domain.define %B, %A' in infer-widths.mlir:468:5. Don't know the reason about this error
|
Hi @uenoku @seldridge 👋, Thank you for your feedback on the PR. I've addressed the memory safety concerns by implementing the suggested CI Failure AnalysisThe Windows CI test is failing with this error: Investigation DoneI've thoroughly investigated this issue:
Request for AssistanceSince I can't reproduce this locally, could you please help with:
I'm happy to investigate further with your guidance. The complete test file and changes can be seen in the PR. |
|
It should be more than just Windows. See this commit: 1be4b77 Domain information can show up and it should ignored. |
Add the `DomainDefineOp` to the list of operations which are ignored by FIRRTL's `InferWidths` pass as they have no effect. Signed-off-by: Schuyler Eldridge <schuyler.eldridge@sifive.com>
Sort the types for the "no-op" case when visiting operations in FIRRTL's `InferWidths` pass. Signed-off-by: Schuyler Eldridge <schuyler.eldridge@sifive.com>
Cleanup trailing whitespace in an `InferWidths` test. Signed-off-by: Schuyler Eldridge <schuyler.eldridge@sifive.com>
Gets rid of a Slang warning.
Programs are essentially just modules. There are a few subtle semantic differences, but we aren't far enough down the simulation path to have those show up. For the time being, just treat programs as modules. We will add the necessary exit blocking mechanisms later on when we have sufficient simulation support in Arcilator.
Add support for lowering the `moore.builtin.time` op to a new `llhd.current_time` op that simply materializes the current simulation time as an SSA value. Error diff on circt-tests: ```diff -37 error: failed to legalize operation 'moore.builtin.time' +22 error: failed to legalize operation 'moore.time_to_logic' +15 error: failed to legalize operation 'moore.fmt.time' 0 total change ```
|
Hi @uenoku @seldridge 👋, I have now resolved the upstream conflicts and can merge cleanly. Please help me review the code again. |
|
I gave this a spin on an internal design that is 1.7GiB of FIRRTL. There's a pretty major performance regression vs. the old infer widths: Old: New: I haven't dug into this more to see what is going on. |
|
Hi @uenoku @seldridge 👋, Thank you for catching the performance regression in the earlier version and sharing those critical metrics! 🙏 I've taken this feedback seriously and conducted optimization on the width inference algorithm. Performance ImprovementsUsing the largest available FIRRTL design I could access (309MB), here are the optimized results:
Key optimizations:
Could you please re-run your 1.7GiB test case with this optimized implementation? I'm confident you'll see significant improvements. |
|
Yes, this looks way better now. I reran this and am seeing: Old: New: |
|
Hi @uenoku @seldridge 👋, First, thank you for your last feedback - I'm really glad to hear the optimizations are heading in the right direction! 🚀 Since it's been about a month since your last review, would you be available for another look when convenient? |
[WIP][FIRRTL] Add formally verified alternative InferWidths pass
🔍 Related Issue
Fixes #9140 (InferWidths failures on cyclic constraints)
📖 Background & Motivation
The current
InferWidthsimplementation has critical limitations:Correctness gaps: Fails on cyclic constraint cases like issue9140_0.mlir and issue9140_1.mlir
This PR introduces
InferWidths_new- a drop-in alternative pass that:⚙️ Technical Approach
The new pass implements a constraint-based width inference engine with:
🧪 Testing Strategy
Comprehensive verification across 2 test dimensions:
(
test/Dialect/FIRRTL/infer-widths.mlir)test_new_inferwidths/• issue9140_0.mlir (example 1)
• issue9140_1.mlir (example 2)
🚀 Integration Plan
Following maintainer's phased adoption strategy:
firrtl-infer-widths-newopt-in