PageRenderTime 46ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/pypy/translator/unsimplify.py

https://bitbucket.org/pypy/pypy/
Python | 180 lines | 122 code | 8 blank | 50 comment | 20 complexity | 01c05e76fa0c54270600c239cb6716ed MD5 | raw file
Possible License(s): AGPL-3.0, BSD-3-Clause, Apache-2.0
  1. from pypy.objspace.flow.model import *
  2. def copyvar(annotator, v):
  3. """Make a copy of the Variable v, preserving annotations and concretetype."""
  4. assert isinstance(v, Variable)
  5. newvar = Variable(v)
  6. if annotator is not None and v in annotator.bindings:
  7. annotator.transfer_binding(newvar, v)
  8. if hasattr(v, 'concretetype'):
  9. newvar.concretetype = v.concretetype
  10. return newvar
  11. def varoftype(concretetype, name=None):
  12. var = Variable(name)
  13. var.concretetype = concretetype
  14. return var
  15. def insert_empty_block(annotator, link, newops=[]):
  16. """Insert and return a new block along the given link."""
  17. vars = {}
  18. for v in link.args:
  19. if isinstance(v, Variable):
  20. vars[v] = True
  21. for op in newops:
  22. for v in op.args:
  23. if isinstance(v, Variable):
  24. vars.setdefault(v, True)
  25. vars[op.result] = False
  26. vars = [v for v, keep in vars.items() if keep]
  27. mapping = {}
  28. for v in vars:
  29. mapping[v] = copyvar(annotator, v)
  30. newblock = Block(vars)
  31. newblock.operations.extend(newops)
  32. newblock.closeblock(Link(link.args, link.target))
  33. newblock.renamevariables(mapping)
  34. link.args[:] = vars
  35. link.target = newblock
  36. return newblock
  37. def insert_empty_startblock(annotator, graph):
  38. vars = [copyvar(annotator, v) for v in graph.startblock.inputargs]
  39. newblock = Block(vars)
  40. newblock.closeblock(Link(vars, graph.startblock))
  41. graph.startblock = newblock
  42. def starts_with_empty_block(graph):
  43. return (not graph.startblock.operations
  44. and graph.startblock.exitswitch is None
  45. and graph.startblock.exits[0].args == graph.getargs())
  46. def split_block(annotator, block, index, _forcelink=None):
  47. """return a link where prevblock is the block leading up but excluding the
  48. index'th operation and target is a new block with the neccessary variables
  49. passed on.
  50. """
  51. assert 0 <= index <= len(block.operations)
  52. if block.exitswitch == c_last_exception:
  53. assert index < len(block.operations)
  54. #varmap is the map between names in the new and the old block
  55. #but only for variables that are produced in the old block and needed in
  56. #the new one
  57. varmap = {}
  58. vars_produced_in_new_block = {}
  59. def get_new_name(var):
  60. if var is None:
  61. return None
  62. if isinstance(var, Constant):
  63. return var
  64. if var in vars_produced_in_new_block:
  65. return var
  66. if var not in varmap:
  67. varmap[var] = copyvar(annotator, var)
  68. return varmap[var]
  69. moved_operations = block.operations[index:]
  70. new_moved_ops = []
  71. for op in moved_operations:
  72. newop = SpaceOperation(op.opname,
  73. [get_new_name(arg) for arg in op.args],
  74. op.result)
  75. new_moved_ops.append(newop)
  76. vars_produced_in_new_block[op.result] = True
  77. moved_operations = new_moved_ops
  78. links = block.exits
  79. block.exits = None
  80. for link in links:
  81. for i, arg in enumerate(link.args):
  82. #last_exception and last_exc_value are considered to be created
  83. #when the link is entered
  84. if link.args[i] not in [link.last_exception, link.last_exc_value]:
  85. link.args[i] = get_new_name(link.args[i])
  86. exitswitch = get_new_name(block.exitswitch)
  87. #the new block gets all the attributes relevant to outgoing links
  88. #from block the old block
  89. if _forcelink is not None:
  90. assert index == 0
  91. linkargs = list(_forcelink)
  92. for v in varmap:
  93. if v not in linkargs:
  94. # 'v' was not specified by _forcelink, but we found out that
  95. # we need it! Hack: if it is 'concretetype is lltype.Void'
  96. # then it's ok to recreate its value in the target block.
  97. # If not, then we have a problem :-)
  98. from pypy.rpython.lltypesystem import lltype
  99. assert v.concretetype is lltype.Void
  100. c = Constant(None, lltype.Void)
  101. w = varmap[v]
  102. newop = SpaceOperation('same_as', [c], w)
  103. i = 0
  104. while i < len(moved_operations):
  105. if w in moved_operations[i].args:
  106. break
  107. i += 1
  108. moved_operations.insert(i, newop)
  109. else:
  110. linkargs = varmap.keys()
  111. newblock = Block([get_new_name(v) for v in linkargs])
  112. newblock.operations = moved_operations
  113. newblock.recloseblock(*links)
  114. newblock.exitswitch = exitswitch
  115. link = Link(linkargs, newblock)
  116. block.operations = block.operations[:index]
  117. block.recloseblock(link)
  118. block.exitswitch = None
  119. return link
  120. def split_block_at_start(annotator, block):
  121. # split before the first op, preserve order and inputargs
  122. # in the second block!
  123. return split_block(annotator, block, 0, _forcelink=block.inputargs)
  124. def call_initial_function(translator, initial_func, annhelper=None):
  125. """Before the program starts, call 'initial_func()'."""
  126. from pypy.annotation import model as annmodel
  127. from pypy.rpython.lltypesystem import lltype
  128. from pypy.rpython.annlowlevel import MixLevelHelperAnnotator
  129. own_annhelper = (annhelper is None)
  130. if own_annhelper:
  131. annhelper = MixLevelHelperAnnotator(translator.rtyper)
  132. c_initial_func = annhelper.constfunc(initial_func, [], annmodel.s_None)
  133. if own_annhelper:
  134. annhelper.finish()
  135. entry_point = translator.entry_point_graph
  136. args = [copyvar(translator.annotator, v) for v in entry_point.getargs()]
  137. extrablock = Block(args)
  138. v_none = varoftype(lltype.Void)
  139. newop = SpaceOperation('direct_call', [c_initial_func], v_none)
  140. extrablock.operations = [newop]
  141. extrablock.closeblock(Link(args, entry_point.startblock))
  142. entry_point.startblock = extrablock
  143. checkgraph(entry_point)
  144. def call_final_function(translator, final_func, annhelper=None):
  145. """When the program finishes normally, call 'final_func()'."""
  146. from pypy.annotation import model as annmodel
  147. from pypy.rpython.lltypesystem import lltype
  148. from pypy.rpython.annlowlevel import MixLevelHelperAnnotator
  149. own_annhelper = (annhelper is None)
  150. if own_annhelper:
  151. annhelper = MixLevelHelperAnnotator(translator.rtyper)
  152. c_final_func = annhelper.constfunc(final_func, [], annmodel.s_None)
  153. if own_annhelper:
  154. annhelper.finish()
  155. entry_point = translator.entry_point_graph
  156. v = copyvar(translator.annotator, entry_point.getreturnvar())
  157. extrablock = Block([v])
  158. v_none = varoftype(lltype.Void)
  159. newop = SpaceOperation('direct_call', [c_final_func], v_none)
  160. extrablock.operations = [newop]
  161. extrablock.closeblock(Link([v], entry_point.returnblock))
  162. for block in entry_point.iterblocks():
  163. if block is not extrablock:
  164. for link in block.exits:
  165. if link.target is entry_point.returnblock:
  166. link.target = extrablock
  167. checkgraph(entry_point)