intrinsics.py 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  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. def __log(a):
  125. # Original definition:
  126. #
  127. # def log(a, **remainder):
  128. # a_value, = yield [("RV", [a])]
  129. # print("== LOG == " + str(a_value))
  130. # raise PrimitiveFinished(a)
  131. a_tmp = tree_ir.StoreLocalInstruction(None, a)
  132. return tree_ir.CompoundInstruction(
  133. tree_ir.create_block(
  134. a_tmp,
  135. tree_ir.PrintInstruction(
  136. tree_ir.BinaryInstruction(
  137. tree_ir.LiteralInstruction("== LOG == "),
  138. '+',
  139. tree_ir.CallInstruction(
  140. tree_ir.LoadGlobalInstruction('str'),
  141. [tree_ir.ReadValueInstruction(a_tmp.create_load())])))),
  142. a_tmp.create_load())
  143. MISC_INTRINSICS = {
  144. # Reference equality
  145. 'element_eq' :
  146. lambda a, b:
  147. tree_ir.CreateNodeWithValueInstruction(
  148. tree_ir.BinaryInstruction(a, '==', b)),
  149. 'element_neq' :
  150. lambda a, b:
  151. tree_ir.CreateNodeWithValueInstruction(
  152. tree_ir.BinaryInstruction(a, '!=', b)),
  153. # Strings
  154. 'string_get' :
  155. lambda a, b:
  156. tree_ir.CreateNodeWithValueInstruction(
  157. tree_ir.LoadIndexInstruction(
  158. tree_ir.ReadValueInstruction(a),
  159. tree_ir.ReadValueInstruction(b))),
  160. 'string_len' :
  161. lambda a:
  162. tree_ir.CreateNodeWithValueInstruction(
  163. tree_ir.CallInstruction(
  164. tree_ir.LoadGlobalInstruction('len'),
  165. [tree_ir.ReadValueInstruction(a)])),
  166. 'string_join' :
  167. lambda a, b:
  168. tree_ir.CreateNodeWithValueInstruction(
  169. tree_ir.BinaryInstruction(
  170. tree_ir.CallInstruction(
  171. tree_ir.LoadGlobalInstruction('str'),
  172. [tree_ir.ReadValueInstruction(a)]),
  173. '+',
  174. tree_ir.CallInstruction(
  175. tree_ir.LoadGlobalInstruction('str'),
  176. [tree_ir.ReadValueInstruction(b)]))),
  177. 'string_startswith' :
  178. lambda a, b:
  179. tree_ir.CreateNodeWithValueInstruction(
  180. tree_ir.CallInstruction(
  181. tree_ir.LoadMemberInstruction(
  182. tree_ir.ReadValueInstruction(a),
  183. 'startswith'),
  184. [tree_ir.ReadValueInstruction(b)])),
  185. # State creation
  186. 'create_node' : tree_ir.CreateNodeInstruction,
  187. 'create_edge' :
  188. # Lambda is totally necessary here, pylint.
  189. # You totally dropped the ball on this one.
  190. # pylint: disable=I0011,W0108
  191. lambda a, b:
  192. tree_ir.CreateEdgeInstruction(a, b),
  193. 'create_value' :
  194. lambda a:
  195. tree_ir.CreateNodeWithValueInstruction(
  196. tree_ir.ReadValueInstruction(a)),
  197. # State reads
  198. 'read_edge_src' :
  199. lambda a:
  200. tree_ir.LoadIndexInstruction(
  201. tree_ir.ReadEdgeInstruction(a),
  202. tree_ir.LiteralInstruction(0)),
  203. 'read_edge_dst' :
  204. lambda a:
  205. tree_ir.LoadIndexInstruction(
  206. tree_ir.ReadEdgeInstruction(a),
  207. tree_ir.LiteralInstruction(1)),
  208. 'is_edge' :
  209. lambda a:
  210. tree_ir.CreateNodeWithValueInstruction(
  211. tree_ir.BinaryInstruction(
  212. tree_ir.LoadIndexInstruction(
  213. tree_ir.ReadEdgeInstruction(a),
  214. tree_ir.LiteralInstruction(0)),
  215. 'is not',
  216. tree_ir.LiteralInstruction(None))),
  217. # read_root
  218. 'read_root' :
  219. lambda:
  220. tree_ir.LoadIndexInstruction(
  221. tree_ir.LoadLocalInstruction(jit.KWARGS_PARAMETER_NAME),
  222. tree_ir.LiteralInstruction('root')),
  223. # read_userroot
  224. 'read_userroot' :
  225. lambda:
  226. tree_ir.LoadIndexInstruction(
  227. tree_ir.LoadLocalInstruction(jit.KWARGS_PARAMETER_NAME),
  228. tree_ir.LiteralInstruction('user_root')),
  229. # Dictionary operations
  230. 'dict_read' :
  231. lambda a, b:
  232. tree_ir.ReadDictionaryValueInstruction(
  233. a, tree_ir.ReadValueInstruction(b)),
  234. 'dict_read_edge' :
  235. lambda a, b:
  236. tree_ir.ReadDictionaryEdgeInstruction(
  237. a, tree_ir.ReadValueInstruction(b)),
  238. 'dict_add' : __dict_add,
  239. # Set operations
  240. 'set_add' : __set_add,
  241. # List operations
  242. 'list_len' :
  243. lambda a:
  244. tree_ir.CreateNodeWithValueInstruction(
  245. create_get_length(tree_ir.ReadOutgoingEdgesInstruction(a))),
  246. 'list_read' : __list_read,
  247. 'list_append' : __list_append,
  248. # log
  249. 'log' : __log
  250. }
  251. def register_time_intrinsic(target_jit):
  252. """Registers the time() intrinsic with the given JIT."""
  253. import_name = target_jit.import_value(time.time, 'time')
  254. target_jit.register_intrinsic(
  255. 'time',
  256. lambda: tree_ir.CreateNodeWithValueInstruction(
  257. tree_ir.CallInstruction(
  258. tree_ir.LoadGlobalInstruction(import_name),
  259. [])))
  260. def register_intrinsics(target_jit):
  261. """Registers all intrinsics in the module with the given JIT."""
  262. for (key, value) in BINARY_INTRINSICS.items():
  263. target_jit.register_binary_intrinsic(key, value)
  264. for (key, value) in UNARY_INTRINSICS.items():
  265. target_jit.register_unary_intrinsic(key, value)
  266. for (key, value) in CAST_INTRINSICS.items():
  267. target_jit.register_cast_intrinsic(key, value)
  268. for (key, value) in MISC_INTRINSICS.items():
  269. target_jit.register_intrinsic(key, value)
  270. register_time_intrinsic(target_jit)