[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()