Skip to content

Commit

Permalink
Distinguish kinds of conditional jumps...
Browse files Browse the repository at this point in the history
In dotio, make "jump true" branches be bold.
  • Loading branch information
rocky committed Nov 24, 2024
1 parent e1fdc8c commit 8f072d6
Show file tree
Hide file tree
Showing 4 changed files with 61 additions and 27 deletions.
27 changes: 20 additions & 7 deletions control_flow/bb.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@
BB_EXIT,
BB_FINALLY,
BB_FOR,
BB_JUMP_CONDITIONAL,
BB_JUMP_BACKWARD_IF_FALSE,
BB_JUMP_FORWARD_IF_FALSE,
BB_JUMP_FORWARD_IF_TRUE,
BB_JUMP_TO_FALLTHROUGH,
BB_JUMP_UNCONDITIONAL,
BB_LOOP,
Expand Down Expand Up @@ -252,15 +254,21 @@ def __init__(self, version=PYTHON_VERSION_TRIPLE, is_pypy=IS_PYPY):
else:
self.EXCEPT_INSTRUCTIONS.add(opcode.opmap["RAISE_VARARGS"])

self.JUMP_CONDITIONAL = set()
self.JUMP_IF_FALSE = set()
for opname in (
"POP_JUMP_IF_FALSE",
"POP_JUMP_IF_TRUE",
"JUMP_IF_FALSE_OR_POP",
"POP_JUMP_IF_FALSE",
):
if opname in opcode.opmap:
self.JUMP_IF_FALSE.add(opcode.opmap[opname])

self.JUMP_IF_TRUE = set()
for opname in (
"JUMP_IF_TRUE_OR_POP",
"POP_JUMP_IF_TRUE",
):
if opname in opcode.opmap:
self.JUMP_CONDITIONAL.add(opcode.opmap[opname])
self.JUMP_IF_TRUE.add(opcode.opmap[opname])

self.NOFOLLOW_INSTRUCTIONS = {
opcode.opmap["RETURN_VALUE"],
Expand Down Expand Up @@ -465,8 +473,13 @@ def basic_blocks(
last_line_number = inst.starts_line

# Add block flags for certain classes of instructions
if op in bb.JUMP_CONDITIONAL:
flags.add(BB_JUMP_CONDITIONAL)
if op in bb.JUMP_IF_FALSE:
jump_type = BB_JUMP_FORWARD_IF_FALSE if inst.argval > inst.offset else BB_JUMP_BACKWARD_IF_FALSE
flags.add(jump_type)

if op in bb.JUMP_IF_TRUE:
jump_type = BB_JUMP_FORWARD_IF_TRUE if inst.argval > inst.offset else BB_JUMP_BACKWARD_IF_FALSE
flags.add(jump_type)

if op in bb.POP_BLOCK_INSTRUCTIONS:
flags.add(BB_POP_BLOCK)
Expand Down
15 changes: 12 additions & 3 deletions control_flow/cfg.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@
TreeGraph,
jump_flags,
BB_JOIN_POINT,
BB_JUMP_CONDITIONAL,
BB_JUMP_BACKWARD_IF_FALSE,
BB_JUMP_BACKWARD_IF_TRUE,
BB_JUMP_FORWARD_IF_FALSE,
BB_JUMP_FORWARD_IF_TRUE,
BB_LOOP,
BB_NOFOLLOW,
BB_ENTRY,
Expand Down Expand Up @@ -184,8 +187,14 @@ def add_edge(source_node, dest_node, edge_kind: str) -> Edge:
if jump_index > block.start_offset:
if BB_LOOP in block.flags:
edge_kind = "for-finish"
elif BB_JUMP_CONDITIONAL in self.block_nodes[block].flags:
edge_kind = "forward-conditional"
elif BB_JUMP_BACKWARD_IF_FALSE in self.block_nodes[block].flags:
edge_kind = "jump-backward-if-false"
elif BB_JUMP_BACKWARD_IF_TRUE in self.block_nodes[block].flags:
edge_kind = "jump-backward-if-true"
elif BB_JUMP_FORWARD_IF_FALSE in self.block_nodes[block].flags:
edge_kind = "jump-forward-if-false"
elif BB_JUMP_FORWARD_IF_TRUE in self.block_nodes[block].flags:
edge_kind = "jump-forward-if-true"
else:
edge_kind = "forward"
else:
Expand Down
12 changes: 7 additions & 5 deletions control_flow/dotio.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@

MAX_COLOR_LEVELS: Final = len(BB_LEVEL_BACKGROUNDS) - 1

flags_prefix: Final = "flags="
flags_prefix: Final = "flags={"
FEL: Final = len(flags_prefix)
NODE_TEXT_WIDTH = 26 + FEL

Expand Down Expand Up @@ -238,7 +238,9 @@ def add_edge(self, edge, exit_node: BasicBlock, edge_seen):
style = '[style="invis"]'
else:
style = '[style="dashed"]'
elif edge.kind == "forward-conditional":
elif edge.kind in ("jump-backward-if-true", "jump-forward-if-true"):
style = '[style="dotted,bold"]'
elif edge.kind in ("jump-backward-if-false", "jump-forward-if-false"):
style = '[style="dotted"]'

nid1 = self.node_ids[edge.source]
Expand All @@ -255,7 +257,7 @@ def add_edge(self, edge, exit_node: BasicBlock, edge_seen):
edge_port,
)

def node_repr(self, node, align, is_exit, is_dominator_format: bool):
def node_repr(self, node, align, is_exit):
jump_text = ""
reach_offset_text = ""
flag_text = ""
Expand All @@ -270,7 +272,7 @@ def node_repr(self, node, align, is_exit, is_dominator_format: bool):
format_flags_with_width(
node.flags,
NODE_TEXT_WIDTH - FEL,
align + (" " * (len("flags="))),
align + (" " * (len(flags_prefix))),
),
)
else:
Expand Down Expand Up @@ -332,7 +334,7 @@ def add_node(
node.number,
level,
align,
self.node_repr(node.bb, align, is_exit, is_dominator_format),
self.node_repr(node.bb, align, is_exit),
align,
)
self.buffer += " block_%d %s%s;\n" % (node.number, style, label)
34 changes: 22 additions & 12 deletions control_flow/graph.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,11 @@
BB_EXIT = 13

# Has a conditional jump of some sort. This would be
# found in "if", and "while" constructs.
BB_JUMP_CONDITIONAL = 14
# found in "if" constructs.
BB_JUMP_FORWARD_IF_FALSE = 14
BB_JUMP_FORWARD_IF_TRUE = 15
BB_JUMP_BACKWARD_IF_FALSE = 16
BB_JUMP_BACKWARD_IF_TRUE = 17

# Jumps to what would be the fallthough.
# If there were optimization, this instruction would be removed.
Expand All @@ -78,17 +81,17 @@

# We mostly use it in drawing graphs to make
# sure the jump arrow points straight down.
BB_JUMP_TO_FALLTHROUGH = 15
BB_JUMP_TO_FALLTHROUGH = 18

# The beginning of the basic block is a join.
BB_JOIN_POINT = 16
BB_JOIN_POINT = 19

# Basic block ends in a return or an raise that is not inside
# a "try" block.
BB_RETURN = 17
BB_RETURN = 20

# Unreachable block
BB_DEAD_CODE = 17
BB_DEAD_CODE = 21

FLAG2NAME = {
BB_ENTRY: "entry",
Expand All @@ -102,7 +105,10 @@
BB_EXCEPT: "except",
BB_JOIN_POINT: "join block",
BB_JUMP_UNCONDITIONAL: "unconditional",
BB_JUMP_CONDITIONAL: "conditional jump",
BB_JUMP_BACKWARD_IF_FALSE: "jump backward if false",
BB_JUMP_BACKWARD_IF_TRUE: "jump backward if true",
BB_JUMP_FORWARD_IF_FALSE: "jump forward if false",
BB_JUMP_FORWARD_IF_TRUE: "jump forward if true",
BB_JUMP_TO_FALLTHROUGH: "jump to fallthough",
BB_FOR: "for",
BB_FINALLY: "finally",
Expand Down Expand Up @@ -165,7 +171,7 @@ def format_flags_with_width(flags, max_width, newline):
pass
pass

return result + (" " * remain)
return result + "}" + (" " * remain)


class Node:
Expand Down Expand Up @@ -268,10 +274,14 @@ def is_conditional_jump(self) -> bool:
"""Return True is edge is attached to a conditional jump
instruction at its source.
"""
return (
BB_JUMP_CONDITIONAL in self.source.flags
and self.dest.bb.start_offset in self.source.bb.jump_offsets
)
return {
BB_JUMP_FORWARD_IF_TRUE,
BB_JUMP_FORWARD_IF_FALSE,
BB_JUMP_BACKWARD_IF_TRUE,
BB_JUMP_BACKWARD_IF_FALSE,
}.intersection(
self.source.flags
) and self.dest.bb.start_offset in self.source.bb.jump_offsets


class DiGraph:
Expand Down

0 comments on commit 8f072d6

Please sign in to comment.