/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

  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)'