-
-
Notifications
You must be signed in to change notification settings - Fork 795
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
fix[venom]: fix invalid phi
s after SCCP
#4181
Changes from 7 commits
9ceb3e3
c18ca96
dff03be
98652d0
db53eec
37dc99d
4bd7fb7
a867595
4f57fa1
a39bbe1
59f64f0
1128c60
826a0d3
c552757
ab38dea
4599ea1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||
---|---|---|---|---|---|---|---|---|
|
@@ -58,12 +58,14 @@ class SCCP(IRPass): | |||||||
work_list: list[WorkListItem] | ||||||||
cfg_dirty: bool | ||||||||
cfg_in_exec: dict[IRBasicBlock, OrderedSet[IRBasicBlock]] | ||||||||
cfg_phi_fix_needed: OrderedSet[IRBasicBlock] | ||||||||
|
||||||||
def __init__(self, analyses_cache: IRAnalysesCache, function: IRFunction): | ||||||||
super().__init__(analyses_cache, function) | ||||||||
self.lattice = {} | ||||||||
self.work_list: list[WorkListItem] = [] | ||||||||
self.cfg_dirty = False | ||||||||
self.cfg_phi_fix_needed = OrderedSet() | ||||||||
|
||||||||
def run_pass(self): | ||||||||
self.fn = self.function | ||||||||
|
@@ -74,7 +76,11 @@ def run_pass(self): | |||||||
|
||||||||
# self._propagate_variables() | ||||||||
|
||||||||
self.analyses_cache.invalidate_analysis(CFGAnalysis) | ||||||||
if self.cfg_dirty: | ||||||||
self.analyses_cache.force_analysis(CFGAnalysis) | ||||||||
self._fix_phi_nodes() | ||||||||
else: | ||||||||
self.analyses_cache.invalidate_analysis(CFGAnalysis) | ||||||||
|
||||||||
def _calculate_sccp(self, entry: IRBasicBlock): | ||||||||
""" | ||||||||
|
@@ -305,6 +311,9 @@ def _replace_constants(self, inst: IRInstruction): | |||||||
inst.opcode = "jmp" | ||||||||
inst.operands = [target] | ||||||||
self.cfg_dirty = True | ||||||||
for bb in inst.parent.cfg_out: | ||||||||
if bb.label == target: | ||||||||
self.cfg_phi_fix_needed.add(bb) | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||
|
||||||||
elif inst.opcode in ("assert", "assert_unreachable"): | ||||||||
lat = self._eval_from_lattice(inst.operands[0]) | ||||||||
|
@@ -329,6 +338,40 @@ def _replace_constants(self, inst: IRInstruction): | |||||||
if isinstance(lat, IRLiteral): | ||||||||
inst.operands[i] = lat | ||||||||
|
||||||||
def _fix_phi_nodes(self): | ||||||||
charles-cooper marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||
visited: OrderedSet[IRBasicBlock] = OrderedSet() | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why keep track of visited, instead of just iterating over |
||||||||
for bb in self.cfg_phi_fix_needed: | ||||||||
self._fix_phi_bb_r(bb, visited) | ||||||||
|
||||||||
def _fix_phi_bb_r(self, bb: IRBasicBlock, visited: OrderedSet[IRBasicBlock]): | ||||||||
|
||||||||
if bb in visited: | ||||||||
return | ||||||||
|
||||||||
for inst in bb.instructions: | ||||||||
if inst.opcode == "phi": | ||||||||
self._fix_phi_node_inst(inst) | ||||||||
|
||||||||
visited.add(bb) | ||||||||
|
||||||||
for next_bb in bb.cfg_out: | ||||||||
self._fix_phi_bb_r(next_bb, visited) | ||||||||
|
||||||||
def _fix_phi_node_inst(self, phi_inst: IRInstruction): | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||
if len(phi_inst.parent.cfg_in) != 1: | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. when can this happen? shouldn't we handle this case? |
||||||||
return | ||||||||
|
||||||||
src_bb: IRBasicBlock = phi_inst.parent.cfg_in.first() | ||||||||
assert isinstance(src_bb, IRBasicBlock) | ||||||||
|
||||||||
from_src_bb = filter(lambda x: x[0] == src_bb.label, phi_inst.phi_operands) | ||||||||
operands = list(map(lambda x: x[1], from_src_bb)) | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. please use a list comprehension here
Suggested change
|
||||||||
|
||||||||
assert len(operands) == 1 | ||||||||
assert isinstance(operands[0], IRVariable) | ||||||||
assert phi_inst.output is not None | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||
phi_inst.output.value = operands[0] | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why modify the instruction if it gets removed on the next line? |
||||||||
phi_inst.parent.remove_instruction(phi_inst) | ||||||||
charles-cooper marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||
|
||||||||
|
||||||||
def _meet(x: LatticeItem, y: LatticeItem) -> LatticeItem: | ||||||||
if x == LatticeEnum.TOP: | ||||||||
|
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.
Why not
self._fix_phi_bb_r(bb, OrderedSet())
here and remove all the need forself.cfg_phi_fix_needed
and iterating later?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.
The reason was not to iterate over some basic block multiple times. Since solutions only detects start from which the occurrence of faulty phi node could be possible but not the end there could be a lot of overlap. In this case since I iterate over possible positions of the faulty phi nodes at the end I visit every possible basic block only once.