intrinsics.py 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279
  1. import jit
  2. import tree_ir
  3. import time
  4. BINARY_INTRINSICS = {
  5. 'value_eq' : '==',
  6. 'value_neq' : '!=',
  7. 'bool_and' : 'and',
  8. 'bool_or' : 'or',
  9. 'integer_addition' : '+',
  10. 'integer_subtraction' : '-',
  11. 'integer_multiplication' : '*',
  12. 'integer_division' : '/',
  13. 'integer_gt' : '>',
  14. 'integer_gte' : '>=',
  15. 'integer_lt' : '<',
  16. 'integer_lte' : '<=',
  17. 'float_addition' : '+',
  18. 'float_subtraction' : '-',
  19. 'float_multiplication' : '*',
  20. 'float_division' : '/',
  21. 'float_gt' : '>',
  22. 'float_gte' : '>=',
  23. 'float_lt' : '<',
  24. 'float_lte' : '<='
  25. }
  26. UNARY_INTRINSICS = {
  27. 'bool_not' : 'not',
  28. 'integer_neg' : '-',
  29. 'float_neg' : '-'
  30. }
  31. CAST_INTRINSICS = {
  32. 'cast_i2f' : float,
  33. 'cast_i2s' : str,
  34. 'cast_i2b' : bool,
  35. 'cast_f2i' : int,
  36. 'cast_f2s' : str,
  37. 'cast_f2b' : bool,
  38. 'cast_s2i' : int,
  39. 'cast_s2f' : float,
  40. 'cast_s2b' : bool,
  41. 'cast_b2i' : int,
  42. 'cast_b2f' : float,
  43. 'cast_b2s' : str
  44. }
  45. def create_get_length(expression):
  46. """Creates an expression that evaluates the given expression, and then
  47. computes the length of its result."""
  48. return tree_ir.CallInstruction(
  49. tree_ir.LoadGlobalInstruction('len'),
  50. [expression])
  51. # Don't compain about the variable names, pylint. It's important that we
  52. # get them right.
  53. # pylint: disable=I0011,C0103
  54. def __set_add(a, b):
  55. tmp = tree_ir.StoreLocalInstruction(None, a)
  56. return tree_ir.create_block(
  57. tmp,
  58. tree_ir.CreateEdgeInstruction(tmp.create_load(), b),
  59. tmp.create_load())
  60. def __dict_add(a, b, c):
  61. a_tmp = tree_ir.StoreLocalInstruction(None, a)
  62. b_tmp = tree_ir.StoreLocalInstruction(None, b)
  63. return tree_ir.create_block(
  64. a_tmp,
  65. b_tmp,
  66. tree_ir.CreateEdgeInstruction(
  67. tree_ir.CreateEdgeInstruction(a_tmp.create_load(), c),
  68. b_tmp.create_load()),
  69. a_tmp.create_load())
  70. def __list_read(a, b):
  71. # The statements in this function generate the following code:
  72. #
  73. # a_tmp = a # To make sure a is evaluated before b.
  74. # b_value, = yield [("RV", [b])]
  75. # result, = yield [("RD", [a_tmp, b_value])]
  76. # if result is None:
  77. # raise Exception("List read out of bounds: %s" % b_value)
  78. # result
  79. a_tmp = tree_ir.StoreLocalInstruction(None, a)
  80. b_val = tree_ir.StoreLocalInstruction(
  81. None,
  82. tree_ir.ReadValueInstruction(b))
  83. result = tree_ir.StoreLocalInstruction(
  84. None,
  85. tree_ir.ReadDictionaryValueInstruction(
  86. a_tmp.create_load(), b_val.create_load()))
  87. return tree_ir.create_block(
  88. a_tmp,
  89. b_val,
  90. result,
  91. tree_ir.SelectInstruction(
  92. tree_ir.BinaryInstruction(
  93. result.create_load(),
  94. 'is',
  95. tree_ir.LiteralInstruction(None)),
  96. tree_ir.RaiseInstruction(
  97. tree_ir.CallInstruction(
  98. tree_ir.LoadGlobalInstruction('Exception'),
  99. [tree_ir.BinaryInstruction(
  100. tree_ir.LiteralInstruction('List read out of bounds: %s'),
  101. '%',
  102. b_val.create_load())])),
  103. tree_ir.NopInstruction()),
  104. result.create_load())
  105. def __list_append(a, b):
  106. # We want to generate code that is more or less equivalent to:
  107. #
  108. # a_tmp = a
  109. # b_tmp = b
  110. # a_outgoing, = yield [("RO", [a_tmp])]
  111. # _ = yield [("CD", [a_tmp, len(a_outgoing), b_tmp])]
  112. # a
  113. a_tmp = tree_ir.StoreLocalInstruction(None, a)
  114. b_tmp = tree_ir.StoreLocalInstruction(None, b)
  115. return tree_ir.create_block(
  116. a_tmp,
  117. tree_ir.CreateDictionaryEdgeInstruction(
  118. a_tmp.create_load(),
  119. create_get_length(
  120. tree_ir.ReadOutgoingEdgesInstruction(
  121. a_tmp.create_load())),
  122. b_tmp),
  123. a_tmp.create_load())
  124. MISC_INTRINSICS = {
  125. # Reference equality
  126. 'element_eq' :
  127. lambda a, b:
  128. tree_ir.CreateNodeWithValueInstruction(
  129. tree_ir.BinaryInstruction(a, '==', b)),
  130. 'element_neq' :
  131. lambda a, b:
  132. tree_ir.CreateNodeWithValueInstruction(
  133. tree_ir.BinaryInstruction(a, '!=', b)),
  134. # Strings
  135. 'string_get' :
  136. lambda a, b:
  137. tree_ir.CreateNodeWithValueInstruction(
  138. tree_ir.LoadIndexInstruction(
  139. tree_ir.ReadValueInstruction(a),
  140. tree_ir.ReadValueInstruction(b))),
  141. 'string_len' :
  142. lambda a:
  143. tree_ir.CreateNodeWithValueInstruction(
  144. tree_ir.CallInstruction(
  145. tree_ir.LoadGlobalInstruction('len'),
  146. [tree_ir.ReadValueInstruction(a)])),
  147. 'string_join' :
  148. lambda a, b:
  149. tree_ir.CreateNodeWithValueInstruction(
  150. tree_ir.BinaryInstruction(
  151. tree_ir.CallInstruction(
  152. tree_ir.LoadGlobalInstruction('str'),
  153. [tree_ir.ReadValueInstruction(a)]),
  154. '+',
  155. tree_ir.CallInstruction(
  156. tree_ir.LoadGlobalInstruction('str'),
  157. [tree_ir.ReadValueInstruction(b)]))),
  158. 'string_startswith' :
  159. lambda a, b:
  160. tree_ir.CreateNodeWithValueInstruction(
  161. tree_ir.CallInstruction(
  162. tree_ir.LoadMemberInstruction(
  163. tree_ir.ReadValueInstruction(a),
  164. 'startswith'),
  165. [tree_ir.ReadValueInstruction(b)])),
  166. # State creation
  167. 'create_node' : tree_ir.CreateNodeInstruction,
  168. 'create_edge' :
  169. # Lambda is totally necessary here, pylint.
  170. # You totally dropped the ball on this one.
  171. # pylint: disable=I0011,W0108
  172. lambda a, b:
  173. tree_ir.CreateEdgeInstruction(a, b),
  174. 'create_value' :
  175. lambda a:
  176. tree_ir.CreateNodeWithValueInstruction(
  177. tree_ir.ReadValueInstruction(a)),
  178. # State reads
  179. 'read_edge_src' :
  180. lambda a:
  181. tree_ir.LoadIndexInstruction(
  182. tree_ir.ReadEdgeInstruction(a),
  183. tree_ir.LiteralInstruction(0)),
  184. 'read_edge_dst' :
  185. lambda a:
  186. tree_ir.LoadIndexInstruction(
  187. tree_ir.ReadEdgeInstruction(a),
  188. tree_ir.LiteralInstruction(1)),
  189. 'is_edge' :
  190. lambda a:
  191. tree_ir.CreateNodeWithValueInstruction(
  192. tree_ir.BinaryInstruction(
  193. tree_ir.LoadIndexInstruction(
  194. tree_ir.ReadEdgeInstruction(a),
  195. tree_ir.LiteralInstruction(0)),
  196. 'is not',
  197. tree_ir.LiteralInstruction(None))),
  198. # read_root
  199. 'read_root' :
  200. lambda:
  201. tree_ir.LoadIndexInstruction(
  202. tree_ir.LoadLocalInstruction(jit.KWARGS_PARAMETER_NAME),
  203. tree_ir.LiteralInstruction('root')),
  204. # read_userroot
  205. 'read_userroot' :
  206. lambda:
  207. tree_ir.LoadIndexInstruction(
  208. tree_ir.LoadLocalInstruction(jit.KWARGS_PARAMETER_NAME),
  209. tree_ir.LiteralInstruction('user_root')),
  210. # Dictionary operations
  211. 'dict_read' :
  212. lambda a, b:
  213. tree_ir.ReadDictionaryValueInstruction(
  214. a, tree_ir.ReadValueInstruction(b)),
  215. 'dict_read_edge' :
  216. lambda a, b:
  217. tree_ir.ReadDictionaryEdgeInstruction(
  218. a, tree_ir.ReadValueInstruction(b)),
  219. 'dict_add' : __dict_add,
  220. # Set operations
  221. 'set_add' : __set_add,
  222. # List operations
  223. 'list_len' :
  224. lambda a:
  225. tree_ir.CreateNodeWithValueInstruction(
  226. create_get_length(tree_ir.ReadOutgoingEdgesInstruction(a))),
  227. 'list_read' : __list_read,
  228. 'list_append' : __list_append
  229. }
  230. def register_time_intrinsic(target_jit):
  231. """Registers the time() intrinsic with the given JIT."""
  232. import_name = target_jit.import_value(time.time, 'time')
  233. target_jit.register_intrinsic(
  234. 'time',
  235. lambda: tree_ir.CreateNodeWithValueInstruction(
  236. tree_ir.CallInstruction(
  237. tree_ir.LoadGlobalInstruction(import_name),
  238. [])))
  239. def register_intrinsics(target_jit):
  240. """Registers all intrinsics in the module with the given JIT."""
  241. for (key, value) in BINARY_INTRINSICS.items():
  242. target_jit.register_binary_intrinsic(key, value)
  243. for (key, value) in UNARY_INTRINSICS.items():
  244. target_jit.register_unary_intrinsic(key, value)
  245. for (key, value) in CAST_INTRINSICS.items():
  246. target_jit.register_cast_intrinsic(key, value)
  247. for (key, value) in MISC_INTRINSICS.items():
  248. target_jit.register_intrinsic(key, value)
  249. register_time_intrinsic(target_jit)