intrinsics.py 8.0 KB

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