[Python-checkins] CVS: python/dist/src/Tools/compiler/compiler pycodegen.py,1.35,1.36 pyassem.py,1.18,1.19
Jeremy Hylton
jhylton@users.sourceforge.net
Thu, 12 Apr 2001 13:21:41 -0700
Update of /cvsroot/python/python/dist/src/Tools/compiler/compiler
In directory usw-pr-cvs1:/tmp/cvs-serv7276/compiler
Modified Files:
pycodegen.py pyassem.py
Log Message:
pyassem.py:
Fix annoying bugs in flow graph layout code. In some cases the
implicit control transfers weren't honored. In other cases,
JUMP_FORWARD instructions jumped backwards.
Remove unused arg from nextBlock().
pycodegen.py
Add optional force kwarg to set_lineno() that will emit a
SET_LINENO even if it is the same as the previous lineno.
Use explicit LOAD_FAST and STORE_FAST to access list comp implicit
variables. (The symbol table doesn't know about them.)
Index: pycodegen.py
===================================================================
RCS file: /cvsroot/python/python/dist/src/Tools/compiler/compiler/pycodegen.py,v
retrieving revision 1.35
retrieving revision 1.36
diff -C2 -r1.35 -r1.36
*** pycodegen.py 2001/04/12 17:33:34 1.35
--- pycodegen.py 2001/04/12 20:21:39 1.36
***************
*** 194,198 ****
self.emit(prefix + '_GLOBAL', name)
! def set_lineno(self, node):
"""Emit SET_LINENO if node has lineno attribute and it is
different than the last lineno emitted.
--- 194,198 ----
self.emit(prefix + '_GLOBAL', name)
! def set_lineno(self, node, force=0):
"""Emit SET_LINENO if node has lineno attribute and it is
different than the last lineno emitted.
***************
*** 206,210 ****
"""
lineno = getattr(node, 'lineno', None)
! if lineno is not None and lineno != self.last_lineno:
self.emit('SET_LINENO', lineno)
self.last_lineno = lineno
--- 206,211 ----
"""
lineno = getattr(node, 'lineno', None)
! if lineno is not None and (lineno != self.last_lineno
! or force):
self.emit('SET_LINENO', lineno)
self.last_lineno = lineno
***************
*** 414,420 ****
def visitListComp(self, node):
- # XXX would it be easier to transform the AST into the form it
- # would have if the list comp were expressed as a series of
- # for and if stmts and an explicit append?
self.set_lineno(node)
# setup list
--- 415,418 ----
***************
*** 424,431 ****
self.emit('DUP_TOP')
self.emit('LOAD_ATTR', 'append')
! self.storeName(append)
! l = len(node.quals)
stack = []
! for i, for_ in zip(range(l), node.quals):
start, anchor = self.visit(for_)
cont = None
--- 422,429 ----
self.emit('DUP_TOP')
self.emit('LOAD_ATTR', 'append')
! self.emit('STORE_FAST', append)
!
stack = []
! for i, for_ in zip(range(len(node.quals)), node.quals):
start, anchor = self.visit(for_)
cont = None
***************
*** 435,440 ****
self.visit(if_, cont)
stack.insert(0, (start, cont, anchor))
!
! self.loadName(append)
self.visit(node.expr)
self.emit('CALL_FUNCTION', 1)
--- 433,438 ----
self.visit(if_, cont)
stack.insert(0, (start, cont, anchor))
!
! self.emit('LOAD_FAST', append)
self.visit(node.expr)
self.emit('CALL_FUNCTION', 1)
***************
*** 450,459 ****
self.emit('JUMP_ABSOLUTE', start)
self.startBlock(anchor)
! self.delName(append)
self.__list_count = self.__list_count - 1
def visitListCompFor(self, node):
- self.set_lineno(node)
start = self.newBlock()
anchor = self.newBlock()
--- 448,456 ----
self.emit('JUMP_ABSOLUTE', start)
self.startBlock(anchor)
! self.emit('DELETE_FAST', append)
self.__list_count = self.__list_count - 1
def visitListCompFor(self, node):
start = self.newBlock()
anchor = self.newBlock()
***************
*** 469,473 ****
def visitListCompIf(self, node, branch):
! self.set_lineno(node)
self.visit(node.test)
self.emit('JUMP_IF_FALSE', branch)
--- 466,470 ----
def visitListCompIf(self, node, branch):
! self.set_lineno(node, force=1)
self.visit(node.test)
self.emit('JUMP_IF_FALSE', branch)
***************
*** 673,676 ****
--- 670,674 ----
def _visitAssSequence(self, node, op='UNPACK_SEQUENCE'):
+ ## print >> sys.stderr, "AssSequence", op, findOp(node), node
if findOp(node) != 'OP_DELETE':
self.emit(op, len(node.nodes))
Index: pyassem.py
===================================================================
RCS file: /cvsroot/python/python/dist/src/Tools/compiler/compiler/pyassem.py,v
retrieving revision 1.18
retrieving revision 1.19
diff -C2 -r1.18 -r1.19
*** pyassem.py 2001/04/12 17:33:34 1.18
--- pyassem.py 2001/04/12 20:21:39 1.19
***************
*** 28,36 ****
if self.current:
print "end", repr(self.current)
print " ", self.current.get_children()
print repr(block)
self.current = block
! def nextBlock(self, block=None, force=0):
# XXX think we need to specify when there is implicit transfer
# from one block to the next. might be better to represent this
--- 28,37 ----
if self.current:
print "end", repr(self.current)
+ print " next", self.current.next
print " ", self.current.get_children()
print repr(block)
self.current = block
! def nextBlock(self, block=None):
# XXX think we need to specify when there is implicit transfer
# from one block to the next. might be better to represent this
***************
*** 96,99 ****
--- 97,101 ----
order = dfs_postorder(self.entry, {})
order.reverse()
+ self.fixupOrder(order, self.exit)
# hack alert
if not self.exit in order:
***************
*** 102,105 ****
--- 104,204 ----
return order
+ def fixupOrder(self, blocks, default_next):
+ """Fixup bad order introduced by DFS."""
+
+ # XXX This is a total mess. There must be a better way to get
+ # the code blocks in the right order.
+
+ self.fixupOrderHonorNext(blocks, default_next)
+ self.fixupOrderForward(blocks, default_next)
+
+ def fixupOrderHonorNext(self, blocks, default_next):
+ """Fix one problem with DFS.
+
+ The DFS uses child block, but doesn't know about the special
+ "next" block. As a result, the DFS can order blocks so that a
+ block isn't next to the right block for implicit control
+ transfers.
+ """
+ index = {}
+ for i in range(len(blocks)):
+ index[blocks[i]] = i
+
+ for i in range(0, len(blocks) - 1):
+ b = blocks[i]
+ n = blocks[i + 1]
+ if not b.next or b.next[0] == default_next or b.next[0] == n:
+ continue
+ # The blocks are in the wrong order. Find the chain of
+ # blocks to insert where they belong.
+ cur = b
+ chain = []
+ elt = cur
+ while elt.next and elt.next[0] != default_next:
+ chain.append(elt.next[0])
+ elt = elt.next[0]
+ # Now remove the blocks in the chain from the current
+ # block list, so that they can be re-inserted.
+ l = []
+ for b in chain:
+ assert index[b] > i
+ l.append((index[b], b))
+ l.sort()
+ l.reverse()
+ for j, b in l:
+ del blocks[index[b]]
+ # Insert the chain in the proper location
+ blocks[i:i + 1] = [cur] + chain
+ # Finally, re-compute the block indexes
+ for i in range(len(blocks)):
+ index[blocks[i]] = i
+
+ def fixupOrderForward(self, blocks, default_next):
+ """Make sure all JUMP_FORWARDs jump forward"""
+ index = {}
+ chains = []
+ cur = []
+ for b in blocks:
+ index[b] = len(chains)
+ cur.append(b)
+ if b.next and b.next[0] == default_next:
+ chains.append(cur)
+ cur = []
+ chains.append(cur)
+
+ while 1:
+ constraints = []
+
+ for i in range(len(chains)):
+ l = chains[i]
+ for b in l:
+ for c in b.get_children():
+ if index[c] < i:
+ forward_p = 0
+ for inst in b.insts:
+ if inst[0] == 'JUMP_FORWARD':
+ if inst[1] == c:
+ forward_p = 1
+ if not forward_p:
+ continue
+ constraints.append((index[c], i))
+
+ if not constraints:
+ break
+
+ # XXX just do one for now
+ # do swaps to get things in the right order
+ goes_before, a_chain = constraints[0]
+ assert a_chain > goes_before
+ c = chains[a_chain]
+ chains.remove(c)
+ chains.insert(goes_before, c)
+
+
+ del blocks[:]
+ for c in chains:
+ for b in c:
+ blocks.append(b)
+
def getBlocks(self):
return self.blocks.elements()