-
Notifications
You must be signed in to change notification settings - Fork 894
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add Optimization Barriers #4763
base: main
Are you sure you want to change the base?
Add Optimization Barriers #4763
Conversation
* This acts as an optimization barrier, limiting the rewriting allowed * For now this forbids all optimization, but attributes can be added to opt in to specific optimizations as required
* This uses $barrier optimization barriers to connect wires into the flattened module instead of connections
* This can optionally ignore rewriting the outputs of cells or processes * This by default rewrites drivers of wires with public names but can also optionally rewrite drivers of wires with private names * A -remove flag allows cleaning up the design by replacing barriers with connections
* This uses optbarriers and flatten -barriers to insert barriers on public wires in the design, limiting the optimization that can affect them
767981a
to
33d5138
Compare
Is there a background discussion on this cell somewhere? I'm interested in it as it's similar to a |
I brought it up at the Dev JF on monday but we didn't write down too much about the conclusions. The gist of it is that there are some applications for Yosys where it is more important to retain some amount of the structural information rather than just the semantic. This has caused issues like #3426 in the past and has given me similar issues recently where I want to structurally rewrite the drivers for some nodes which causes semantic changes to the design for formal verification. The alternative approach to something like optimization barriers is to not do the optimizations in the first place, but in my experience there tends to be lots of logic involved with private wires that cause a blowup in design size and can be cleaned away straightforwardly, the structure with respect to public wires is usually all that matters. Am open to any suggestions/critiques about how to go about this, this is just a draft for one way it can be done. |
I think I may need a bit more care with how
without optbarriers this generated a if (rst)
barrier_in <= barrier_out;
else
barrier_in <= a;
I think the right solution to this is that as well as rewriting signals to come from a barrier when they appear on the |
Since variants of this were brought up independently and for different use cases, I made an attempt now to summarize the motivating use cases that I'm aware of and how it would apply there:
|
Thanks for such a thorough analysis, @jix! |
I will also chime in and add that, if I'm understanding this pull correctly, this would be an incredibly useful feature for my project. I'm working on a triple modular redundancy plugin, and one major unresolved problem is passes like If I could instead annotate cells with |
543327f
to
f864b7a
Compare
f864b7a
to
6532cf6
Compare
Have fixed the process issue but it adds a reasonable bit more complexity. The idea is that a path through a set of assignments in a process from a variable to itself should see the pre-barrier version of itself, as this is needed in I have an example on a real design that matches the pattern I commented earlier in the thread where this more careful rewriting is needed to prevent an On a reasonable sized design running
The flop/latch inferences are the same (which is not true without the more complex process rewriting) and the rest of the numbers seem to be in the reasonable ranges for what id expect, although I haven't done a proper equivalence check or anything yet and this could probably do with tests. Not sure when I will get much time to add tests at the moment. Other than that I think the logic should be done so I will mark as ready for review for now. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have reviewed all the bits outside optbarries.cc
, I think we need to fix the bmt2 $buf
handling
@@ -966,7 +966,7 @@ struct FirrtlWorker | |||
register_reverse_wire_map(y_id, cell->getPort(ID::Y)); | |||
continue; | |||
} | |||
if (cell->type == ID($pos)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's strange this interprets $pos
without looking at the A_SIGNED
parameter, but if there's a bug it's pre-existing
@@ -677,7 +677,7 @@ struct Smt2Worker | |||
if (cell->type == ID($eqx)) return export_bvop(cell, "(= A B)", 'b'); | |||
|
|||
if (cell->type == ID($not)) return export_bvop(cell, "(bvnot A)"); | |||
if (cell->type == ID($pos)) return export_bvop(cell, "A"); | |||
if (cell->type.in(ID($pos), ID($buf), ID($barrier))) return export_bvop(cell, "A"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this will crash when given a $buf
or $barrier
as those don't have A_SIGNED
@@ -1071,7 +1071,7 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell) | |||
return true; | |||
} | |||
|
|||
if (cell->type == ID($_BUF_)) { | |||
if (cell->type.in(ID($buf), ID($_BUF_), ID($barrier))) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We met here :) (see #4803)
@@ -430,15 +430,15 @@ bool SatGen::importCell(RTLIL::Cell *cell, int timestep) | |||
return true; | |||
} | |||
|
|||
if (cell->type.in(ID($pos), ID($buf), ID($neg))) | |||
if (cell->type.in(ID($pos), ID($buf), ID($barrier), ID($neg))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think by supplying a SAT model for $barrier
to the optimization passes you are running the risk of barrier leakage. I would make the model opt-in, not sure how to do it best though
@@ -345,6 +366,10 @@ struct FlattenPass : public Pass { | |||
log(" with a public name the enclosing scope can be found via their\n"); | |||
log(" 'hdlname' attribute.\n"); | |||
log("\n"); | |||
log(" -barriers\n"); | |||
log(" Use $barrier cells to connect flattened modules to their surrounding\n"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"introduce optimization barriers when a flattened module drives a public wire" ?
|
||
for (int i = 0; i < GetSize(new_conn.first); i++) { | ||
const auto lhs = new_conn.first[i], rhs = new_conn.second[i]; | ||
auto& sigsig = !lhs.is_wire() || !lhs.wire->name.isPublic() ? skip_conn : barrier_conn; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think lhs.is_wire()
shouldn't happen here, we could add an assert
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Err, !lhs.is_wire()
This adds the
$barrier
cell type which represents an optimization barrier that Yosys should not optimize through. Changes include:$barrier
as just a buffer. I also added$buf
support while I was at it where it didn't exist.opt_merge
to ignore$barrier
-barriers
toflatten
that will insert barriers to drive all public wires driven by the flatteningoptbarriers
command to insert/remove barriers everywhere that public wires are driven. This has the following options:-nocells
- don't add barriers for the outputs of cells-noprocs
- don't add barriers for the outputs of processes-private
- add barriers for private wires as well as public-remove
- convert selected barriers back to connections-barriers
flag toprep
that callsoptbarriers
at the start and passes-barriers
to flatten. This should be a drop in replacement for a regularprep
call that has the benefit of maintaining all the structure among public wires.This still needs tests and probably some discussion about what the flags/defaults should be as currently this is very conservative on the optimizations allowed. I wasn't sure exactly what optimizations people would want to opt into but attributes can be added to
$barrier
to do so.