tree_ir.py 46 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197
  1. # NOTE: NOP_LITERAL abuses a mechanic of the modelverse kernel. Specifically,
  2. # whenever the `ModelverseKernel.execute_yields` method returns `None`, then
  3. # the server built around it takes that as a hint that an instruction's phase
  4. # has been completed. The server interrupts the kernel's thread of execution
  5. # when it remarks that an instruction has completed a phase (i.e., when `None`
  6. # is returned by `ModelverseKernel.execute_yields`) and proceeds to check for
  7. # input and output.
  8. #
  9. # In assembly language, a nop is usually used as a point at which a thread of
  10. # execution can be terminated. It follows from the paragraph above that what
  11. # the interpreter does is more or less equivalent to placing nops after every
  12. # instruction. It is worthwhile to remark that JIT-compiled code cannot rely
  13. # on the kernel to interrupt the thread of execution automatically during a
  14. # jitted function's execution -- jitted functions are considered equivalent
  15. # to a single instruction as far as the kernel is concerned. A nop will be
  16. # inserted _after_ the function call (if it is called from interpreted code)
  17. # but that does not suffice for IO, which needs the input/output processing
  18. # to be performed during function execution.
  19. #
  20. # For this reason, the JIT must strategically interrupt the execution of the
  21. # functions it compiles. In other words, it must insert its own nops.
  22. # Here comes the interesting part: a nop is equivalent to `yield None`,
  23. # because that will persuade `ModelverseKernel.execute_yields` to relay the
  24. # `None` marker value to the server, without terminating the current
  25. # generator.
  26. NOP_LITERAL = None
  27. """A literal that results in a nop during which execution may be interrupted
  28. when yielded."""
  29. class Instruction(object):
  30. """A base class for instructions. An instruction is essentially a syntax
  31. node that must first be defined, and can only then be used."""
  32. def __init__(self):
  33. self.has_result_cache = None
  34. self.has_definition_cache = None
  35. def has_result(self):
  36. """Tells if this instruction computes a result."""
  37. if self.has_result_cache is None:
  38. self.has_result_cache = self.has_result_impl()
  39. return self.has_result_cache
  40. def has_definition(self):
  41. """Tells if this instruction requires a definition."""
  42. if self.has_definition_cache is None:
  43. self.has_definition_cache = self.has_definition_impl()
  44. return self.has_definition_cache
  45. def has_result_impl(self):
  46. """Tells if this instruction computes a result."""
  47. return True
  48. def has_definition_impl(self):
  49. """Tells if this instruction requires a definition."""
  50. return True
  51. def get_result_name_override(self, code_generator):
  52. """Gets a value that overrides the code generator's result name for this
  53. instruction if it is not None."""
  54. return None
  55. def generate_python_def(self, code_generator):
  56. """Generates a Python statement that executes this instruction.
  57. The statement is appended immediately to the code generator."""
  58. if self.has_definition():
  59. raise NotImplementedError()
  60. else:
  61. code_generator.append_line('pass')
  62. def generate_python_use(self, code_generator):
  63. """Generates a Python expression that retrieves this instruction's
  64. result. The expression is returned as a string."""
  65. if self.has_result():
  66. return code_generator.get_result_name(self)
  67. else:
  68. return 'None'
  69. def get_children(self):
  70. """Gets this instruction's sequence of child instructions."""
  71. raise NotImplementedError()
  72. def create(self, new_children):
  73. """Creates a new instruction of this type from the given sequence of child instructions."""
  74. raise NotImplementedError()
  75. def simplify_node(self):
  76. """Applies basic simplification to this instruction only."""
  77. return self
  78. def simplify(self):
  79. """Applies basic simplification to this instruction and all of its children."""
  80. # This fairly convoluted one-liner first simplifies all children, then creates
  81. # an instruction from the simplified children, and finally simplifies that top-level
  82. # instruction.
  83. return self.create([c.simplify() for c in self.get_children()]).simplify_node()
  84. def __str__(self):
  85. code_generator = PythonGenerator()
  86. self.generate_python_def(code_generator)
  87. return str(code_generator)
  88. class PythonGenerator(object):
  89. """Generates Python code from instructions."""
  90. def __init__(self, combine_state_definitions=True):
  91. self.code = []
  92. self.state_definitions = []
  93. self.state_definition_names = set()
  94. self.indentation_string = ' ' * 4
  95. self.indentation = 0
  96. self.result_name_dict = {}
  97. self.combine_state_definitions = combine_state_definitions
  98. def append(self, text):
  99. """Appends the given string to this code generator."""
  100. self.flush_state_definitions()
  101. self.code.append(text)
  102. def append_indentation(self):
  103. """Appends indentation to the code generator."""
  104. self.append(self.indentation_string * self.indentation)
  105. def append_line(self, line=None):
  106. """Appends the indentation string followed by the given string (if any)
  107. and a newline to the code generator."""
  108. self.append_indentation()
  109. if line is not None:
  110. self.append(line)
  111. self.append('\n')
  112. def increase_indentation(self):
  113. """Increases the code generator's indentation by one indent."""
  114. self.flush_state_definitions()
  115. self.indentation += 1
  116. def decrease_indentation(self):
  117. """Decreases the code generator's indentation by one indent."""
  118. self.flush_state_definitions()
  119. self.indentation -= 1
  120. def get_result_name(self, instruction, advised_name=None):
  121. """Gets the name of the given instruction's result variable."""
  122. if instruction not in self.result_name_dict:
  123. override_name = instruction.get_result_name_override(self)
  124. if override_name is not None:
  125. self.result_name_dict[instruction] = override_name
  126. elif advised_name is not None:
  127. self.result_name_dict[instruction] = advised_name
  128. else:
  129. self.result_name_dict[instruction] = \
  130. 'tmp' + str(len(self.result_name_dict))
  131. result = self.result_name_dict[instruction]
  132. if result in self.state_definition_names:
  133. # This might mean that we're trying to access a name that is
  134. # defined by the current block of state definitions. So we need
  135. # to flush the state definitions now.
  136. self.flush_state_definitions()
  137. return result
  138. def append_definition(self, lhs, rhs):
  139. """Defines the first instruction's result variable as the second
  140. instruction's result."""
  141. self.append_line(
  142. self.get_result_name(lhs) + ' = ' + rhs.generate_python_use(self))
  143. def append_move_definition(self, lhs, rhs):
  144. """First defines the second instruction, then defines the first
  145. instruction as the result of the second."""
  146. if rhs.has_definition():
  147. # Retrieve the result name for the lhs.
  148. lhs_result_name = self.get_result_name(lhs)
  149. # Encourage the rhs to take on the same result name as the lhs.
  150. rhs_result_name = self.get_result_name(rhs, lhs_result_name)
  151. # Generate the rhs' definition.
  152. rhs.generate_python_def(self)
  153. # Only perform an assignment if it's truly necessary.
  154. if lhs_result_name != rhs_result_name:
  155. self.append_definition(lhs, rhs)
  156. else:
  157. self.append_definition(lhs, rhs)
  158. def append_state_definition(self, lhs, opcode, args):
  159. """Appends a definition that queries the modelverse state."""
  160. result_name = self.get_result_name(lhs)
  161. request_tuple = '(%s, [%s])' % (
  162. repr(opcode),
  163. ', '.join([arg_i.generate_python_use(self) for arg_i in args]))
  164. self.state_definitions.append((result_name, request_tuple))
  165. self.state_definition_names.add(result_name)
  166. if not self.combine_state_definitions:
  167. self.flush_state_definitions()
  168. def flush_state_definitions(self):
  169. """Flushes the list of state-access definitions to the generated code."""
  170. state_defs = self.state_definitions
  171. if len(state_defs) > 0:
  172. # Clear state_definitions _before_ calling append_line, because append_line
  173. # will call flush_state_definitions. Clearing state_definitions afterward
  174. # will result in infinite recursion.
  175. self.state_definitions = []
  176. self.state_definition_names = set()
  177. if len(state_defs) == 1:
  178. self.append_line('%s, = yield [%s]' % state_defs[0])
  179. else:
  180. self.append_line(
  181. "%s = yield [%s]" % (
  182. ', '.join([name for name, _ in state_defs]),
  183. ', '.join([def_val for _, def_val in state_defs])))
  184. def __str__(self):
  185. self.flush_state_definitions()
  186. return ''.join(self.code)
  187. class VoidInstruction(Instruction):
  188. """A base class for instructions that do not return a value."""
  189. def has_result_impl(self):
  190. """Tells if this instruction computes a result."""
  191. return False
  192. def get_children(self):
  193. """Gets this instruction's sequence of child instructions."""
  194. return []
  195. def create(self, new_children):
  196. """Creates a new instruction of this type from the given sequence of child instructions."""
  197. return self
  198. class EmptyInstruction(VoidInstruction):
  199. """Represents the empty instruction, which does nothing."""
  200. def has_definition_impl(self):
  201. """Tells if this instruction requires a definition."""
  202. return False
  203. class SelectInstruction(Instruction):
  204. """Represents a select-instruction: an instruction that defines one of two
  205. child instructions, and sets its result to the defined child's result."""
  206. def __init__(self, condition, if_clause, else_clause):
  207. Instruction.__init__(self)
  208. self.condition = condition
  209. self.if_clause = if_clause
  210. self.else_clause = else_clause
  211. def has_result_impl(self):
  212. """Tells if this instruction computes a result."""
  213. return self.if_clause.has_result() or self.else_clause.has_result()
  214. def simplify_node(self):
  215. """Applies basic simplification to this instruction only."""
  216. if isinstance(self.condition, LiteralInstruction):
  217. return self.if_clause if self.condition.literal else self.else_clause
  218. else:
  219. return SelectInstruction(self.condition, self.if_clause, self.else_clause)
  220. def get_children(self):
  221. """Gets this instruction's sequence of child instructions."""
  222. return [self.condition, self.if_clause, self.else_clause]
  223. def create(self, new_children):
  224. """Creates a new instruction of this type from the given sequence of child instructions."""
  225. condition, if_clause, else_clause = new_children
  226. return SelectInstruction(condition, if_clause, else_clause)
  227. def generate_python_def(self, code_generator):
  228. """Generates Python code for this instruction."""
  229. if_has_result = self.has_result()
  230. if self.condition.has_definition():
  231. self.condition.generate_python_def(code_generator)
  232. code_generator.append_line(
  233. 'if ' + self.condition.generate_python_use(code_generator) + ':')
  234. code_generator.increase_indentation()
  235. if if_has_result:
  236. code_generator.append_move_definition(self, self.if_clause)
  237. else:
  238. self.if_clause.generate_python_def(code_generator)
  239. code_generator.decrease_indentation()
  240. else_has_def = self.else_clause.has_definition()
  241. if else_has_def or if_has_result:
  242. code_generator.append_line('else:')
  243. code_generator.increase_indentation()
  244. if if_has_result:
  245. code_generator.append_move_definition(self, self.else_clause)
  246. else:
  247. self.else_clause.generate_python_def(code_generator)
  248. code_generator.decrease_indentation()
  249. class ReturnInstruction(VoidInstruction):
  250. """Represents a return-instruction."""
  251. def __init__(self, value):
  252. VoidInstruction.__init__(self)
  253. self.value = value
  254. def get_children(self):
  255. """Gets this instruction's sequence of child instructions."""
  256. return [self.value]
  257. def create(self, new_children):
  258. """Creates a new instruction of this type from the given sequence of child instructions."""
  259. value, = new_children
  260. return ReturnInstruction(value)
  261. def generate_python_def(self, code_generator):
  262. """Generates Python code for this instruction."""
  263. if self.value.has_definition():
  264. self.value.generate_python_def(code_generator)
  265. code_generator.append_line(
  266. 'raise PrimitiveFinished(' +
  267. self.value.generate_python_use(code_generator) +
  268. ')')
  269. class RaiseInstruction(VoidInstruction):
  270. """An instruction that raises an error."""
  271. def __init__(self, value):
  272. VoidInstruction.__init__(self)
  273. self.value = value
  274. def get_children(self):
  275. """Gets this instruction's sequence of child instructions."""
  276. return [self.value]
  277. def create(self, new_children):
  278. """Creates a new instruction of this type from the given sequence of child instructions."""
  279. value, = new_children
  280. return RaiseInstruction(value)
  281. def generate_python_def(self, code_generator):
  282. """Generates Python code for this instruction."""
  283. self.value.generate_python_def(code_generator)
  284. code_generator.append_line(
  285. 'raise ' + self.value.generate_python_use(code_generator))
  286. class CallInstruction(Instruction):
  287. """An instruction that performs a simple call."""
  288. def __init__(self, target, argument_list):
  289. Instruction.__init__(self)
  290. self.target = target
  291. self.argument_list = argument_list
  292. def get_children(self):
  293. """Gets this instruction's sequence of child instructions."""
  294. return [self.target] + self.argument_list
  295. def create(self, new_children):
  296. """Creates a new instruction of this type from the given sequence of child instructions."""
  297. return CallInstruction(new_children[0], new_children[1:])
  298. def generate_python_def(self, code_generator):
  299. """Generates Python code for this instruction."""
  300. if self.target.has_definition():
  301. self.target.generate_python_def(code_generator)
  302. for arg in self.argument_list:
  303. if arg.has_definition():
  304. arg.generate_python_def(code_generator)
  305. code_generator.append_line(
  306. '%s = %s(%s)' % (
  307. code_generator.get_result_name(self),
  308. self.target.generate_python_use(code_generator),
  309. ', '.join([arg.generate_python_use(code_generator) for arg in self.argument_list])))
  310. class JitCallInstruction(Instruction):
  311. """An instruction that calls a jitted function."""
  312. def __init__(self, target, named_args, kwarg):
  313. Instruction.__init__(self)
  314. self.target = target
  315. self.named_args = named_args
  316. self.kwarg = kwarg
  317. def get_children(self):
  318. """Gets this instruction's sequence of child instructions."""
  319. return [self.target] + [arg for _, arg in self.named_args] + [self.kwarg]
  320. def create(self, new_children):
  321. """Creates a new instruction of this type from the given sequence of child instructions."""
  322. param_names = [name for name, _ in self.named_args]
  323. return JitCallInstruction(
  324. new_children[0], zip(param_names, new_children[1:-1]), new_children[-1])
  325. def generate_python_def(self, code_generator):
  326. """Generates Python code for this instruction."""
  327. if self.target.has_definition():
  328. self.target.generate_python_def(code_generator)
  329. arg_list = []
  330. for param_name, arg in self.named_args:
  331. if arg.has_definition():
  332. arg.generate_python_def(code_generator)
  333. arg_list.append(
  334. '%s=%s' % (param_name, arg.generate_python_use(code_generator)))
  335. if self.kwarg.has_definition():
  336. self.kwarg.generate_python_def(code_generator)
  337. arg_list.append(
  338. '**%s' % self.kwarg.generate_python_use(code_generator))
  339. own_name = code_generator.get_result_name(self)
  340. code_generator.append_line('try:')
  341. code_generator.increase_indentation()
  342. code_generator.append_line(
  343. '%s_gen = %s(%s)' % (
  344. own_name,
  345. self.target.generate_python_use(code_generator),
  346. ', '.join(arg_list)))
  347. code_generator.append_line('%s_inp = None' % own_name)
  348. code_generator.append_line('while 1:')
  349. code_generator.increase_indentation()
  350. code_generator.append_line(
  351. '%s_inp = yield %s_gen.send(%s_inp)' % (own_name, own_name, own_name))
  352. code_generator.decrease_indentation()
  353. code_generator.decrease_indentation()
  354. code_generator.append_line('except PrimitiveFinished as %s_ex:' % own_name)
  355. code_generator.increase_indentation()
  356. code_generator.append_line('%s = %s_ex.result' % (own_name, own_name))
  357. code_generator.decrease_indentation()
  358. class PrintInstruction(Instruction):
  359. """An instruction that prints a value."""
  360. def __init__(self, argument):
  361. Instruction.__init__(self)
  362. self.argument = argument
  363. def has_result_impl(self):
  364. """Tells if this instruction has a result."""
  365. return False
  366. def get_children(self):
  367. """Gets this instruction's sequence of child instructions."""
  368. return [self.argument]
  369. def create(self, new_children):
  370. """Creates a new instruction of this type from the given sequence of child instructions."""
  371. arg, = new_children
  372. return PrintInstruction(arg)
  373. def generate_python_def(self, code_generator):
  374. """Generates Python code for this instruction."""
  375. if self.argument.has_definition():
  376. self.argument.generate_python_def(code_generator)
  377. code_generator.append_line(
  378. 'print(%s)' % (
  379. self.argument.generate_python_use(code_generator)))
  380. class BinaryInstruction(Instruction):
  381. """An instruction that performs a binary operation."""
  382. def __init__(self, lhs, operator, rhs):
  383. Instruction.__init__(self)
  384. self.lhs = lhs
  385. self.operator = operator
  386. self.rhs = rhs
  387. def has_definition_impl(self):
  388. """Tells if this instruction requires a definition."""
  389. return self.lhs.has_definition() or self.rhs.has_definition()
  390. def get_children(self):
  391. """Gets this instruction's sequence of child instructions."""
  392. return [self.lhs, self.rhs]
  393. def create(self, new_children):
  394. """Creates a new instruction of this type from the given sequence of child instructions."""
  395. lhs, rhs, = new_children
  396. return BinaryInstruction(lhs, self.operator, rhs)
  397. def simplify_node(self):
  398. """Applies basic simplification to this instruction only."""
  399. if isinstance(self.lhs, LiteralInstruction) and isinstance(self.rhs, LiteralInstruction):
  400. # TODO: there's probably a better way to do this than with eval.
  401. return LiteralInstruction(
  402. eval('%s %s %s' % (repr(self.lhs.literal), self.operator, repr(self.rhs.literal))))
  403. else:
  404. return self
  405. def generate_python_use(self, code_generator):
  406. """Generates a Python expression that retrieves this instruction's
  407. result. The expression is returned as a string."""
  408. return '(%s %s %s)' % (
  409. self.lhs.generate_python_use(code_generator),
  410. self.operator,
  411. self.rhs.generate_python_use(code_generator))
  412. def generate_python_def(self, code_generator):
  413. """Generates a Python statement that executes this instruction.
  414. The statement is appended immediately to the code generator."""
  415. if self.lhs.has_definition():
  416. self.lhs.generate_python_def(code_generator)
  417. if self.rhs.has_definition():
  418. self.rhs.generate_python_def(code_generator)
  419. elif self.rhs.has_definition():
  420. self.rhs.generate_python_def(code_generator)
  421. else:
  422. code_generator.append_line('pass')
  423. class UnaryInstruction(Instruction):
  424. """An instruction that performs a unary operation."""
  425. def __init__(self, operator, operand):
  426. Instruction.__init__(self)
  427. self.operator = operator
  428. self.operand = operand
  429. def has_definition_impl(self):
  430. """Tells if this instruction requires a definition."""
  431. return self.operand.has_definition()
  432. def get_children(self):
  433. """Gets this instruction's sequence of child instructions."""
  434. return [self.operand]
  435. def create(self, new_children):
  436. """Creates a new instruction of this type from the given sequence of child instructions."""
  437. operand, = new_children
  438. return UnaryInstruction(self.operator, operand)
  439. def simplify_node(self):
  440. """Applies basic simplification to this instruction only."""
  441. if isinstance(self.operand, LiteralInstruction):
  442. # TODO: there's probably a better way to do this than with eval.
  443. return LiteralInstruction(
  444. eval('%s %s' % (self.operator, repr(self.operand.literal))))
  445. else:
  446. return self
  447. def generate_python_use(self, code_generator):
  448. """Generates a Python expression that retrieves this instruction's
  449. result. The expression is returned as a string."""
  450. return '(%s %s)' % (
  451. self.operator,
  452. self.operand.generate_python_use(code_generator))
  453. def generate_python_def(self, code_generator):
  454. """Generates a Python statement that executes this instruction.
  455. The statement is appended immediately to the code generator."""
  456. if self.operand.has_definition():
  457. self.operand.generate_python_def(code_generator)
  458. else:
  459. code_generator.append_line('pass')
  460. class LoopInstruction(VoidInstruction):
  461. """Represents a loop-instruction, which loops until broken."""
  462. def __init__(self, body):
  463. VoidInstruction.__init__(self)
  464. self.body = body
  465. def get_children(self):
  466. """Gets this instruction's sequence of child instructions."""
  467. return [self.body]
  468. def create(self, new_children):
  469. """Creates a new instruction of this type from the given sequence of child instructions."""
  470. body, = new_children
  471. return LoopInstruction(body)
  472. def generate_python_def(self, code_generator):
  473. """Generates Python code for this instruction."""
  474. code_generator.append_line('while 1:')
  475. code_generator.increase_indentation()
  476. self.body.generate_python_def(code_generator)
  477. code_generator.decrease_indentation()
  478. class BreakInstruction(VoidInstruction):
  479. """Represents a break-instruction."""
  480. def generate_python_def(self, code_generator):
  481. """Generates Python code for this instruction."""
  482. code_generator.append_line('break')
  483. class ContinueInstruction(VoidInstruction):
  484. """Represents a continue-instruction."""
  485. def generate_python_def(self, code_generator):
  486. """Generates Python code for this instruction."""
  487. code_generator.append_line('continue')
  488. class CompoundInstruction(Instruction):
  489. """Represents an instruction that evaluates two other instructions
  490. in order, and returns the second instruction's result."""
  491. def __init__(self, first, second):
  492. Instruction.__init__(self)
  493. self.first = first
  494. self.second = second
  495. def has_result_impl(self):
  496. """Tells if this instruction has a result."""
  497. return self.second.has_result() or self.first.has_result()
  498. def get_children(self):
  499. """Gets this instruction's sequence of child instructions."""
  500. return [self.first, self.second]
  501. def create(self, new_children):
  502. """Creates a new instruction of this type from the given sequence of child instructions."""
  503. first, second = new_children
  504. return CompoundInstruction(first, second)
  505. def simplify_node(self):
  506. """Applies basic simplification to this instruction and its children."""
  507. if not self.first.has_definition() and (
  508. not self.first.has_result() or self.second.has_result()):
  509. return self.second
  510. elif (not self.second.has_definition()) and (not self.second.has_result()):
  511. return self.first
  512. else:
  513. return self
  514. def generate_python_def(self, code_generator):
  515. """Generates Python code for this instruction."""
  516. if self.second.has_result():
  517. self.first.generate_python_def(code_generator)
  518. code_generator.append_move_definition(self, self.second)
  519. elif self.first.has_result():
  520. code_generator.append_move_definition(self, self.first)
  521. self.second.generate_python_def(code_generator)
  522. else:
  523. self.first.generate_python_def(code_generator)
  524. self.second.generate_python_def(code_generator)
  525. class LiteralInstruction(Instruction):
  526. """Represents an integer, floating-point, string or Boolean literal."""
  527. def __init__(self, literal):
  528. Instruction.__init__(self)
  529. self.literal = literal
  530. def has_definition_impl(self):
  531. """Tells if this instruction requires a definition."""
  532. return False
  533. def get_children(self):
  534. """Gets this instruction's sequence of child instructions."""
  535. return []
  536. def create(self, new_children):
  537. """Creates a new instruction of this type from the given sequence of child instructions."""
  538. return self
  539. def generate_python_use(self, code_generator):
  540. """Generates a Python expression that retrieves this instruction's
  541. result. The expression is returned as a string."""
  542. return repr(self.literal)
  543. class DictionaryLiteralInstruction(Instruction):
  544. """Constructs a dictionary literal."""
  545. def __init__(self, key_value_pairs):
  546. Instruction.__init__(self)
  547. self.key_value_pairs = key_value_pairs
  548. def get_children(self):
  549. """Gets this instruction's sequence of child instructions."""
  550. return [val for _, val in self.key_value_pairs]
  551. def create(self, new_children):
  552. """Creates a new instruction of this type from the given sequence of child instructions."""
  553. keys = [k for k, _ in self.key_value_pairs]
  554. return DictionaryLiteralInstruction(zip(keys, new_children))
  555. def has_definition(self):
  556. """Tells if this instruction requires a definition."""
  557. return any(
  558. [key.has_definition() or val.has_definition()
  559. for key, val in self.key_value_pairs])
  560. def simplify(self):
  561. """Applies basic simplification to this instruction and its children."""
  562. return DictionaryLiteralInstruction(
  563. [(key.simplify(), val.simplify()) for key, val in self.key_value_pairs])
  564. def generate_python_def(self, code_generator):
  565. """Generates a Python statement that executes this instruction.
  566. The statement is appended immediately to the code generator."""
  567. for key, val in self.key_value_pairs:
  568. if key.has_definition():
  569. key.generate_python_def(code_generator)
  570. if val.has_definition():
  571. val.generate_python_def(code_generator)
  572. def generate_python_use(self, code_generator):
  573. """Generates a Python expression that retrieves this instruction's
  574. result. The expression is returned as a string."""
  575. return '{ %s }' % ', '.join(
  576. ['%s : %s' % (
  577. key.generate_python_use(code_generator),
  578. val.generate_python_use(code_generator))
  579. for key, val in self.key_value_pairs])
  580. class StateInstruction(Instruction):
  581. """An instruction that accesses the modelverse state."""
  582. def get_opcode(self):
  583. """Gets the opcode for this state instruction."""
  584. raise NotImplementedError()
  585. def get_arguments(self):
  586. """Gets this state instruction's argument list."""
  587. raise NotImplementedError()
  588. def get_children(self):
  589. """Gets this instruction's sequence of child instructions."""
  590. return self.get_arguments()
  591. def create(self, new_children):
  592. """Creates a new instruction of this type from the given sequence of child instructions."""
  593. return type(self)(*new_children)
  594. def generate_python_def(self, code_generator):
  595. """Generates a Python statement that executes this instruction.
  596. The statement is appended immediately to the code generator."""
  597. args = self.get_arguments()
  598. for arg_i in args:
  599. if arg_i.has_definition():
  600. arg_i.generate_python_def(code_generator)
  601. code_generator.append_state_definition(self, self.get_opcode(), args)
  602. class VariableName(object):
  603. """A data structure that unifies names across instructions that access the
  604. same variable."""
  605. def __init__(self, name):
  606. self.name = name
  607. def get_result_name_override(self, _):
  608. """Gets a value that overrides the code generator's result name for this
  609. instruction if it is not None."""
  610. return self.name
  611. class VariableInstruction(Instruction):
  612. """A base class for instructions that access variables."""
  613. def __init__(self, name):
  614. Instruction.__init__(self)
  615. if isinstance(name, str) or isinstance(name, unicode) or name is None:
  616. self.name = VariableName(name)
  617. else:
  618. self.name = name
  619. def get_children(self):
  620. """Gets this instruction's sequence of child instructions."""
  621. raise NotImplementedError()
  622. def create(self, new_children):
  623. """Creates a new instruction of this type from the given sequence of child instructions."""
  624. raise NotImplementedError()
  625. def get_result_name_override(self, code_generator):
  626. """Gets a value that overrides the code generator's result name for this
  627. instruction if it is not None."""
  628. return code_generator.get_result_name(self.name)
  629. class LocalInstruction(VariableInstruction):
  630. """A base class for instructions that access local variables."""
  631. def get_children(self):
  632. """Gets this instruction's sequence of child instructions."""
  633. raise NotImplementedError()
  634. def create(self, new_children):
  635. """Creates a new instruction of this type from the given sequence of child instructions."""
  636. raise NotImplementedError()
  637. def create_load(self):
  638. """Creates an instruction that loads the variable referenced by this instruction."""
  639. return LoadLocalInstruction(self.name)
  640. def create_store(self, value):
  641. """Creates an instruction that stores the given value in the variable referenced
  642. by this instruction."""
  643. return StoreLocalInstruction(self.name, value)
  644. class StoreLocalInstruction(LocalInstruction):
  645. """An instruction that stores a value in a local variable."""
  646. def __init__(self, name, value):
  647. LocalInstruction.__init__(self, name)
  648. self.value = value
  649. def get_children(self):
  650. """Gets this instruction's sequence of child instructions."""
  651. return [self.value]
  652. def create(self, new_children):
  653. """Creates a new instruction of this type from the given sequence of child instructions."""
  654. val, = new_children
  655. return StoreLocalInstruction(self.name, val)
  656. def generate_python_def(self, code_generator):
  657. """Generates a Python statement that executes this instruction.
  658. The statement is appended immediately to the code generator."""
  659. code_generator.append_move_definition(self, self.value)
  660. class LoadLocalInstruction(LocalInstruction):
  661. """An instruction that loads a value from a local variable."""
  662. def has_definition_impl(self):
  663. """Tells if this instruction requires a definition."""
  664. return False
  665. def get_children(self):
  666. """Gets this instruction's sequence of child instructions."""
  667. return []
  668. def create(self, new_children):
  669. """Creates a new instruction of this type from the given sequence of child instructions."""
  670. return self
  671. class DefineFunctionInstruction(VariableInstruction):
  672. """An instruction that defines a function."""
  673. def __init__(self, name, parameter_list, body):
  674. VariableInstruction.__init__(self, name)
  675. self.parameter_list = parameter_list
  676. self.body = body
  677. def get_children(self):
  678. """Gets this instruction's sequence of child instructions."""
  679. return [self.body]
  680. def create(self, new_children):
  681. """Creates a new instruction of this type from the given sequence of child instructions."""
  682. body, = new_children
  683. return DefineFunctionInstruction(self.name, self.parameter_list, body)
  684. def generate_python_def(self, code_generator):
  685. """Generates a Python statement that executes this instruction.
  686. The statement is appended immediately to the code generator."""
  687. code_generator.append_line('def %s(%s):' % (
  688. code_generator.get_result_name(self), ', '.join(self.parameter_list)))
  689. code_generator.increase_indentation()
  690. self.body.generate_python_def(code_generator)
  691. code_generator.decrease_indentation()
  692. class LocalExistsInstruction(LocalInstruction):
  693. """An instruction that checks if a local variable exists."""
  694. def has_definition_impl(self):
  695. """Tells if this instruction requires a definition."""
  696. return False
  697. def get_children(self):
  698. """Gets this instruction's sequence of child instructions."""
  699. return []
  700. def create(self, new_children):
  701. """Creates a new instruction of this type from the given sequence of child instructions."""
  702. return self
  703. def generate_python_use(self, code_generator):
  704. """Generates a Python expression that retrieves this instruction's
  705. result. The expression is returned as a string."""
  706. return "'%s' in locals()" % self.get_result_name_override(code_generator)
  707. class LoadGlobalInstruction(VariableInstruction):
  708. """An instruction that loads a value from a global variable."""
  709. def has_definition_impl(self):
  710. """Tells if this instruction requires a definition."""
  711. return False
  712. def get_children(self):
  713. """Gets this instruction's sequence of child instructions."""
  714. return []
  715. def create(self, new_children):
  716. """Creates a new instruction of this type from the given sequence of child instructions."""
  717. return self
  718. class LoadIndexInstruction(Instruction):
  719. """An instruction that produces a value by indexing a specified expression with
  720. a given key."""
  721. def __init__(self, indexed, key):
  722. Instruction.__init__(self)
  723. self.indexed = indexed
  724. self.key = key
  725. def has_definition_impl(self):
  726. """Tells if this instruction requires a definition."""
  727. return False
  728. def get_children(self):
  729. """Gets this instruction's sequence of child instructions."""
  730. return [self.indexed, self.key]
  731. def create(self, new_children):
  732. """Creates a new instruction of this type from the given sequence of child instructions."""
  733. indexed, key = new_children
  734. return LoadIndexInstruction(indexed, key)
  735. def generate_python_use(self, code_generator):
  736. """Generates a Python expression that retrieves this instruction's
  737. result. The expression is returned as a string."""
  738. if self.indexed.has_definition():
  739. self.indexed.generate_python_def(code_generator)
  740. if self.key.has_definition():
  741. self.key.generate_python_def(code_generator)
  742. return "%s[%s]" % (
  743. self.indexed.generate_python_use(code_generator),
  744. self.key.generate_python_use(code_generator))
  745. class LoadMemberInstruction(Instruction):
  746. """An instruction that produces a value by loading a member from a container."""
  747. def __init__(self, container, member_name):
  748. Instruction.__init__(self)
  749. self.container = container
  750. self.member_name = member_name
  751. def has_definition_impl(self):
  752. """Tells if this instruction requires a definition."""
  753. return self.container.has_definition()
  754. def get_children(self):
  755. """Gets this instruction's sequence of child instructions."""
  756. return [self.container]
  757. def create(self, new_children):
  758. """Creates a new instruction of this type from the given sequence of child instructions."""
  759. container, = new_children
  760. return LoadMemberInstruction(container, self.member_name)
  761. def generate_python_def(self, code_generator):
  762. """Generates a Python statement that executes this instruction.
  763. The statement is appended immediately to the code generator."""
  764. self.container.generate_python_def(code_generator)
  765. def generate_python_use(self, code_generator):
  766. """Generates a Python expression that retrieves this instruction's
  767. result. The expression is returned as a string."""
  768. return "%s.%s" % (
  769. self.container.generate_python_use(code_generator),
  770. self.member_name)
  771. class StoreMemberInstruction(Instruction):
  772. """An instruction that stores a value in a container member."""
  773. def __init__(self, container, member_name, value):
  774. Instruction.__init__(self)
  775. self.container = container
  776. self.member_name = member_name
  777. self.value = value
  778. def has_definition_impl(self):
  779. """Tells if this instruction requires a definition."""
  780. return True
  781. def has_result_impl(self):
  782. """Tells if this instruction computes a result."""
  783. return False
  784. def get_children(self):
  785. """Gets this instruction's sequence of child instructions."""
  786. return [self.container, self.value]
  787. def create(self, new_children):
  788. """Creates a new instruction of this type from the given sequence of child instructions."""
  789. container, value = new_children
  790. return StoreMemberInstruction(container, self.member_name, value)
  791. def generate_python_def(self, code_generator):
  792. """Generates a Python statement that executes this instruction.
  793. The statement is appended immediately to the code generator."""
  794. if self.container.has_definition():
  795. self.container.generate_python_def(code_generator)
  796. code_generator.append_line('%s.%s = %s' % (
  797. self.container.generate_python_use(code_generator),
  798. self.member_name,
  799. self.value.generate_python_use(code_generator)))
  800. class NopInstruction(Instruction):
  801. """A nop instruction, which allows for the kernel's thread of execution to be interrupted."""
  802. def has_result_impl(self):
  803. """Tells if this instruction computes a result."""
  804. return False
  805. def get_children(self):
  806. """Gets this instruction's sequence of child instructions."""
  807. return []
  808. def create(self, new_children):
  809. """Creates a new instruction of this type from the given sequence of child instructions."""
  810. return self
  811. def generate_python_def(self, code_generator):
  812. """Generates a Python statement that executes this instruction.
  813. The statement is appended immediately to the code generator."""
  814. code_generator.append_line('yield %s' % repr(NOP_LITERAL))
  815. class ReadValueInstruction(StateInstruction):
  816. """An instruction that reads a value from a node."""
  817. def __init__(self, node_id):
  818. StateInstruction.__init__(self)
  819. self.node_id = node_id
  820. def simplify_node(self):
  821. """Applies basic simplification to this instruction only."""
  822. if isinstance(self.node_id, CreateNodeWithValueInstruction):
  823. return self.node_id.value
  824. else:
  825. return self
  826. def get_opcode(self):
  827. """Gets the opcode for this state instruction."""
  828. return "RV"
  829. def get_arguments(self):
  830. """Gets this state instruction's argument list."""
  831. return [self.node_id]
  832. class ReadDictionaryValueInstruction(StateInstruction):
  833. """An instruction that reads a dictionary value."""
  834. def __init__(self, node_id, key):
  835. StateInstruction.__init__(self)
  836. self.node_id = node_id
  837. self.key = key
  838. def get_opcode(self):
  839. """Gets the opcode for this state instruction."""
  840. return "RD"
  841. def get_arguments(self):
  842. """Gets this state instruction's argument list."""
  843. return [self.node_id, self.key]
  844. class ReadDictionaryEdgeInstruction(StateInstruction):
  845. """An instruction that reads a dictionary edge."""
  846. def __init__(self, node_id, key):
  847. StateInstruction.__init__(self)
  848. self.node_id = node_id
  849. self.key = key
  850. def get_opcode(self):
  851. """Gets the opcode for this state instruction."""
  852. return "RDE"
  853. def get_arguments(self):
  854. """Gets this state instruction's argument list."""
  855. return [self.node_id, self.key]
  856. class ReadEdgeInstruction(StateInstruction):
  857. """An instruction that reads an edge."""
  858. def __init__(self, node_id):
  859. StateInstruction.__init__(self)
  860. self.node_id = node_id
  861. def get_opcode(self):
  862. """Gets the opcode for this state instruction."""
  863. return "RE"
  864. def get_arguments(self):
  865. """Gets this state instruction's argument list."""
  866. return [self.node_id]
  867. class CreateNodeInstruction(StateInstruction):
  868. """An instruction that creates an empty node."""
  869. def get_opcode(self):
  870. """Gets the opcode for this state instruction."""
  871. return "CN"
  872. def get_arguments(self):
  873. """Gets this state instruction's argument list."""
  874. return []
  875. class CreateNodeWithValueInstruction(StateInstruction):
  876. """An instruction that creates a node with a given value."""
  877. def __init__(self, value):
  878. StateInstruction.__init__(self)
  879. self.value = value
  880. def get_opcode(self):
  881. """Gets the opcode for this state instruction."""
  882. return "CNV"
  883. def get_arguments(self):
  884. """Gets this state instruction's argument list."""
  885. return [self.value]
  886. class CreateEdgeInstruction(StateInstruction):
  887. """An instruction that creates an edge."""
  888. def __init__(self, source_id, target_id):
  889. StateInstruction.__init__(self)
  890. self.source_id = source_id
  891. self.target_id = target_id
  892. def get_opcode(self):
  893. """Gets the opcode for this state instruction."""
  894. return "CE"
  895. def get_arguments(self):
  896. """Gets this state instruction's argument list."""
  897. return [self.source_id, self.target_id]
  898. class CreateDictionaryEdgeInstruction(StateInstruction):
  899. """An instruction that creates a dictionary edge."""
  900. def __init__(self, source_id, key, target_id):
  901. StateInstruction.__init__(self)
  902. self.source_id = source_id
  903. self.key = key
  904. self.target_id = target_id
  905. def get_opcode(self):
  906. """Gets the opcode for this state instruction."""
  907. return "CD"
  908. def get_arguments(self):
  909. """Gets this state instruction's argument list."""
  910. return [self.source_id, self.key, self.target_id]
  911. class DeleteNodeInstruction(StateInstruction):
  912. """An instruction that deletes a node."""
  913. def __init__(self, node_id):
  914. StateInstruction.__init__(self)
  915. self.node_id = node_id
  916. def has_result(self):
  917. """Tells if this instruction computes a result."""
  918. return False
  919. def get_opcode(self):
  920. """Gets the opcode for this state instruction."""
  921. return "DN"
  922. def get_arguments(self):
  923. """Gets this state instruction's argument list."""
  924. return [self.node_id]
  925. class DeleteEdgeInstruction(StateInstruction):
  926. """An instruction that deletes an edge."""
  927. def __init__(self, edge_id):
  928. StateInstruction.__init__(self)
  929. self.edge_id = edge_id
  930. def has_result(self):
  931. """Tells if this instruction computes a result."""
  932. return False
  933. def get_opcode(self):
  934. """Gets the opcode for this state instruction."""
  935. return "DE"
  936. def get_arguments(self):
  937. """Gets this state instruction's argument list."""
  938. return [self.edge_id]
  939. def create_block(*statements):
  940. """Creates a block-statement from the given list of statements."""
  941. length = len(statements)
  942. if length == 0:
  943. return EmptyInstruction()
  944. elif length == 1:
  945. return statements[0]
  946. else:
  947. return CompoundInstruction(
  948. statements[0],
  949. create_block(*statements[1:]))
  950. def with_debug_info_trace(instruction, debug_info, function_name):
  951. """Prepends the given instruction with a tracing instruction that prints
  952. the given debug information and function name."""
  953. if debug_info is None and function_name is None:
  954. return instruction
  955. else:
  956. if debug_info is None:
  957. debug_info = 'unknown location'
  958. if function_name is None:
  959. function_name = 'unknown function'
  960. return create_block(
  961. PrintInstruction(
  962. LiteralInstruction('TRACE: %s(%s, JIT)' % (debug_info, function_name))),
  963. instruction)
  964. def map_and_simplify(function, instruction):
  965. """Applies the given mapping function to every instruction in the tree
  966. that has the given instruction as root, and simplifies it on-the-fly.
  967. This is at least as powerful as first mapping and then simplifying, as
  968. maps and simplifications are interspersed."""
  969. # Let's just agree to disagree on map vs list comprehensions, pylint.
  970. # pylint: disable=I0011,W0141
  971. return function(
  972. instruction.create(
  973. map(map_and_simplify, instruction.get_children()))).simplify_node()
  974. if __name__ == "__main__":
  975. example_tree = SelectInstruction(
  976. LiteralInstruction(True),
  977. LoopInstruction(
  978. CompoundInstruction(
  979. BreakInstruction(),
  980. CompoundInstruction(
  981. EmptyInstruction(),
  982. ContinueInstruction()
  983. )
  984. )
  985. ),
  986. ReturnInstruction(
  987. EmptyInstruction()))
  988. print(example_tree.simplify())