cfg_to_tree.py 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610
  1. """Lowers CFG-IR to tree-IR."""
  2. import modelverse_jit.cfg_ir as cfg_ir
  3. import modelverse_jit.cfg_optimization as cfg_optimization
  4. import modelverse_jit.tree_ir as tree_ir
  5. import modelverse_jit.runtime as jit_runtime
  6. import modelverse_jit.bytecode_to_tree as bytecode_to_tree
  7. # The CFG deconstruction code here is based on the relooper algorithm
  8. # as detailed in https://github.com/kripken/Relooper/blob/master/paper.pdf
  9. class FlowGraphComponent(object):
  10. """Represents a control-flow graph component."""
  11. def __init__(self, entry_blocks, blocks, reachable):
  12. self.entry_blocks = entry_blocks
  13. self.blocks = blocks
  14. self.reachable = reachable
  15. def get_entry_reachable_blocks(self):
  16. """Gets the set of all blocks that are reachable from the entry points."""
  17. return set.union(*[self.get_reachable_blocks(block) for block in self.entry_blocks])
  18. def get_reachable_blocks(self, block):
  19. """Gets all blocks in this component that are reachable from the given block."""
  20. return set.intersection(self.reachable[block], self.blocks)
  21. def get_directly_reachable_blocks(self, block):
  22. """Gets all blocks in this component that are reachable from the given block by taking
  23. exactly one branch."""
  24. return set.intersection(cfg_optimization.get_directly_reachable_blocks(block), self.blocks)
  25. def can_reach(self, source_block, target_block):
  26. """Tests if the first block can reach the second."""
  27. return target_block in self.reachable[source_block] and target_block in self.blocks
  28. def sub_component(self, new_entry_points):
  29. """Creates a sub-component of this component, with the given new entry points."""
  30. result = FlowGraphComponent(new_entry_points, self.blocks, self.reachable)
  31. result.blocks = result.get_entry_reachable_blocks()
  32. return result
  33. def create_graph_component(entry_point):
  34. """Creates a flow graph component from the given entry point."""
  35. reachable = cfg_optimization.get_all_reachable_blocks(entry_point)
  36. all_blocks = set(reachable[entry_point])
  37. all_blocks.add(entry_point)
  38. return FlowGraphComponent([entry_point], all_blocks, reachable)
  39. class SimpleBlock(object):
  40. """A 'simple' block in the relooper algorithm."""
  41. def __init__(self, body, next_block):
  42. self.body = body
  43. self.next_block = next_block
  44. def lower(self, state):
  45. """Lowers this 'simple' block to a tree."""
  46. return tree_ir.create_block(
  47. state.lower_block(self.body),
  48. self.next_block.lower(state))
  49. class EmptyBlock(object):
  50. """An empty relooper block."""
  51. def lower(self, _):
  52. """Lowers this empty block to a tree."""
  53. return tree_ir.EmptyInstruction()
  54. class LoopBlock(object):
  55. """A 'loop' block in the relooper algorithm."""
  56. def __init__(self, inner, next_block):
  57. self.inner = inner
  58. self.next_block = next_block
  59. def lower(self, state):
  60. """Lowers this 'loop' block to a tree."""
  61. inner = tree_ir.LoopInstruction(
  62. tree_ir.create_block(
  63. self.inner.lower(state),
  64. tree_ir.BreakInstruction()))
  65. return tree_ir.create_block(
  66. inner,
  67. self.next_block.lower(state))
  68. class MultipleBlock(object):
  69. """A 'multiple' block in the relooper algorithm that does _not_ require a loop."""
  70. def __init__(self, handled_blocks, next_block):
  71. self.handled_blocks = handled_blocks
  72. self.next_block = next_block
  73. def lower_handled_blocks(self, state):
  74. """Lowers the handled blocks of this 'multiple' block to a tree."""
  75. result = tree_ir.EmptyInstruction()
  76. for entry, block in self.handled_blocks:
  77. result = tree_ir.SelectInstruction(
  78. tree_ir.BinaryInstruction(
  79. tree_ir.LoadLocalInstruction(state.label_variable),
  80. '==',
  81. tree_ir.LiteralInstruction(entry.index)),
  82. block.lower(state),
  83. result)
  84. return result
  85. def lower(self, state):
  86. """Lowers this 'multiple' block to a tree."""
  87. return tree_ir.create_block(
  88. self.lower_handled_blocks(state),
  89. self.next_block.lower(state))
  90. class MultipleLoopBlock(MultipleBlock):
  91. """A 'multiple' block in the relooper algorithm."""
  92. def __init__(self, handled_blocks, next_block):
  93. MultipleBlock.__init__(self, handled_blocks, next_block)
  94. def lower(self, state):
  95. """Lowers this 'multiple' block to a tree."""
  96. inner = tree_ir.LoopInstruction(
  97. tree_ir.create_block(
  98. self.lower_handled_blocks(state),
  99. tree_ir.BreakInstruction()))
  100. return tree_ir.create_block(
  101. inner,
  102. self.next_block.lower(state))
  103. class ContinueFlow(cfg_ir.FlowInstruction):
  104. """Represents a control flow instruction which continues to the next loop iteration."""
  105. def __init__(self, loop):
  106. cfg_ir.FlowInstruction.__init__(self)
  107. self.loop = loop
  108. def get_dependencies(self):
  109. """Gets all definitions and instructions on which this instruction depends."""
  110. return []
  111. def branches(self):
  112. """Gets a list of basic blocks targeted by this flow instruction."""
  113. return []
  114. def __str__(self):
  115. return 'continue'
  116. class BreakFlow(cfg_ir.FlowInstruction):
  117. """Represents a control flow instruction which breaks out of a loop."""
  118. def __init__(self, loop):
  119. cfg_ir.FlowInstruction.__init__(self)
  120. self.loop = loop
  121. def get_dependencies(self):
  122. """Gets all definitions and instructions on which this instruction depends."""
  123. return []
  124. def branches(self):
  125. """Gets a list of basic blocks targeted by this flow instruction."""
  126. return []
  127. def __str__(self):
  128. return 'break'
  129. def solipsize(graph_component, loop, entry_blocks, next_blocks):
  130. """Replaces branches to entry blocks and next blocks by jumps to 'continue' and 'break'
  131. blocks, respectively."""
  132. all_blocks = set()
  133. reachable_from_inner = set()
  134. for block in graph_component.blocks:
  135. if block in next_blocks:
  136. continue
  137. all_blocks.add(block)
  138. for branch in block.flow.branches():
  139. if branch.block in entry_blocks:
  140. # Create a 'continue' block, and point to that.
  141. continue_block = cfg_ir.BasicBlock(block.counter)
  142. for param in branch.block.parameters:
  143. continue_block.append_parameter(param)
  144. continue_block.flow = ContinueFlow(loop)
  145. branch.block = continue_block
  146. all_blocks.add(continue_block)
  147. elif branch.block in next_blocks:
  148. # Create a 'break' block, and point to that.
  149. break_block = cfg_ir.BasicBlock(block.counter)
  150. for param in branch.block.parameters:
  151. break_block.append_parameter(param)
  152. break_block.flow = BreakFlow(loop)
  153. branch.block = break_block
  154. all_blocks.add(break_block)
  155. reachable_from_inner.add(branch.block)
  156. return reachable_from_inner, FlowGraphComponent(
  157. graph_component.entry_blocks,
  158. all_blocks,
  159. {
  160. block : cfg_optimization.get_reachable_blocks(block)
  161. for block in all_blocks
  162. })
  163. def to_relooper_loop(graph_component):
  164. """Converts the given graph component to a relooper 'loop'."""
  165. entry_blocks = graph_component.entry_blocks
  166. result = LoopBlock(None, None)
  167. inner_blocks = []
  168. next_blocks = []
  169. for block in graph_component.blocks:
  170. if any([graph_component.can_reach(block, ep) for ep in entry_blocks]):
  171. inner_blocks.append(block)
  172. else:
  173. next_blocks.append(block)
  174. reachable_from_inner, inner_component = solipsize(
  175. graph_component, result, entry_blocks, next_blocks)
  176. result.inner = reloop(inner_component)
  177. next_component = FlowGraphComponent(
  178. reachable_from_inner, next_blocks, graph_component.reachable)
  179. result.next_block = reloop(next_component)
  180. return result
  181. def to_relooper_multiple_or_loop(graph_component):
  182. """Converts the given graph component to a relooper 'multiple' or 'loop'."""
  183. # From the Emscripten paper:
  184. #
  185. # If we have more than one entry, try to create a Multiple block:
  186. # For each entry, find all the labels it reaches that
  187. # cannot be reached by any other entry. If at least one entry
  188. # has such labels, return a Multiple block, whose Handled
  189. # blocks are blocks for those labels (and whose entries are
  190. # those labels), and whose Next block is all the rest. Entries
  191. # for the next block are entries that did not become part of
  192. # the Handled blocks, and also labels that can be reached
  193. # from the Handled blocks.
  194. entry_blocks = graph_component.entry_blocks
  195. if len(entry_blocks) <= 1:
  196. return to_relooper_loop(graph_component)
  197. entry_reachables = {ep : graph_component.get_reachable_blocks(ep) for ep in entry_blocks}
  198. exclusive_entries = {}
  199. for entry in entry_blocks:
  200. exclusive_blocks = set(entry_reachables[entry])
  201. for other_entry in entry_blocks:
  202. if other_entry != entry:
  203. exclusive_blocks.difference_update(entry_reachables[other_entry])
  204. if len(exclusive_blocks) > 0:
  205. exclusive_entries[entry] = exclusive_blocks
  206. if len(exclusive_entries) == 0:
  207. return to_relooper_loop(graph_component)
  208. next_entries = set(graph_component.entry_blocks)
  209. for block_set in exclusive_entries.values():
  210. for elem in block_set:
  211. directly_reachable = graph_component.get_directly_reachable_blocks(elem)
  212. directly_reachable.remove(elem)
  213. next_entries.update(directly_reachable)
  214. next_entries.difference_update(exclusive_entries.keys())
  215. result = MultipleLoopBlock({}, None)
  216. for entry, exclusive_blocks in exclusive_entries.items():
  217. other_blocks = set(graph_component.blocks)
  218. other_blocks.difference_update(exclusive_blocks)
  219. result.handled_blocks[entry] = reloop(
  220. solipsize(graph_component, result, set([entry]), other_blocks))
  221. result.next_block = reloop(graph_component.sub_component(next_entries))
  222. return result
  223. def reloop(graph_component):
  224. """Applies the relooper algorithm to the given graph component."""
  225. entry_blocks = graph_component.entry_blocks
  226. if len(entry_blocks) == 0:
  227. return EmptyBlock()
  228. reachable_set = graph_component.get_entry_reachable_blocks()
  229. if len(entry_blocks) == 1 and entry_blocks[0] not in reachable_set:
  230. graph_component.blocks.remove(entry_blocks[0])
  231. return SimpleBlock(
  232. entry_blocks[0],
  233. reloop(
  234. FlowGraphComponent(
  235. graph_component.get_directly_reachable_blocks(entry_blocks[0]),
  236. graph_component.blocks,
  237. graph_component.reachable)))
  238. elif all([block in reachable_set for block in entry_blocks]):
  239. return to_relooper_loop(graph_component)
  240. else:
  241. return to_relooper_multiple_or_loop(graph_component)
  242. def reloop_trivial(graph_component):
  243. """Converts the given control-flow graph to a 'multiple' block that contains only 'simple'
  244. blocks."""
  245. return MultipleLoopBlock(
  246. [(block, SimpleBlock(block, EmptyBlock())) for block in graph_component.blocks],
  247. EmptyBlock())
  248. def reloop_function_body(entry_point):
  249. """Reloops the control-flow graph defined by the given entry point."""
  250. return reloop_trivial(create_graph_component(entry_point))
  251. class LoweringState(object):
  252. """Stores information related to the relooper->tree conversion."""
  253. def __init__(self, jit):
  254. self.jit = jit
  255. self.label_variable = tree_ir.VariableName('__label')
  256. self.definition_loads = {}
  257. self.local_name_map = bytecode_to_tree.LocalNameMap()
  258. self.root_edge_names = {}
  259. def __get_root_edge_name(self, root_node):
  260. """Gets the name of the given root edge's variable."""
  261. return self.__get_root_node_name(root_node) + '_edge'
  262. def __get_root_node_name(self, root_node):
  263. """Gets the name of the given root node's variable."""
  264. if isinstance(root_node, cfg_ir.Definition):
  265. return self.__get_root_edge_name(root_node.value)
  266. if root_node in self.root_edge_names:
  267. return self.root_edge_names[root_node]
  268. result = 'jit_locals%d' % len(self.root_edge_names)
  269. self.root_edge_names[root_node] = result
  270. return result
  271. def __create_value_load(self, value):
  272. """Creates a tree that loads the given value."""
  273. if value.has_value():
  274. if isinstance(value, cfg_ir.Literal):
  275. return self.lower_literal(value)
  276. else:
  277. return tree_ir.LoadLocalInstruction(None)
  278. else:
  279. return tree_ir.LiteralInstruction(None)
  280. def load_definition(self, definition):
  281. """Loads the given definition's variable."""
  282. if definition in self.definition_loads:
  283. return self.definition_loads[definition]
  284. if isinstance(definition.value, cfg_ir.Definition):
  285. result = self.load_definition(definition.value)
  286. else:
  287. result = self.__create_value_load(definition.value)
  288. self.definition_loads[definition] = result
  289. return result
  290. def lower_block(self, block):
  291. """Lowers the given (relooped) block to a tree."""
  292. statements = []
  293. for definition in block.definitions:
  294. statements.append(self.lower_definition(definition))
  295. statements.append(self.lower_flow(block.flow))
  296. return tree_ir.create_block(*statements)
  297. def lower_definition(self, definition):
  298. """Lowers the given definition to a tree."""
  299. if isinstance(definition.value, cfg_ir.Definition):
  300. return tree_ir.EmptyInstruction()
  301. instruction = definition.value
  302. tree_instruction = self.lower_value(instruction)
  303. def_load = self.load_definition(definition)
  304. if isinstance(def_load, tree_ir.LocalInstruction):
  305. return def_load.create_store(tree_instruction)
  306. else:
  307. return tree_instruction
  308. def lower_value(self, value):
  309. """Lowers the given instruction to a tree."""
  310. value_type = type(value)
  311. if value_type in LoweringState.value_lowerings:
  312. return LoweringState.value_lowerings[value_type](self, value)
  313. else:
  314. raise jit_runtime.JitCompilationFailedException(
  315. "Unknown CFG instruction: '%s'" % value)
  316. def lower_literal(self, value):
  317. """Lowers the given literal value."""
  318. return tree_ir.LiteralInstruction(value.literal)
  319. def lower_check_local_exists(self, value):
  320. """Lowers a 'check-value-exists' value."""
  321. return tree_ir.LocalExistsInstruction(
  322. self.local_name_map.get_local_name(value.variable.node_id))
  323. def lower_declare_local(self, value):
  324. """Lowers a 'declare-local' value."""
  325. local_name = self.local_name_map.get_local_name(value.variable.node_id)
  326. return tree_ir.create_block(
  327. tree_ir.create_new_local_node(
  328. local_name,
  329. self.load_definition(value.root_node)),
  330. tree_ir.LoadLocalInstruction(local_name))
  331. def lower_resolve_local(self, value):
  332. """Lowers a 'resolve-local' value."""
  333. return tree_ir.LoadLocalInstruction(
  334. self.local_name_map.get_local_name(value.variable.node_id))
  335. def lower_declare_global(self, value):
  336. """Lowers a 'declare-global' value."""
  337. #
  338. # global_var, = yield [("CN", [])]
  339. # _globals, = yield [("RD", [task_root, "globals"])]
  340. # yield [("CD", [_globals, var_name, global_var])]
  341. #
  342. task_root = bytecode_to_tree.retrieve_task_root()
  343. global_var = tree_ir.StoreLocalInstruction(None, tree_ir.CreateNodeInstruction())
  344. return tree_ir.create_block(
  345. global_var.create_store(
  346. tree_ir.CreateNodeInstruction()),
  347. tree_ir.CreateDictionaryEdgeInstruction(
  348. tree_ir.ReadDictionaryValueInstruction(
  349. task_root.create_load(),
  350. tree_ir.LiteralInstruction('globals')),
  351. tree_ir.LiteralInstruction(
  352. value.variable.name),
  353. global_var.create_load()),
  354. global_var.create_load())
  355. def lower_resolve_global(self, value):
  356. """Lowers a 'resolve-global' value."""
  357. #
  358. # _globals, = yield [("RD", [task_root, "globals"])]
  359. # global_var, = yield [("RD", [_globals, var_name])]
  360. #
  361. task_root = bytecode_to_tree.retrieve_task_root()
  362. return tree_ir.ReadDictionaryValueInstruction(
  363. tree_ir.ReadDictionaryValueInstruction(
  364. task_root.create_load(),
  365. tree_ir.LiteralInstruction('globals')),
  366. tree_ir.LiteralInstruction(value.variable.name))
  367. def lower_function_parameter(self, value):
  368. """Lowers a 'function-parameter' value."""
  369. return tree_ir.LoadLocalInstruction(value.name)
  370. def lower_alloc_root_node(self, value):
  371. """Lowers an 'alloc-root-node' value."""
  372. local_name = tree_ir.VariableName(self.__get_root_node_name(value))
  373. return tree_ir.create_block(
  374. tree_ir.create_new_local_node(
  375. local_name,
  376. tree_ir.LoadIndexInstruction(
  377. tree_ir.LoadLocalInstruction(jit_runtime.KWARGS_PARAMETER_NAME),
  378. tree_ir.LiteralInstruction('task_root')),
  379. self.__get_root_edge_name(value)),
  380. tree_ir.LoadLocalInstruction(local_name))
  381. def lower_free_root_node(self, value):
  382. """Lowers a 'free-root-node' value."""
  383. return tree_ir.DeleteEdgeInstruction(
  384. tree_ir.LoadLocalInstruction(self.__get_root_edge_name(value.root_node)))
  385. def lower_load_pointer(self, value):
  386. """Lowers a 'load' value."""
  387. return bytecode_to_tree.create_access(self.load_definition(value.pointer))
  388. def lower_store_pointer(self, value):
  389. """Lowers a 'store' value."""
  390. return bytecode_to_tree.create_assign(
  391. self.load_definition(value.pointer), self.load_definition(value.value))
  392. def lower_read(self, value):
  393. """Lowers a 'read' value."""
  394. return tree_ir.ReadValueInstruction(
  395. self.load_definition(value.node))
  396. def lower_create_node(self, value):
  397. """Lowers a 'create-node' value."""
  398. if value.value.has_value():
  399. return tree_ir.CreateNodeWithValueInstruction(
  400. self.load_definition(value.value))
  401. else:
  402. return tree_ir.CreateNodeInstruction()
  403. def lower_binary(self, value):
  404. """Lowers a 'binary' value."""
  405. return tree_ir.BinaryInstruction(
  406. self.load_definition(value.lhs),
  407. value.operator,
  408. self.load_definition(value.rhs))
  409. def lower_input(self, _):
  410. """Lowers an 'input' value."""
  411. return bytecode_to_tree.create_input(self.jit.use_input_function)
  412. def lower_output(self, value):
  413. """Lowers an 'output' value."""
  414. return bytecode_to_tree.create_output(self.load_definition(value.value))
  415. def lower_direct_call(self, value):
  416. """Lowers a direct function call."""
  417. calling_convention = value.calling_convention
  418. if calling_convention in LoweringState.call_lowerings:
  419. return LoweringState.call_lowerings[calling_convention](self, value)
  420. else:
  421. raise jit_runtime.JitCompilationFailedException(
  422. "Unknown calling convention: '%s' in instruction '%s'" %
  423. (calling_convention, value))
  424. def lower_indirect_call(self, value):
  425. """Lowers an indirect function call."""
  426. return bytecode_to_tree.create_indirect_call(
  427. self.load_definition(value.target),
  428. [(name, self.load_definition(arg)) for name, arg in value.argument_list])
  429. value_lowerings = {
  430. cfg_ir.Literal : lower_literal,
  431. cfg_ir.CheckLocalExists : lower_check_local_exists,
  432. cfg_ir.DeclareLocal : lower_declare_local,
  433. cfg_ir.ResolveLocal : lower_resolve_local,
  434. cfg_ir.DeclareGlobal : lower_declare_global,
  435. cfg_ir.ResolveGlobal : lower_resolve_global,
  436. cfg_ir.FunctionParameter : lower_function_parameter,
  437. cfg_ir.AllocateRootNode : lower_alloc_root_node,
  438. cfg_ir.DeallocateRootNode : lower_free_root_node,
  439. cfg_ir.LoadPointer : lower_load_pointer,
  440. cfg_ir.StoreAtPointer : lower_store_pointer,
  441. cfg_ir.Read : lower_read,
  442. cfg_ir.CreateNode : lower_create_node,
  443. cfg_ir.Binary : lower_binary,
  444. cfg_ir.Input : lower_input,
  445. cfg_ir.Output : lower_output,
  446. cfg_ir.DirectFunctionCall : lower_direct_call,
  447. cfg_ir.IndirectFunctionCall : lower_indirect_call
  448. }
  449. def lower_simple_positional_call(self, value):
  450. """Lowers a direct call that uses the 'simple-positional' calling convention."""
  451. return tree_ir.CallInstruction(
  452. tree_ir.LoadGlobalInstruction(value.target_name),
  453. [self.load_definition(arg) for _, arg in value.argument_list])
  454. def lower_jit_call(self, value):
  455. """Lowers a direct call that uses the 'jit' calling convention."""
  456. arg_list = [(name, self.load_definition(arg)) for name, arg in value.argument_list]
  457. intrinsic = self.jit.get_intrinsic(value.target_name)
  458. if intrinsic is not None:
  459. return bytecode_to_tree.apply_intrinsic(intrinsic, arg_list)
  460. else:
  461. return tree_ir.create_jit_call(
  462. tree_ir.LoadGlobalInstruction(value.target_name),
  463. arg_list,
  464. tree_ir.LoadLocalInstruction(jit_runtime.KWARGS_PARAMETER_NAME))
  465. call_lowerings = {
  466. cfg_ir.SIMPLE_POSITIONAL_CALLING_CONVENTION : lower_simple_positional_call,
  467. cfg_ir.JIT_CALLING_CONVENTION : lower_jit_call
  468. }
  469. def lower_flow(self, flow):
  470. """Lowers the given (relooped) flow instruction to a tree."""
  471. flow_type = type(flow)
  472. if flow_type in LoweringState.flow_lowerings:
  473. return LoweringState.flow_lowerings[flow_type](self, flow)
  474. else:
  475. raise jit_runtime.JitCompilationFailedException(
  476. "Unknown CFG flow instruction: '%s'" % flow)
  477. def lower_jump(self, flow):
  478. """Lowers the given 'jump' flow instruction to a tree."""
  479. return self.lower_branch(flow.branch)
  480. def lower_select(self, flow):
  481. """Lowers the given 'select' flow instruction to a tree."""
  482. return tree_ir.SelectInstruction(
  483. self.load_definition(flow.condition),
  484. self.lower_branch(flow.if_branch),
  485. self.lower_branch(flow.else_branch))
  486. def lower_return(self, flow):
  487. """Lowers the given 'return' flow instruction to a tree."""
  488. return tree_ir.ReturnInstruction(self.load_definition(flow.value))
  489. def lower_throw(self, flow):
  490. """Lowers the given 'throw' flow instruction to a tree."""
  491. return tree_ir.RaiseInstruction(self.load_definition(flow.exception))
  492. def lower_unreachable(self, _):
  493. """Lowers the given 'unreachable' flow instruction to a tree."""
  494. return tree_ir.EmptyInstruction()
  495. def lower_break(self, _):
  496. """Lowers the given 'break' flow instruction to a tree."""
  497. return tree_ir.BreakInstruction()
  498. def lower_continue(self, _):
  499. """Lowers the given 'continue' flow instruction to a tree."""
  500. return tree_ir.ContinueInstruction()
  501. def lower_branch(self, branch):
  502. """Lowers the given (relooped) branch to a tree."""
  503. for param, arg in zip(branch.block.parameters, branch.arguments):
  504. self.load_definition(param).create_store(self.load_definition(arg))
  505. return tree_ir.StoreLocalInstruction(
  506. self.label_variable,
  507. tree_ir.LiteralInstruction(branch.block.index))
  508. flow_lowerings = {
  509. cfg_ir.JumpFlow : lower_jump,
  510. cfg_ir.SelectFlow : lower_select,
  511. cfg_ir.ReturnFlow : lower_return,
  512. cfg_ir.ThrowFlow : lower_throw,
  513. cfg_ir.UnreachableFlow : lower_unreachable,
  514. BreakFlow : lower_break,
  515. ContinueFlow : lower_continue
  516. }