Skip to content

Commit 43d8275

Browse files
committed
cpychecker: Eliminate absinterp.Location in favor of a stmtgraph.StmtNode
Previously in cpychecker, we tracked the PC location of a state using the absinterp.Location class, which tracked a BB and an index into the stmt array. This commit eliminates that class in favor of using a gccutils.graph.stmtgraph, where each gimple statement is a stmtgraph.StmtNode, simplifying locations to being nodes within a directed graph. The logic for ignoring exception-handling edges can be reduced to simply not building those edges when initially creating the StmtGraph. We add an ordering to stmtgraph.StmtEdge, to ensure deterministic orderings. Motivation: (A) absinterp.Location vs gcc.Location was confusing (B) we may be able to solve: https://fedorahosted.org/gcc-python-plugin/ticket/58 by doing some manipulation of the stmtgraph, undoing the sharing of return statements, so that each "return" in the source code gets its own node, and updating the locations accordingly. (Alternatively, we could just use the location of the last stmt in the trace that had a non-None location)
1 parent e3bedcd commit 43d8275

File tree

4 files changed

+125
-145
lines changed

4 files changed

+125
-145
lines changed

gccutils/graph/stmtgraph.py

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ class StmtGraph(Graph):
3434
'__lastnode',
3535
'supernode_for_stmtnode')
3636

37-
def __init__(self, fun, split_phi_nodes):
37+
def __init__(self, fun, split_phi_nodes, omit_complex_edges=False):
3838
"""
3939
fun : the underlying gcc.Function
4040
@@ -65,7 +65,7 @@ def __init__(self, fun, split_phi_nodes):
6565
self.__lastnode = None
6666

6767
def add_stmt(stmt):
68-
nextnode = self.add_node(StmtNode(fun, stmt))
68+
nextnode = self.add_node(StmtNode(fun, bb, stmt))
6969
self.node_for_stmt[stmt] = nextnode
7070
if self.__lastnode:
7171
self.add_edge(self.__lastnode, nextnode, None)
@@ -96,7 +96,7 @@ def add_stmt(stmt):
9696
# returning void that contain multiple "return;"
9797
# statements:
9898
cls = StmtNode
99-
node = self.add_node(cls(fun, None))
99+
node = self.add_node(cls(fun, bb, None))
100100
self.entry_of_bb[bb] = node
101101
self.exit_of_bb[bb] = node
102102
if bb == fun.cfg.entry:
@@ -110,6 +110,13 @@ def add_stmt(stmt):
110110
# 2nd pass: wire up the cross-BB edges:
111111
for bb in basic_blocks:
112112
for edge in bb.succs:
113+
114+
# If requested, omit "complex" edges e.g. due to
115+
# exception-handling:
116+
if omit_complex_edges:
117+
if edge.complex:
118+
continue
119+
113120
last_node = self.exit_of_bb[bb]
114121
if split_phi_nodes:
115122
# add SplitPhiNode instances at the end of each edge
@@ -150,7 +157,7 @@ def add_stmt(stmt):
150157
edge.caselabelexprs = frozenset(caselabelexprs)
151158

152159
def _make_edge(self, srcnode, dstnode, edge):
153-
return StmtEdge(srcnode, dstnode, edge)
160+
return StmtEdge(srcnode, dstnode, edge, len(self.edges))
154161

155162
def get_entry_nodes(self):
156163
return [self.entry]
@@ -161,11 +168,12 @@ def get_node_for_labeldecl(self, labeldecl):
161168
return self.entry_of_bb[bb]
162169

163170
class StmtNode(Node):
164-
__slots__ = ('fun', 'stmt')
171+
__slots__ = ('fun', 'bb', 'stmt')
165172

166-
def __init__(self, fun, stmt):
173+
def __init__(self, fun, bb, stmt):
167174
Node.__init__(self)
168175
self.fun = fun
176+
self.bb = bb
169177
self.stmt = stmt # can be None for empty BBs
170178

171179
def __str__(self):
@@ -203,6 +211,9 @@ def to_dot_html(self, ctxt):
203211
else:
204212
return Text(str(self))
205213

214+
def __eq__(self, other):
215+
return self.stmt == other.stmt
216+
206217
class EntryNode(StmtNode):
207218
__slots__ = ()
208219

@@ -268,7 +279,7 @@ class SplitPhiNode(StmtNode):
268279
__slots__ = ('inneredge', 'rhs')
269280

270281
def __init__(self, fun, stmt, inneredge):
271-
StmtNode.__init__(self, fun, stmt)
282+
StmtNode.__init__(self, fun, None, stmt)
272283
self.inneredge = inneredge
273284

274285
# Lookup the RHS for this edge:
@@ -288,18 +299,24 @@ def __str__(self):
288299
def __repr__(self):
289300
return 'SplitPhiNode(%r, %r)' % (self.stmt, self.inneredge)
290301

302+
def __eq__(self, other):
303+
return isinstance(other, SplitPhiNode) and self.inneredge == other.inneredge
304+
291305
class StmtEdge(Edge):
292-
__slots__ = ('cfgedge', 'caselabelexprs')
306+
__slots__ = ('cfgedge', 'sortidx', 'caselabelexprs')
293307

294-
def __init__(self, srcnode, dstnode, cfgedge):
308+
def __init__(self, srcnode, dstnode, cfgedge, sortidx):
295309
Edge.__init__(self, srcnode, dstnode)
296310
self.cfgedge = cfgedge # will be None within a BB
311+
self.sortidx = sortidx
297312

298313
# For use in handling switch statements:
299314
# the set of gcc.CaseLabelExpr for this edge
300315
self.caselabelexprs = frozenset()
301316

317+
302318
def to_dot_label(self, ctx):
319+
return str(self.sortidx)
303320
if self.cfgedge:
304321
if self.cfgedge.true_value:
305322
return 'true'
@@ -331,3 +348,6 @@ def false_value(self):
331348
if self.cfgedge:
332349
return self.cfgedge.false_value
333350

351+
def __cmp__(self, other):
352+
return cmp(self.sortidx, other.sortidx)
353+

0 commit comments

Comments
 (0)