intrinsics.py 16 KB

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