intrinsics.py 7.6 KB

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