PageRenderTime 49ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/pypy/jit/codewriter/effectinfo.py

https://bitbucket.org/pypy/pypy/
Python | 299 lines | 249 code | 33 blank | 17 comment | 35 complexity | c6e3d58c6027286c478defc2573dde2b MD5 | raw file
Possible License(s): AGPL-3.0, BSD-3-Clause, Apache-2.0
  1. from pypy.jit.metainterp.typesystem import deref, fieldType, arrayItem
  2. from pypy.rpython.lltypesystem.rclass import OBJECT
  3. from pypy.rpython.lltypesystem import lltype
  4. from pypy.rpython.ootypesystem import ootype
  5. from pypy.translator.backendopt.graphanalyze import BoolGraphAnalyzer
  6. class EffectInfo(object):
  7. _cache = {}
  8. # the 'extraeffect' field is one of the following values:
  9. EF_ELIDABLE_CANNOT_RAISE = 0 #elidable function (and cannot raise)
  10. EF_LOOPINVARIANT = 1 #special: call it only once per loop
  11. EF_CANNOT_RAISE = 2 #a function which cannot raise
  12. EF_ELIDABLE_CAN_RAISE = 3 #elidable function (but can raise)
  13. EF_CAN_RAISE = 4 #normal function (can raise)
  14. EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE = 5 #can raise and force virtualizables
  15. EF_RANDOM_EFFECTS = 6 #can do whatever
  16. # the 'oopspecindex' field is one of the following values:
  17. OS_NONE = 0 # normal case, no oopspec
  18. OS_ARRAYCOPY = 1 # "list.ll_arraycopy"
  19. OS_STR2UNICODE = 2 # "str.str2unicode"
  20. #
  21. OS_STR_CONCAT = 22 # "stroruni.concat"
  22. OS_STR_SLICE = 23 # "stroruni.slice"
  23. OS_STR_EQUAL = 24 # "stroruni.equal"
  24. OS_STREQ_SLICE_CHECKNULL = 25 # s2!=NULL and s1[x:x+length]==s2
  25. OS_STREQ_SLICE_NONNULL = 26 # s1[x:x+length]==s2 (assert s2!=NULL)
  26. OS_STREQ_SLICE_CHAR = 27 # s1[x:x+length]==char
  27. OS_STREQ_NONNULL = 28 # s1 == s2 (assert s1!=NULL,s2!=NULL)
  28. OS_STREQ_NONNULL_CHAR = 29 # s1 == char (assert s1!=NULL)
  29. OS_STREQ_CHECKNULL_CHAR = 30 # s1!=NULL and s1==char
  30. OS_STREQ_LENGTHOK = 31 # s1 == s2 (assert len(s1)==len(s2))
  31. #
  32. OS_UNI_CONCAT = 42 #
  33. OS_UNI_SLICE = 43 #
  34. OS_UNI_EQUAL = 44 #
  35. OS_UNIEQ_SLICE_CHECKNULL = 45 #
  36. OS_UNIEQ_SLICE_NONNULL = 46 #
  37. OS_UNIEQ_SLICE_CHAR = 47 #
  38. OS_UNIEQ_NONNULL = 48 # the same for unicode
  39. OS_UNIEQ_NONNULL_CHAR = 49 # (must be the same amount as for
  40. OS_UNIEQ_CHECKNULL_CHAR = 50 # STR, in the same order)
  41. OS_UNIEQ_LENGTHOK = 51 #
  42. _OS_offset_uni = OS_UNI_CONCAT - OS_STR_CONCAT
  43. #
  44. OS_LIBFFI_PREPARE = 60
  45. OS_LIBFFI_PUSH_ARG = 61
  46. OS_LIBFFI_CALL = 62
  47. OS_LIBFFI_GETARRAYITEM = 63
  48. OS_LIBFFI_SETARRAYITEM = 64
  49. #
  50. OS_LLONG_INVERT = 69
  51. OS_LLONG_ADD = 70
  52. OS_LLONG_SUB = 71
  53. OS_LLONG_MUL = 72
  54. OS_LLONG_LT = 73
  55. OS_LLONG_LE = 74
  56. OS_LLONG_EQ = 75
  57. OS_LLONG_NE = 76
  58. OS_LLONG_GT = 77
  59. OS_LLONG_GE = 78
  60. OS_LLONG_AND = 79
  61. OS_LLONG_OR = 80
  62. OS_LLONG_LSHIFT = 81
  63. OS_LLONG_RSHIFT = 82
  64. OS_LLONG_XOR = 83
  65. OS_LLONG_FROM_INT = 84
  66. OS_LLONG_TO_INT = 85
  67. OS_LLONG_FROM_FLOAT = 86
  68. OS_LLONG_TO_FLOAT = 87
  69. OS_LLONG_ULT = 88
  70. OS_LLONG_ULE = 89
  71. OS_LLONG_UGT = 90
  72. OS_LLONG_UGE = 91
  73. OS_LLONG_URSHIFT = 92
  74. OS_LLONG_FROM_UINT = 93
  75. OS_LLONG_U_TO_FLOAT = 94
  76. #
  77. OS_MATH_SQRT = 100
  78. # for debugging:
  79. _OS_CANRAISE = set([OS_NONE, OS_STR2UNICODE, OS_LIBFFI_CALL])
  80. def __new__(cls, readonly_descrs_fields, readonly_descrs_arrays,
  81. write_descrs_fields, write_descrs_arrays,
  82. extraeffect=EF_CAN_RAISE,
  83. oopspecindex=OS_NONE,
  84. can_invalidate=False):
  85. key = (frozenset_or_none(readonly_descrs_fields),
  86. frozenset_or_none(readonly_descrs_arrays),
  87. frozenset_or_none(write_descrs_fields),
  88. frozenset_or_none(write_descrs_arrays),
  89. extraeffect,
  90. oopspecindex,
  91. can_invalidate)
  92. if key in cls._cache:
  93. return cls._cache[key]
  94. if extraeffect == EffectInfo.EF_RANDOM_EFFECTS:
  95. assert readonly_descrs_fields is None
  96. assert readonly_descrs_arrays is None
  97. assert write_descrs_fields is None
  98. assert write_descrs_arrays is None
  99. else:
  100. assert readonly_descrs_fields is not None
  101. assert readonly_descrs_arrays is not None
  102. assert write_descrs_fields is not None
  103. assert write_descrs_arrays is not None
  104. result = object.__new__(cls)
  105. result.readonly_descrs_fields = readonly_descrs_fields
  106. result.readonly_descrs_arrays = readonly_descrs_arrays
  107. if extraeffect == EffectInfo.EF_LOOPINVARIANT or \
  108. extraeffect == EffectInfo.EF_ELIDABLE_CANNOT_RAISE or \
  109. extraeffect == EffectInfo.EF_ELIDABLE_CAN_RAISE:
  110. result.write_descrs_fields = []
  111. result.write_descrs_arrays = []
  112. else:
  113. result.write_descrs_fields = write_descrs_fields
  114. result.write_descrs_arrays = write_descrs_arrays
  115. result.extraeffect = extraeffect
  116. result.can_invalidate = can_invalidate
  117. result.oopspecindex = oopspecindex
  118. if result.check_can_raise():
  119. assert oopspecindex in cls._OS_CANRAISE
  120. cls._cache[key] = result
  121. return result
  122. def check_can_raise(self):
  123. return self.extraeffect > self.EF_CANNOT_RAISE
  124. def check_can_invalidate(self):
  125. return self.can_invalidate
  126. def check_is_elidable(self):
  127. return (self.extraeffect == self.EF_ELIDABLE_CAN_RAISE or
  128. self.extraeffect == self.EF_ELIDABLE_CANNOT_RAISE)
  129. def check_forces_virtual_or_virtualizable(self):
  130. return self.extraeffect >= self.EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE
  131. def has_random_effects(self):
  132. return self.extraeffect >= self.EF_RANDOM_EFFECTS
  133. def frozenset_or_none(x):
  134. if x is None:
  135. return None
  136. return frozenset(x)
  137. EffectInfo.MOST_GENERAL = EffectInfo(None, None, None, None,
  138. EffectInfo.EF_RANDOM_EFFECTS,
  139. can_invalidate=True)
  140. def effectinfo_from_writeanalyze(effects, cpu,
  141. extraeffect=EffectInfo.EF_CAN_RAISE,
  142. oopspecindex=EffectInfo.OS_NONE,
  143. can_invalidate=False):
  144. from pypy.translator.backendopt.writeanalyze import top_set
  145. if effects is top_set or extraeffect == EffectInfo.EF_RANDOM_EFFECTS:
  146. readonly_descrs_fields = None
  147. readonly_descrs_arrays = None
  148. write_descrs_fields = None
  149. write_descrs_arrays = None
  150. extraeffect = EffectInfo.EF_RANDOM_EFFECTS
  151. else:
  152. readonly_descrs_fields = []
  153. readonly_descrs_arrays = []
  154. write_descrs_fields = []
  155. write_descrs_arrays = []
  156. def add_struct(descrs_fields, (_, T, fieldname)):
  157. T = deref(T)
  158. if consider_struct(T, fieldname):
  159. descr = cpu.fielddescrof(T, fieldname)
  160. descrs_fields.append(descr)
  161. def add_array(descrs_arrays, (_, T)):
  162. ARRAY = deref(T)
  163. if consider_array(ARRAY):
  164. descr = cpu.arraydescrof(ARRAY)
  165. descrs_arrays.append(descr)
  166. for tup in effects:
  167. if tup[0] == "struct":
  168. add_struct(write_descrs_fields, tup)
  169. elif tup[0] == "readstruct":
  170. tupw = ("struct",) + tup[1:]
  171. if tupw not in effects:
  172. add_struct(readonly_descrs_fields, tup)
  173. elif tup[0] == "array":
  174. add_array(write_descrs_arrays, tup)
  175. elif tup[0] == "readarray":
  176. tupw = ("array",) + tup[1:]
  177. if tupw not in effects:
  178. add_array(readonly_descrs_arrays, tup)
  179. else:
  180. assert 0
  181. #
  182. return EffectInfo(readonly_descrs_fields,
  183. readonly_descrs_arrays,
  184. write_descrs_fields,
  185. write_descrs_arrays,
  186. extraeffect,
  187. oopspecindex,
  188. can_invalidate)
  189. def consider_struct(TYPE, fieldname):
  190. if fieldType(TYPE, fieldname) is lltype.Void:
  191. return False
  192. if isinstance(TYPE, ootype.OOType):
  193. return True
  194. if not isinstance(TYPE, lltype.GcStruct): # can be a non-GC-struct
  195. return False
  196. if fieldname == "typeptr" and TYPE is OBJECT:
  197. # filter out the typeptr, because
  198. # a) it is optimized in different ways
  199. # b) it might not be there in C if removetypeptr is specified
  200. return False
  201. return True
  202. def consider_array(ARRAY):
  203. if arrayItem(ARRAY) is lltype.Void:
  204. return False
  205. if isinstance(ARRAY, ootype.Array):
  206. return True
  207. if not isinstance(ARRAY, lltype.GcArray): # can be a non-GC-array
  208. return False
  209. return True
  210. # ____________________________________________________________
  211. class VirtualizableAnalyzer(BoolGraphAnalyzer):
  212. def analyze_simple_operation(self, op, graphinfo):
  213. return op.opname in ('jit_force_virtualizable',
  214. 'jit_force_virtual')
  215. class QuasiImmutAnalyzer(BoolGraphAnalyzer):
  216. def analyze_simple_operation(self, op, graphinfo):
  217. return op.opname == 'jit_force_quasi_immutable'
  218. class RandomEffectsAnalyzer(BoolGraphAnalyzer):
  219. def analyze_external_call(self, op, seen=None):
  220. try:
  221. funcobj = op.args[0].value._obj
  222. if funcobj.random_effects_on_gcobjs:
  223. return True
  224. except (AttributeError, lltype.DelayedPointer):
  225. return True # better safe than sorry
  226. return super(RandomEffectsAnalyzer, self).analyze_external_call(
  227. op, seen)
  228. def analyze_simple_operation(self, op, graphinfo):
  229. return False
  230. # ____________________________________________________________
  231. class CallInfoCollection(object):
  232. def __init__(self):
  233. # {oopspecindex: (calldescr, func_as_int)}
  234. self._callinfo_for_oopspec = {}
  235. def _freeze_(self):
  236. return True
  237. def add(self, oopspecindex, calldescr, func_as_int):
  238. self._callinfo_for_oopspec[oopspecindex] = calldescr, func_as_int
  239. def has_oopspec(self, oopspecindex):
  240. return oopspecindex in self._callinfo_for_oopspec
  241. def all_function_addresses_as_int(self):
  242. return [func for (_, func) in self._callinfo_for_oopspec.values()]
  243. def callinfo_for_oopspec(self, oopspecindex):
  244. """A function that returns the calldescr and the function
  245. address (as an int) of one of the OS_XYZ functions defined above.
  246. Don't use this if there might be several implementations of the same
  247. OS_XYZ specialized by type, e.g. OS_ARRAYCOPY."""
  248. try:
  249. return self._callinfo_for_oopspec[oopspecindex]
  250. except KeyError:
  251. return (None, 0)
  252. def _funcptr_for_oopspec_memo(self, oopspecindex):
  253. from pypy.jit.codewriter import heaptracker
  254. _, func_as_int = self.callinfo_for_oopspec(oopspecindex)
  255. funcadr = heaptracker.int2adr(func_as_int)
  256. return funcadr.ptr
  257. _funcptr_for_oopspec_memo._annspecialcase_ = 'specialize:memo'
  258. def funcptr_for_oopspec(self, oopspecindex):
  259. """A memo function that returns a pointer to the function described
  260. by OS_XYZ (as a real low-level function pointer)."""
  261. funcptr = self._funcptr_for_oopspec_memo(oopspecindex)
  262. assert funcptr
  263. return funcptr
  264. funcptr_for_oopspec._annspecialcase_ = 'specialize:arg(1)'