intrinsics.py 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467
  1. import time
  2. import modelverse_jit.jit as jit
  3. import modelverse_jit.tree_ir as tree_ir
  4. import modelverse_jit.cfg_ir as cfg_ir
  5. import modelverse_jit.runtime as jit_runtime
  6. BINARY_INTRINSICS = {
  7. 'value_eq' : '==',
  8. 'value_neq' : '!=',
  9. 'bool_and' : 'and',
  10. 'bool_or' : 'or',
  11. 'integer_addition' : '+',
  12. 'integer_subtraction' : '-',
  13. 'integer_multiplication' : '*',
  14. 'integer_division' : '/',
  15. 'integer_gt' : '>',
  16. 'integer_gte' : '>=',
  17. 'integer_lt' : '<',
  18. 'integer_lte' : '<=',
  19. 'float_addition' : '+',
  20. 'float_subtraction' : '-',
  21. 'float_multiplication' : '*',
  22. 'float_division' : '/',
  23. 'float_gt' : '>',
  24. 'float_gte' : '>=',
  25. 'float_lt' : '<',
  26. 'float_lte' : '<='
  27. }
  28. UNARY_INTRINSICS = {
  29. 'bool_not' : 'not',
  30. 'integer_neg' : '-',
  31. 'float_neg' : '-'
  32. }
  33. CAST_INTRINSICS = {
  34. 'cast_i2f' : float,
  35. 'cast_i2s' : str,
  36. 'cast_i2b' : bool,
  37. 'cast_f2i' : int,
  38. 'cast_f2s' : str,
  39. 'cast_f2b' : bool,
  40. 'cast_s2i' : int,
  41. 'cast_s2f' : float,
  42. 'cast_s2b' : bool,
  43. 'cast_b2i' : int,
  44. 'cast_b2f' : float,
  45. 'cast_b2s' : str
  46. }
  47. def create_get_length(expression):
  48. """Creates an expression that evaluates the given expression, and then
  49. computes the length of its result."""
  50. return tree_ir.CallInstruction(
  51. tree_ir.LoadGlobalInstruction('len'),
  52. [expression])
  53. # Don't compain about the variable names, pylint. It's important that we
  54. # get them right.
  55. # pylint: disable=I0011,C0103
  56. def __set_add(a, b):
  57. store_a, load_a = tree_ir.evaluate_and_load(a)
  58. return tree_ir.create_block(
  59. store_a,
  60. tree_ir.CreateEdgeInstruction(load_a, b),
  61. load_a)
  62. def __dict_add(a, b, c):
  63. store_a, load_a = tree_ir.evaluate_and_load(a)
  64. store_b, load_b = tree_ir.evaluate_and_load(b)
  65. return tree_ir.create_block(
  66. store_a,
  67. store_b,
  68. tree_ir.CreateEdgeInstruction(
  69. tree_ir.CreateEdgeInstruction(load_a, c),
  70. load_b),
  71. load_a)
  72. def __list_read(a, b):
  73. # The statements in this function generate the following code:
  74. #
  75. # a_tmp = a # To make sure a is evaluated before b.
  76. # b_value, = yield [("RV", [b])]
  77. # result, = yield [("RD", [a_tmp, b_value])]
  78. # if result is None:
  79. # raise Exception("List read out of bounds: %s" % b_value)
  80. # result
  81. store_a, load_a = tree_ir.evaluate_and_load(a)
  82. b_val = tree_ir.StoreLocalInstruction(
  83. None,
  84. tree_ir.ReadValueInstruction(b))
  85. result = tree_ir.StoreLocalInstruction(
  86. None,
  87. tree_ir.ReadDictionaryValueInstruction(
  88. load_a.create_load(), b_val.create_load()))
  89. return tree_ir.create_block(
  90. store_a,
  91. b_val,
  92. result,
  93. tree_ir.SelectInstruction(
  94. tree_ir.BinaryInstruction(
  95. result.create_load(),
  96. 'is',
  97. tree_ir.LiteralInstruction(None)),
  98. tree_ir.RaiseInstruction(
  99. tree_ir.CallInstruction(
  100. tree_ir.LoadGlobalInstruction('Exception'),
  101. [tree_ir.BinaryInstruction(
  102. tree_ir.LiteralInstruction('List read out of bounds: %s'),
  103. '%',
  104. b_val.create_load())])),
  105. tree_ir.EmptyInstruction()),
  106. result.create_load())
  107. def __list_append(a, b):
  108. # We want to generate code that is more or less equivalent to:
  109. #
  110. # a_tmp = a
  111. # b_tmp = b
  112. # a_outgoing, = yield [("RO", [a_tmp])]
  113. # _ = yield [("CD", [a_tmp, len(a_outgoing), b_tmp])]
  114. # a
  115. store_a, load_a = tree_ir.evaluate_and_load(a)
  116. store_b, load_b = tree_ir.evaluate_and_load(b)
  117. return tree_ir.create_block(
  118. store_a,
  119. store_b,
  120. tree_ir.CreateDictionaryEdgeInstruction(
  121. load_a,
  122. create_get_length(
  123. tree_ir.ReadOutgoingEdgesInstruction(
  124. load_a)),
  125. load_b),
  126. load_a)
  127. def __log(a):
  128. # Original definition:
  129. #
  130. # def log(a, **remainder):
  131. # a_value, = yield [("RV", [a])]
  132. # print("== LOG == " + str(a_value))
  133. # raise PrimitiveFinished(a)
  134. store_a, load_a = tree_ir.evaluate_and_load(a)
  135. return tree_ir.CompoundInstruction(
  136. tree_ir.create_block(
  137. store_a,
  138. tree_ir.PrintInstruction(
  139. tree_ir.BinaryInstruction(
  140. tree_ir.LiteralInstruction("== LOG == "),
  141. '+',
  142. tree_ir.CallInstruction(
  143. tree_ir.LoadGlobalInstruction('str'),
  144. [tree_ir.ReadValueInstruction(load_a)])))),
  145. load_a)
  146. def __read_nr_out(a):
  147. # Original definition:
  148. #
  149. # def read_nr_out(a, **remainder):
  150. # outgoing, = yield [("RO", [a])]
  151. # result, = yield [("CNV", [len(outgoing)])]
  152. # raise PrimitiveFinished(result)
  153. return tree_ir.CreateNodeWithValueInstruction(
  154. create_get_length(tree_ir.ReadOutgoingEdgesInstruction(a)))
  155. MISC_INTRINSICS = {
  156. # Reference equality
  157. 'element_eq' :
  158. lambda a, b:
  159. tree_ir.CreateNodeWithValueInstruction(
  160. tree_ir.BinaryInstruction(a, '==', b)),
  161. 'element_neq' :
  162. lambda a, b:
  163. tree_ir.CreateNodeWithValueInstruction(
  164. tree_ir.BinaryInstruction(a, '!=', b)),
  165. # Strings
  166. 'string_get' :
  167. lambda a, b:
  168. tree_ir.CreateNodeWithValueInstruction(
  169. tree_ir.LoadIndexInstruction(
  170. tree_ir.ReadValueInstruction(a),
  171. tree_ir.ReadValueInstruction(b))),
  172. 'string_len' :
  173. lambda a:
  174. tree_ir.CreateNodeWithValueInstruction(
  175. tree_ir.CallInstruction(
  176. tree_ir.LoadGlobalInstruction('len'),
  177. [tree_ir.ReadValueInstruction(a)])),
  178. 'string_join' :
  179. lambda a, b:
  180. tree_ir.CreateNodeWithValueInstruction(
  181. tree_ir.BinaryInstruction(
  182. tree_ir.CallInstruction(
  183. tree_ir.LoadGlobalInstruction('str'),
  184. [tree_ir.ReadValueInstruction(a)]),
  185. '+',
  186. tree_ir.CallInstruction(
  187. tree_ir.LoadGlobalInstruction('str'),
  188. [tree_ir.ReadValueInstruction(b)]))),
  189. 'string_startswith' :
  190. lambda a, b:
  191. tree_ir.CreateNodeWithValueInstruction(
  192. tree_ir.CallInstruction(
  193. tree_ir.LoadMemberInstruction(
  194. tree_ir.ReadValueInstruction(a),
  195. 'startswith'),
  196. [tree_ir.ReadValueInstruction(b)])),
  197. # State creation
  198. 'create_node' : tree_ir.CreateNodeInstruction,
  199. 'create_edge' :
  200. # Lambda is totally necessary here, pylint.
  201. # You totally dropped the ball on this one.
  202. # pylint: disable=I0011,W0108
  203. lambda a, b:
  204. tree_ir.CreateEdgeInstruction(a, b),
  205. 'create_value' :
  206. lambda a:
  207. tree_ir.CreateNodeWithValueInstruction(
  208. tree_ir.ReadValueInstruction(a)),
  209. # State reads
  210. 'read_edge_src' :
  211. lambda a:
  212. tree_ir.LoadIndexInstruction(
  213. tree_ir.ReadEdgeInstruction(a),
  214. tree_ir.LiteralInstruction(0)),
  215. 'read_edge_dst' :
  216. lambda a:
  217. tree_ir.LoadIndexInstruction(
  218. tree_ir.ReadEdgeInstruction(a),
  219. tree_ir.LiteralInstruction(1)),
  220. 'is_edge' :
  221. lambda a:
  222. tree_ir.CreateNodeWithValueInstruction(
  223. tree_ir.BinaryInstruction(
  224. tree_ir.LoadIndexInstruction(
  225. tree_ir.ReadEdgeInstruction(a),
  226. tree_ir.LiteralInstruction(0)),
  227. 'is not',
  228. tree_ir.LiteralInstruction(None))),
  229. 'read_nr_out' : __read_nr_out,
  230. # read_root
  231. 'read_root' :
  232. lambda:
  233. tree_ir.LoadIndexInstruction(
  234. tree_ir.LoadLocalInstruction(jit_runtime.KWARGS_PARAMETER_NAME),
  235. tree_ir.LiteralInstruction('root')),
  236. # read_taskroot
  237. 'read_taskroot' :
  238. lambda:
  239. tree_ir.LoadIndexInstruction(
  240. tree_ir.LoadLocalInstruction(jit_runtime.KWARGS_PARAMETER_NAME),
  241. tree_ir.LiteralInstruction('task_root')),
  242. # Dictionary operations
  243. 'dict_read' :
  244. lambda a, b:
  245. tree_ir.ReadDictionaryValueInstruction(
  246. a, tree_ir.ReadValueInstruction(b)),
  247. 'dict_read_edge' :
  248. lambda a, b:
  249. tree_ir.ReadDictionaryEdgeInstruction(
  250. a, tree_ir.ReadValueInstruction(b)),
  251. 'dict_add' : __dict_add,
  252. 'dict_len' : __read_nr_out,
  253. # Set operations
  254. 'set_add' : __set_add,
  255. # List operations
  256. 'list_len' : __read_nr_out,
  257. 'list_read' : __list_read,
  258. 'list_append' : __list_append,
  259. # log
  260. 'log' : __log
  261. }
  262. def __read_nr_out_cfg(original_def, a):
  263. # Original definition:
  264. #
  265. # def read_nr_out(a, **remainder):
  266. # outgoing, = yield [("RO", [a])]
  267. # result, = yield [("CNV", [len(outgoing)])]
  268. # raise PrimitiveFinished(result)
  269. original_def.redefine(
  270. cfg_ir.CreateNode(
  271. original_def.insert_before(
  272. cfg_ir.create_pure_simple_call(
  273. 'len',
  274. original_def.insert_before(
  275. cfg_ir.create_read_outgoing_edges(a))))))
  276. def __dict_in_cfg(original_def, a, b):
  277. # Original definition:
  278. #
  279. # def dict_in(a, b, **remainder):
  280. # b_value, = yield [("RV", [b])]
  281. # value, = yield [("RD", [a, b_value])]
  282. # is_in = value is not None
  283. # result, = yield [("CNV", [is_in])]
  284. # raise PrimitiveFinished(result)
  285. original_def.redefine(
  286. cfg_ir.CreateNode(
  287. original_def.insert_before(
  288. cfg_ir.Binary(
  289. original_def.insert_before(
  290. cfg_ir.create_read_dict_value(
  291. a, original_def.insert_before(cfg_ir.Read(b)))),
  292. 'is not',
  293. original_def.insert_before(cfg_ir.Literal(None))))))
  294. def __dict_in_node_cfg(original_def, a, b):
  295. # Original definition:
  296. #
  297. # def dict_in_node(a, b, **remainder):
  298. # value, = yield [("RDN", [a, b])]
  299. # result, = yield [("CNV", [value is not None])]
  300. # raise PrimitiveFinished(result)
  301. original_def.redefine(
  302. cfg_ir.CreateNode(
  303. original_def.insert_before(
  304. cfg_ir.Binary(
  305. original_def.insert_before(cfg_ir.create_read_dict_node(a, b)),
  306. 'is not',
  307. original_def.insert_before(cfg_ir.Literal(None))))))
  308. def __dict_read_cfg(original_def, a, b):
  309. # Original definition:
  310. #
  311. # def dict_read(a, b, **remainder):
  312. # b_value, = yield [("RV", [b])]
  313. # result, = yield [("RD", [a, b_value])]
  314. # raise PrimitiveFinished(result)
  315. original_def.redefine(
  316. cfg_ir.create_read_dict_value(
  317. a,
  318. original_def.insert_before(cfg_ir.Read(b))))
  319. MISC_CFG_INTRINSICS = {
  320. # Reference equality
  321. 'element_eq' :
  322. lambda original_def, a, b:
  323. original_def.redefine(
  324. cfg_ir.CreateNode(
  325. original_def.insert_before(
  326. cfg_ir.Binary(a, '==', b)))),
  327. 'element_neq' :
  328. lambda original_def, a, b:
  329. original_def.redefine(
  330. cfg_ir.CreateNode(
  331. original_def.insert_before(
  332. cfg_ir.Binary(a, '!=', b)))),
  333. # String operations
  334. 'string_get' :
  335. lambda original_def, a, b:
  336. original_def.redefine(
  337. cfg_ir.CreateNode(
  338. original_def.insert_before(
  339. cfg_ir.create_index(
  340. original_def.insert_before(cfg_ir.Read(a)),
  341. original_def.insert_before(cfg_ir.Read(b)))))),
  342. 'string_len' :
  343. lambda original_def, a:
  344. original_def.redefine(
  345. cfg_ir.CreateNode(
  346. original_def.insert_before(
  347. cfg_ir.create_pure_simple_call(
  348. 'len',
  349. original_def.insert_before(cfg_ir.Read(a)))))),
  350. 'string_join' :
  351. lambda original_def, a, b:
  352. original_def.redefine(
  353. cfg_ir.CreateNode(
  354. original_def.insert_before(
  355. cfg_ir.Binary(
  356. original_def.insert_before(
  357. cfg_ir.create_pure_simple_call(
  358. 'str',
  359. original_def.insert_before(cfg_ir.Read(a)))),
  360. '+',
  361. original_def.insert_before(
  362. cfg_ir.create_pure_simple_call(
  363. 'str',
  364. original_def.insert_before(cfg_ir.Read(b)))))))),
  365. 'string_startswith' :
  366. lambda original_def, a, b:
  367. original_def.redefine(
  368. cfg_ir.CreateNode(
  369. original_def.insert_before(
  370. cfg_ir.DirectFunctionCall(
  371. 'startswith',
  372. [('self', original_def.insert_before(cfg_ir.Read(a))),
  373. ('substring', original_def.insert_before(cfg_ir.Read(b)))],
  374. calling_convention=cfg_ir.SELF_POSITIONAL_CALLING_CONVENTION,
  375. has_value=True, has_side_effects=False)))),
  376. # State creation
  377. 'create_node' :
  378. lambda original_def:
  379. original_def.redefine(
  380. cfg_ir.CreateNode(original_def.insert_before(cfg_ir.Literal(None)))),
  381. 'create_value' :
  382. lambda original_def, a:
  383. original_def.redefine(
  384. cfg_ir.CreateNode(original_def.insert_before(cfg_ir.Read(a)))),
  385. # State reads
  386. 'read_nr_out' : __read_nr_out_cfg,
  387. # Dictionary operations
  388. 'dict_len' : __read_nr_out_cfg,
  389. 'dict_read' : __dict_read_cfg,
  390. 'dict_in' : __dict_in_cfg,
  391. 'dict_in_node' : __dict_in_node_cfg,
  392. # List operations
  393. 'list_len' : __read_nr_out_cfg
  394. }
  395. def register_time_intrinsic(target_jit):
  396. """Registers the time() intrinsic with the given JIT."""
  397. import_name = target_jit.import_value(time.time, 'time')
  398. target_jit.register_intrinsic(
  399. 'time',
  400. lambda: tree_ir.CreateNodeWithValueInstruction(
  401. tree_ir.CallInstruction(
  402. tree_ir.LoadGlobalInstruction(import_name),
  403. [])))
  404. def register_intrinsics(target_jit):
  405. """Registers all intrinsics in the module with the given JIT."""
  406. for (key, value) in BINARY_INTRINSICS.items():
  407. target_jit.register_binary_intrinsic(key, value)
  408. for (key, value) in UNARY_INTRINSICS.items():
  409. target_jit.register_unary_intrinsic(key, value)
  410. for (key, value) in CAST_INTRINSICS.items():
  411. target_jit.register_cast_intrinsic(key, value)
  412. for (key, value) in MISC_INTRINSICS.items():
  413. target_jit.register_intrinsic(key, value)
  414. for (key, value) in MISC_CFG_INTRINSICS.items():
  415. target_jit.register_cfg_intrinsic(key, value)
  416. register_time_intrinsic(target_jit)