Skip to content
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

Eliminate double inverts in pyrtl.optimize #462

Open
wants to merge 4 commits into
base: development
Choose a base branch
from
Open
Changes from 1 commit
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
50 changes: 50 additions & 0 deletions pyrtl/passes.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,61 @@ def optimize(update_working_block=True, block=None, skip_sanity_check=False):
constant_propagation(block, True)
_remove_unlistened_nets(block)
common_subexp_elimination(block)
_remove_double_inverts(block, skip_sanity_check)
if (not skip_sanity_check) or _get_debug_mode():
block.sanity_check()
return block


def _remove_double_inverts(block, skip_sanity_check=False):
""" Removes all double invert nets from the block. """

# checks if the wirevector is used at a LogicNet other than used_at_net
def is_wirevector_used_elsewhere(wire, used_at_nets):
for net in block.logic:
if net not in used_at_nets:
if wire.name in [x.name for x in net.args] \
or wire.name in [x.name for x in net.dests]:
return True
return False

new_logic = set()
net_exclude_set = set() # removed nets
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems better to call this removed_nets and remove the comment? :)

wire_removal_set = set()
for net1 in block.logic:
for net2 in block.logic:
# Conditions need to be satisfied for the nets to be removed:
# 1. Both nets should be invert nets
# 2. Nets should not be in net_exclude_set (nets that are already removed)
# 3. The destination of net1 should be the argument of net2
# (so we know the nets are connected)
# 4. The destination of net1 should not be used elsewhere
# (because we can't remove a wire that is used in another net)
if net1.op == '~' and net2.op == '~' \
and net1 not in net_exclude_set and net2 not in net_exclude_set \
and net1.dests[0].name == net2.args[0].name \
and not is_wirevector_used_elsewhere(net1.dests[0], (net1, net2)):
new_logic.add(LogicNet('w', None, args=net1.args, dests=net2.dests))
net_exclude_set.add(net1)
net_exclude_set.add(net2)
wire_removal_set.add(net1.dests[0])
break

for net in block.logic:
if net not in net_exclude_set:
new_logic.add(net)

block.logic = new_logic
for dead_wirevector in wire_removal_set:
block.remove_wirevector(dead_wirevector)

if (not skip_sanity_check) or _get_debug_mode():
block.sanity_check()

# clean up wire nodes
_remove_wire_nets(block, skip_sanity_check)


class _ProducerList(object):
""" Maps from wire to its immediate producer and finds ultimate producers. """
def __init__(self):
Expand Down
Loading