cfg_ir.py 43 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144
  1. """Defines control flow graph IR data structures."""
  2. from collections import defaultdict
  3. # Let's just agree to disagree on map vs list comprehensions, pylint.
  4. # pylint: disable=I0011,W0141
  5. class SharedCounter(object):
  6. """Defines a shared counter."""
  7. def __init__(self):
  8. self.index = 0
  9. def next_value(self):
  10. """Gets the next value for this counter."""
  11. result = self.index
  12. self.index += 1
  13. return result
  14. class BasicBlock(object):
  15. """Represents a basic block."""
  16. def __init__(self, counter):
  17. self.parameters = []
  18. self.definitions = []
  19. self.counter = counter
  20. self.index = counter.next_value()
  21. self.definition_counter = SharedCounter()
  22. self.flow = UnreachableFlow()
  23. def append_parameter(self, parameter):
  24. """Appends a parameter to this basic block."""
  25. if isinstance(parameter, Definition):
  26. assert isinstance(parameter.value, BlockParameter)
  27. else:
  28. assert isinstance(parameter, BlockParameter)
  29. result = self.create_definition(parameter)
  30. self.parameters.append(result)
  31. if len(self.definitions) > 0:
  32. self.renumber_definitions()
  33. return result
  34. def remove_parameter(self, parameter):
  35. """Removes the given parameter definition from this basic block."""
  36. return self.parameters.remove(parameter)
  37. def prepend_definition(self, value):
  38. """Defines the given value in this basic block."""
  39. result = self.create_definition(value)
  40. self.definitions.insert(0, result)
  41. self.renumber_definitions()
  42. return result
  43. def __get_def_index_for_insert(self, anchor):
  44. for i, definition in enumerate(self.definitions):
  45. if definition.definition_index == anchor.definition_index:
  46. return i
  47. raise ValueError(
  48. 'Cannot insert a definition because the anchor '
  49. 'is not defined in this block.')
  50. def insert_definition_before(self, anchor, value):
  51. """Inserts the second definition or value before the first definition."""
  52. index = self.__get_def_index_for_insert(anchor)
  53. result = self.create_definition(value)
  54. self.definitions.insert(index, result)
  55. self.renumber_definitions()
  56. return result
  57. def insert_definition_after(self, anchor, value):
  58. """Inserts the second definition or value after the first definition."""
  59. index = self.__get_def_index_for_insert(anchor)
  60. result = self.create_definition(value)
  61. self.definitions.insert(index + 1, result)
  62. self.renumber_definitions()
  63. return result
  64. def append_definition(self, value):
  65. """Defines the given value in this basic block."""
  66. result = self.create_definition(value)
  67. self.definitions.append(result)
  68. return result
  69. def create_definition(self, value=None):
  70. """Creates a definition, but does not assign it to this block yet."""
  71. if isinstance(value, Definition):
  72. value.block = self
  73. value.renumber(self.definition_counter.next_value())
  74. return value
  75. else:
  76. assert isinstance(value, Value) or value is None
  77. return Definition(
  78. self.counter.next_value(),
  79. self,
  80. self.definition_counter.next_value(),
  81. value)
  82. def remove_definition(self, definition):
  83. """Removes the given definition from this basic block."""
  84. return self.definitions.remove(definition)
  85. def renumber_definitions(self):
  86. """Re-numbers all definitions in this basic block."""
  87. self.definition_counter = SharedCounter()
  88. for definition in self.parameters:
  89. definition.renumber(self.definition_counter.next_value())
  90. for definition in self.definitions:
  91. definition.renumber(self.definition_counter.next_value())
  92. assert (
  93. len(set(
  94. [definition.definition_index
  95. for definition in self.parameters + self.definitions])) ==
  96. len(self.parameters) + len(self.definitions))
  97. def __str__(self):
  98. prefix = '!%d(%s):' % (self.index, ', '.join(map(str, self.parameters)))
  99. return '\n'.join(
  100. [prefix] +
  101. [' ' * 4 + str(item) for item in self.definitions + [self.flow]])
  102. class Definition(object):
  103. """Maps a value to a variable."""
  104. def __init__(self, index, block, definition_index, value):
  105. self.index = index
  106. self.block = block
  107. self.definition_index = definition_index
  108. self.value = value
  109. if value is not None:
  110. assert isinstance(value, Value) or isinstance(value, Definition)
  111. def redefine(self, new_value):
  112. """Tweaks this definition to take on the given new value."""
  113. self.value = new_value
  114. if new_value is not None:
  115. assert isinstance(new_value, Value) or isinstance(new_value, Definition)
  116. def renumber(self, new_definition_index):
  117. """Updates this definition's index in the block that defines it."""
  118. self.definition_index = new_definition_index
  119. def get_all_dependencies(self):
  120. """Gets all definitions and instructions on which this definition depends,
  121. along with any dependencies of instruction dependencies."""
  122. if isinstance(self.value, Definition):
  123. return [self.value]
  124. else:
  125. return self.value.get_all_dependencies()
  126. def get_all_filtered_dependencies(self, function):
  127. """Gets all definitions and instructions on which this instruction depends,
  128. along with any dependencies of instruction dependencies. Dependency trees
  129. are filtered by a Boolean-returning function."""
  130. if isinstance(self.value, Definition):
  131. return list(filter(function, [self.value]))
  132. else:
  133. return self.value.get_all_filtered_dependencies(function)
  134. def has_side_effects(self):
  135. """Tests if this definition produces any side-effects."""
  136. return self.value.has_side_effects()
  137. def has_value(self):
  138. """Tells if this definition produces a result that is not None."""
  139. return self.value.has_value()
  140. def has_bidirectional_dependencies(self):
  141. """Tells if this instruction's dependencies are bidirectional."""
  142. return (not isinstance(self.value, Definition)
  143. and self.value.has_bidirectional_dependencies())
  144. def insert_before(self, value):
  145. """Inserts the given value or definition before this definition."""
  146. return self.block.insert_definition_before(self, value)
  147. def insert_after(self, value):
  148. """Inserts the given value or definition after this definition."""
  149. return self.block.insert_definition_after(self, value)
  150. def ref_str(self):
  151. """Gets a string that represents a reference to this definition."""
  152. return '$%d' % self.index
  153. def __str__(self):
  154. return '$%d = %s' % (self.index, self.value.ref_str())
  155. class Instruction(object):
  156. """Represents an instruction."""
  157. def get_dependencies(self):
  158. """Gets all definitions and instructions on which this instruction depends."""
  159. raise NotImplementedError()
  160. def create(self, new_dependencies):
  161. """Creates an instruction of this type from the given set of dependencies."""
  162. raise NotImplementedError()
  163. def get_all_dependencies(self):
  164. """Gets all definitions and instructions on which this instruction depends,
  165. along with any dependencies of instruction dependencies."""
  166. results = list(self.get_dependencies())
  167. for item in results:
  168. if not isinstance(item, Definition):
  169. results.extend(item.get_all_dependencies())
  170. return results
  171. def get_all_filtered_dependencies(self, function):
  172. """Gets all definitions and instructions on which this instruction depends,
  173. along with any dependencies of instruction dependencies. Dependency trees
  174. are filtered by a Boolean-returning function."""
  175. results = list(filter(function, self.get_dependencies()))
  176. for item in results:
  177. if not isinstance(item, Definition):
  178. results.extend(item.get_all_filtered_dependencies(function))
  179. return results
  180. class Branch(Instruction):
  181. """Represents a branch from one basic block to another."""
  182. def __init__(self, block, arguments=None):
  183. self.block = block
  184. assert isinstance(block, BasicBlock)
  185. if arguments is None:
  186. arguments = []
  187. self.arguments = arguments
  188. assert all([isinstance(arg, Definition) for arg in arguments])
  189. def get_dependencies(self):
  190. """Gets all definitions and instructions on which this instruction depends."""
  191. return self.arguments
  192. def create(self, new_dependencies):
  193. """Creates an instruction of this type from the given set of dependencies."""
  194. return Branch(self.block, new_dependencies)
  195. def __str__(self):
  196. return '!%d(%s)' % (self.block.index, ', '.join([arg.ref_str() for arg in self.arguments]))
  197. class FlowInstruction(Instruction):
  198. """Represents a control flow instruction which terminates a basic block."""
  199. def branches(self):
  200. """Gets a list of basic blocks targeted by this flow instruction."""
  201. raise NotImplementedError()
  202. def has_bidirectional_dependencies(self):
  203. """Tells if this instruction's dependencies are bidirectional."""
  204. return False
  205. def has_side_effects(self):
  206. """Tells if this instruction has side-effects."""
  207. # All flow-instructions have side-effects!
  208. return True
  209. class JumpFlow(FlowInstruction):
  210. """Represents a control flow instruction which jumps directly to a basic block."""
  211. def __init__(self, branch):
  212. FlowInstruction.__init__(self)
  213. self.branch = branch
  214. assert isinstance(branch, Branch)
  215. def get_dependencies(self):
  216. """Gets all definitions and instructions on which this instruction depends."""
  217. return self.branches()
  218. def create(self, new_dependencies):
  219. """Creates an instruction of this type from the given set of dependencies."""
  220. return JumpFlow(*new_dependencies)
  221. def branches(self):
  222. """Gets a list of basic blocks targeted by this flow instruction."""
  223. return [self.branch]
  224. def __str__(self):
  225. return 'jump %s' % self.branch
  226. class SelectFlow(FlowInstruction):
  227. """Represents a control flow instruction which jumps to one of two basic blocks depending
  228. on whether a condition is truthy or not."""
  229. def __init__(self, condition, if_branch, else_branch):
  230. FlowInstruction.__init__(self)
  231. self.condition = condition
  232. assert isinstance(condition, Definition)
  233. self.if_branch = if_branch
  234. assert isinstance(if_branch, Branch)
  235. self.else_branch = else_branch
  236. assert isinstance(else_branch, Branch)
  237. def get_dependencies(self):
  238. """Gets all definitions and instructions on which this instruction depends."""
  239. return [self.condition] + self.branches()
  240. def create(self, new_dependencies):
  241. """Creates an instruction of this type from the given set of dependencies."""
  242. return SelectFlow(*new_dependencies)
  243. def branches(self):
  244. """Gets a list of basic blocks targeted by this flow instruction."""
  245. return [self.if_branch, self.else_branch]
  246. def __str__(self):
  247. return 'select %s, %s, %s' % (self.condition.ref_str(), self.if_branch, self.else_branch)
  248. class ReturnFlow(FlowInstruction):
  249. """Represents a control flow instruction which terminates the execution of the current
  250. function and returns a value."""
  251. def __init__(self, value):
  252. FlowInstruction.__init__(self)
  253. self.value = value
  254. assert isinstance(value, Definition)
  255. def get_dependencies(self):
  256. """Gets all definitions and instructions on which this instruction depends."""
  257. return [self.value]
  258. def create(self, new_dependencies):
  259. """Creates an instruction of this type from the given set of dependencies."""
  260. return ReturnFlow(*new_dependencies)
  261. def branches(self):
  262. """Gets a list of basic blocks targeted by this flow instruction."""
  263. return []
  264. def __str__(self):
  265. return 'return %s' % self.value.ref_str()
  266. class ThrowFlow(FlowInstruction):
  267. """Represents a control flow instruction which throws an exception."""
  268. def __init__(self, exception):
  269. FlowInstruction.__init__(self)
  270. self.exception = exception
  271. assert isinstance(exception, Definition)
  272. def get_dependencies(self):
  273. """Gets all definitions and instructions on which this instruction depends."""
  274. return [self.exception]
  275. def create(self, new_dependencies):
  276. """Creates an instruction of this type from the given set of dependencies."""
  277. return ThrowFlow(*new_dependencies)
  278. def branches(self):
  279. """Gets a list of basic blocks targeted by this flow instruction."""
  280. return []
  281. def __str__(self):
  282. return 'throw %s' % self.exception.ref_str()
  283. class UnreachableFlow(FlowInstruction):
  284. """Represents a control flow instruction which is unreachable."""
  285. def get_dependencies(self):
  286. """Gets all definitions and instructions on which this instruction depends."""
  287. return []
  288. def create(self, new_dependencies):
  289. """Creates an instruction of this type from the given set of dependencies."""
  290. assert len(new_dependencies) == 0
  291. return self
  292. def branches(self):
  293. """Gets a list of basic blocks targeted by this flow instruction."""
  294. return []
  295. def __str__(self):
  296. return 'unreachable'
  297. class Value(Instruction):
  298. """A value: an instruction that produces some result."""
  299. def get_dependencies(self):
  300. """Gets all definitions and instructions on which this instruction depends."""
  301. raise NotImplementedError()
  302. def has_value(self):
  303. """Tells if this value produces a result that is not None."""
  304. return True
  305. def has_side_effects(self):
  306. """Tells if this instruction has side-effects."""
  307. return False
  308. def has_bidirectional_dependencies(self):
  309. """Tells if this value has bidirectional dependencies: if so, then all dependencies
  310. of this node on another node are also dependencies of that node on this node."""
  311. return False
  312. def ref_str(self):
  313. """Gets a string that represents this value."""
  314. return str(self)
  315. class BlockParameter(Value):
  316. """A basic block parameter."""
  317. def get_dependencies(self):
  318. """Gets all definitions and instructions on which this instruction depends."""
  319. return []
  320. def create(self, new_dependencies):
  321. """Creates an instruction of this type from the given set of dependencies."""
  322. assert len(new_dependencies) == 0
  323. return BlockParameter()
  324. def __str__(self):
  325. return 'block-parameter'
  326. class FunctionParameter(Value):
  327. """A function parameter."""
  328. def __init__(self, name):
  329. Value.__init__(self)
  330. self.name = name
  331. def create(self, new_dependencies):
  332. """Creates an instruction of this type from the given set of dependencies."""
  333. assert len(new_dependencies) == 0
  334. return FunctionParameter(self.name)
  335. def get_dependencies(self):
  336. """Gets all definitions and instructions on which this instruction depends."""
  337. return []
  338. def __str__(self):
  339. return 'func-parameter %s' % self.name
  340. class Literal(Value):
  341. """A literal value."""
  342. def __init__(self, literal):
  343. Value.__init__(self)
  344. self.literal = literal
  345. def create(self, new_dependencies):
  346. """Creates an instruction of this type from the given set of dependencies."""
  347. assert len(new_dependencies) == 0
  348. return Literal(self.literal)
  349. def get_dependencies(self):
  350. """Gets all definitions and instructions on which this instruction depends."""
  351. return []
  352. def has_value(self):
  353. """Tells if this value produces a result that is not None."""
  354. return self.literal is not None
  355. def __str__(self):
  356. return 'literal %r' % self.literal
  357. class IndirectFunctionCall(Value):
  358. """A value that is the result of an indirect function call."""
  359. def __init__(self, target, argument_list):
  360. Value.__init__(self)
  361. assert isinstance(target, Definition)
  362. self.target = target
  363. assert all([isinstance(val, Definition) for _, val in argument_list])
  364. self.argument_list = argument_list
  365. def has_side_effects(self):
  366. """Tells if this instruction has side-effects."""
  367. return True
  368. def get_dependencies(self):
  369. """Gets all definitions and instructions on which this instruction depends."""
  370. return [self.target] + [val for _, val in self.argument_list]
  371. def create(self, new_dependencies):
  372. """Creates an instruction of this type from the given set of dependencies."""
  373. return IndirectFunctionCall(
  374. new_dependencies[0],
  375. [(name, new_val)
  376. for new_val, (name, _) in zip(new_dependencies[1:], self.argument_list)])
  377. def __str__(self):
  378. return 'indirect-call %s(%s)' % (
  379. self.target.ref_str(),
  380. ', '.join(['%s=%s' % (key, val.ref_str()) for key, val in self.argument_list]))
  381. SIMPLE_POSITIONAL_CALLING_CONVENTION = 'simple-positional'
  382. """The calling convention for functions that use 'return' statements to return.
  383. Arguments are matched to parameters based on position."""
  384. SELF_POSITIONAL_CALLING_CONVENTION = 'self-positional'
  385. """A calling convention that is identical to SIMPLE_POSITIONAL_CALLING_CONVENTION, except
  386. for the fact that the first argument is used as the 'self' parameter."""
  387. JIT_CALLING_CONVENTION = 'jit'
  388. """The calling convention for jitted functions."""
  389. JIT_NO_GC_CALLING_CONVENTION = 'jit-no-gc'
  390. """The calling convention for jitted functions that promise not to initiate a GC cycle."""
  391. MACRO_POSITIONAL_CALLING_CONVENTION = 'macro-positional'
  392. """The calling convention for well-known functions that are expanded as macros during codegen."""
  393. MACRO_IO_CALLING_CONVENTION = 'macro-io'
  394. """The calling convention 'input' and 'output'."""
  395. PRINT_MACRO_NAME = 'print'
  396. """The name of the 'print' macro."""
  397. INPUT_MACRO_NAME = 'input'
  398. """The name of the macro that pops a value from the input queue."""
  399. OUTPUT_MACRO_NAME = 'output'
  400. """The name of the macro that pushes an output onto the output queue."""
  401. NOP_MACRO_NAME = 'nop'
  402. """The name of the macro that performs a nop."""
  403. READ_DICT_KEYS_MACRO_NAME = 'read_dict_keys'
  404. """The name of the macro that reads all keys from a dictionary."""
  405. REVERSE_LIST_MACRO_NAME = 'reverse_list'
  406. """The name of the list reversal macro."""
  407. GC_PROTECT_MACRO_NAME = 'gc_protect'
  408. """The name of the macro that unconditionally protects its first argument from the GC by
  409. drawing an edge between it and the second argument."""
  410. MAYBE_GC_PROTECT_MACRO_NAME = 'maybe_gc_protect'
  411. """The name of the macro that protects its first argument from the GC by drawing an edge between
  412. it and the second argument, but only if that first argument is not None."""
  413. class DirectFunctionCall(Value):
  414. """A value that is the result of a direct function call."""
  415. def __init__(
  416. self, target_name, argument_list,
  417. calling_convention=JIT_CALLING_CONVENTION,
  418. has_value=True,
  419. has_side_effects=True,
  420. has_bidirectional_dependencies=False):
  421. Value.__init__(self)
  422. self.target_name = target_name
  423. assert all([isinstance(val, Definition) for _, val in argument_list])
  424. self.argument_list = argument_list
  425. self.calling_convention = calling_convention
  426. self.has_value_val = has_value
  427. self.has_side_effects_val = has_side_effects
  428. self.has_bidirectional_deps_val = has_bidirectional_dependencies
  429. def has_side_effects(self):
  430. """Tells if this instruction has side-effects."""
  431. return self.has_side_effects_val
  432. def has_value(self):
  433. """Tells if this value produces a result that is not None."""
  434. return self.has_value_val
  435. def has_bidirectional_dependencies(self):
  436. """Tells if this value has bidirectional dependencies."""
  437. return self.has_bidirectional_deps_val
  438. def create(self, new_dependencies):
  439. """Creates an instruction of this type from the given set of dependencies."""
  440. return DirectFunctionCall(
  441. self.target_name,
  442. [(name, new_val)
  443. for new_val, (name, _) in zip(new_dependencies, self.argument_list)],
  444. self.calling_convention, self.has_value_val, self.has_side_effects_val,
  445. self.has_bidirectional_deps_val)
  446. def get_dependencies(self):
  447. """Gets all definitions and instructions on which this instruction depends."""
  448. return [val for _, val in self.argument_list]
  449. def format_calling_convention_tuple(self):
  450. """Formats this direct function call's extended calling convention tuple.
  451. The result is a formatted string that consists of a calling convention,
  452. and optionally information that pertains to whether the function returns
  453. a value and has side-effects."""
  454. if (self.has_side_effects()
  455. and self.has_value()
  456. and not self.has_bidirectional_dependencies()):
  457. return repr(self.calling_convention)
  458. contents = [repr(self.calling_convention)]
  459. if not self.has_side_effects():
  460. contents.append('pure')
  461. if not self.has_value():
  462. contents.append('void')
  463. if self.has_bidirectional_dependencies():
  464. contents.append('two-way-dependencies')
  465. return '(%s)' % ', '.join(contents)
  466. def __str__(self):
  467. return 'direct-call %s %s(%s)' % (
  468. self.format_calling_convention_tuple(),
  469. self.target_name,
  470. ', '.join(['%s=%s' % (key, val.ref_str()) for key, val in self.argument_list]))
  471. class AllocateRootNode(Value):
  472. """A value that produces a new root node. Typically used in function prologs."""
  473. def __init__(self):
  474. Value.__init__(self)
  475. def get_dependencies(self):
  476. """Gets all definitions and instructions on which this instruction depends."""
  477. return []
  478. def create(self, new_dependencies):
  479. """Creates an instruction of this type from the given set of dependencies."""
  480. assert len(new_dependencies) == 0
  481. return AllocateRootNode()
  482. def __str__(self):
  483. return 'alloc-root-node'
  484. class DeallocateRootNode(Value):
  485. """A value that deallocates a root node. Typically used in function epilogs."""
  486. def __init__(self, root_node):
  487. Value.__init__(self)
  488. assert isinstance(root_node, Definition)
  489. self.root_node = root_node
  490. def get_dependencies(self):
  491. """Gets all definitions and instructions on which this instruction depends."""
  492. return [self.root_node]
  493. def create(self, new_dependencies):
  494. """Creates an instruction of this type from the given set of dependencies."""
  495. return DeallocateRootNode(*new_dependencies)
  496. def has_value(self):
  497. """Tells if this value produces a result that is not None."""
  498. return False
  499. def has_bidirectional_dependencies(self):
  500. """Tells if this value has bidirectional dependencies: if so, then all dependencies
  501. of this node on another node are also dependencies of that node on this node."""
  502. return True
  503. def __str__(self):
  504. return 'free-root-node %s' % self.root_node.ref_str()
  505. class DeclareLocal(Value):
  506. """A value that declares a local variable."""
  507. def __init__(self, variable, root_node):
  508. Value.__init__(self)
  509. self.variable = variable
  510. self.root_node = root_node
  511. def get_dependencies(self):
  512. """Gets all definitions and instructions on which this instruction depends."""
  513. return [self.root_node]
  514. def create(self, new_dependencies):
  515. """Creates an instruction of this type from the given set of dependencies."""
  516. root_node, = new_dependencies
  517. return DeclareLocal(self.variable, root_node)
  518. def has_value(self):
  519. """Tells if this value produces a result that is not None."""
  520. return False
  521. def has_side_effects(self):
  522. """Tells if this instruction has side-effects."""
  523. return True
  524. def __str__(self):
  525. return 'declare-local %s, %s' % (self.variable, self.root_node.ref_str())
  526. class DeclareGlobal(Value):
  527. """A value that declares a global variable."""
  528. def __init__(self, variable):
  529. Value.__init__(self)
  530. self.variable = variable
  531. def get_dependencies(self):
  532. """Gets all definitions and instructions on which this instruction depends."""
  533. return []
  534. def create(self, new_dependencies):
  535. """Creates an instruction of this type from the given set of dependencies."""
  536. return DeclareGlobal(self.variable)
  537. def has_value(self):
  538. """Tells if this value produces a result that is not None."""
  539. return False
  540. def has_side_effects(self):
  541. """Tells if this instruction has side-effects."""
  542. return True
  543. def __str__(self):
  544. return 'declare-global %s' % self.variable.name
  545. class CheckLocalExists(Value):
  546. """A value that checks if a local value has been defined (yet)."""
  547. def __init__(self, variable):
  548. Value.__init__(self)
  549. self.variable = variable
  550. def get_dependencies(self):
  551. """Gets all definitions and instructions on which this instruction depends."""
  552. return []
  553. def create(self, new_dependencies):
  554. """Creates an instruction of this type from the given set of dependencies."""
  555. return CheckLocalExists(self.variable)
  556. def __str__(self):
  557. return 'check-local-exists %s' % self.variable
  558. class ResolveLocal(Value):
  559. """A value that resolves a local as a pointer."""
  560. def __init__(self, variable):
  561. Value.__init__(self)
  562. self.variable = variable
  563. def get_dependencies(self):
  564. """Gets all definitions and instructions on which this instruction depends."""
  565. return []
  566. def create(self, new_dependencies):
  567. """Creates an instruction of this type from the given set of dependencies."""
  568. return ResolveLocal(self.variable)
  569. def __str__(self):
  570. return 'resolve-local %s' % self.variable
  571. class ResolveGlobal(Value):
  572. """A value that resolves a global as a pointer."""
  573. def __init__(self, variable):
  574. Value.__init__(self)
  575. self.variable = variable
  576. def get_dependencies(self):
  577. """Gets all definitions and instructions on which this instruction depends."""
  578. return []
  579. def create(self, new_dependencies):
  580. """Creates an instruction of this type from the given set of dependencies."""
  581. return ResolveGlobal(self.variable)
  582. def __str__(self):
  583. return 'resolve-global %s' % self.variable.name
  584. class LoadPointer(Value):
  585. """A value that loads the value assigned to a pointer."""
  586. def __init__(self, pointer):
  587. Value.__init__(self)
  588. self.pointer = pointer
  589. assert isinstance(pointer, Definition)
  590. def get_dependencies(self):
  591. """Gets all definitions and instructions on which this instruction depends."""
  592. return [self.pointer]
  593. def create(self, new_dependencies):
  594. """Creates an instruction of this type from the given set of dependencies."""
  595. return LoadPointer(*new_dependencies)
  596. def __str__(self):
  597. return 'load %s' % self.pointer.ref_str()
  598. class StoreAtPointer(Value):
  599. """A value that assigns a value to a pointer."""
  600. def __init__(self, pointer, value):
  601. Value.__init__(self)
  602. self.pointer = pointer
  603. assert isinstance(pointer, Definition)
  604. self.value = value
  605. assert isinstance(value, Definition)
  606. def get_dependencies(self):
  607. """Gets all definitions and instructions on which this instruction depends."""
  608. return [self.pointer, self.value]
  609. def create(self, new_dependencies):
  610. """Creates an instruction of this type from the given set of dependencies."""
  611. return StoreAtPointer(*new_dependencies)
  612. def has_value(self):
  613. """Tells if this value produces a result that is not None."""
  614. return False
  615. def has_side_effects(self):
  616. """Tells if this instruction has side-effects."""
  617. return True
  618. def __str__(self):
  619. return 'store %s, %s' % (self.pointer.ref_str(), self.value.ref_str())
  620. class Read(Value):
  621. """A value that reads the value stored in a node."""
  622. def __init__(self, node):
  623. Value.__init__(self)
  624. self.node = node
  625. assert isinstance(node, Definition)
  626. def get_dependencies(self):
  627. """Gets all definitions and instructions on which this instruction depends."""
  628. return [self.node]
  629. def create(self, new_dependencies):
  630. """Creates an instruction of this type from the given set of dependencies."""
  631. return Read(*new_dependencies)
  632. def __str__(self):
  633. return 'read %s' % (self.node.ref_str())
  634. class CreateNode(Value):
  635. """A value that creates a new node."""
  636. def __init__(self, value):
  637. Value.__init__(self)
  638. self.value = value
  639. assert isinstance(value, Definition)
  640. def get_dependencies(self):
  641. """Gets all definitions and instructions on which this instruction depends."""
  642. return [self.value]
  643. def create(self, new_dependencies):
  644. """Creates an instruction of this type from the given set of dependencies."""
  645. return CreateNode(*new_dependencies)
  646. def __str__(self):
  647. return 'create-node %s' % (self.value.ref_str())
  648. class CreateEdge(Value):
  649. """A value that creates a new edge."""
  650. def __init__(self, source, target):
  651. Value.__init__(self)
  652. self.source = source
  653. assert isinstance(source, Definition)
  654. self.target = target
  655. assert isinstance(target, Definition)
  656. def get_dependencies(self):
  657. """Gets all definitions and instructions on which this instruction depends."""
  658. return [self.source, self.target]
  659. def create(self, new_dependencies):
  660. """Creates an instruction of this type from the given set of dependencies."""
  661. return CreateEdge(*new_dependencies)
  662. def has_bidirectional_dependencies(self):
  663. """Tells if this value has bidirectional dependencies: if so, then all dependencies
  664. of this node on another node are also dependencies of that node on this node."""
  665. return True
  666. def __str__(self):
  667. return 'create-edge %s, %s' % (self.source.ref_str(), self.target.ref_str())
  668. class Binary(Value):
  669. """A value that applies a binary operator to two other values."""
  670. def __init__(self, lhs, operator, rhs):
  671. Value.__init__(self)
  672. self.lhs = lhs
  673. assert isinstance(lhs, Definition)
  674. self.operator = operator
  675. self.rhs = rhs
  676. assert isinstance(rhs, Definition)
  677. def get_dependencies(self):
  678. """Gets all definitions and instructions on which this instruction depends."""
  679. return [self.lhs, self.rhs]
  680. def create(self, new_dependencies):
  681. """Creates an instruction of this type from the given set of dependencies."""
  682. lhs, rhs = new_dependencies
  683. return Binary(lhs, self.operator, rhs)
  684. def __str__(self):
  685. return 'binary %s, %r, %s' % (self.lhs.ref_str(), self.operator, self.rhs.ref_str())
  686. class Unary(Value):
  687. """A value that applies a unary operator to an operand value."""
  688. def __init__(self, operator, operand):
  689. Value.__init__(self)
  690. self.operator = operator
  691. self.operand = operand
  692. assert isinstance(operand, Definition)
  693. def get_dependencies(self):
  694. """Gets all definitions and instructions on which this instruction depends."""
  695. return [self.operand]
  696. def create(self, new_dependencies):
  697. """Creates an instruction of this type from the given set of dependencies."""
  698. new_operand, = new_dependencies
  699. return Unary(self.operator, new_operand)
  700. def __str__(self):
  701. return 'unary %r, %s' % (self.operator, self.operand.ref_str())
  702. def create_jump(block, arguments=None):
  703. """Creates a jump to the given block with the given argument list."""
  704. return JumpFlow(Branch(block, arguments))
  705. def create_print(argument):
  706. """Creates a value that prints the specified argument."""
  707. return DirectFunctionCall(
  708. PRINT_MACRO_NAME, [('argument', argument)],
  709. calling_convention=MACRO_POSITIONAL_CALLING_CONVENTION,
  710. has_value=False)
  711. def create_output(argument):
  712. """Creates a value that outputs the specified argument."""
  713. return DirectFunctionCall(
  714. OUTPUT_MACRO_NAME, [('argument', argument)],
  715. calling_convention=MACRO_IO_CALLING_CONVENTION,
  716. has_value=False)
  717. def create_input():
  718. """Creates a value that pops a value from the input queue."""
  719. return DirectFunctionCall(
  720. INPUT_MACRO_NAME, [],
  721. calling_convention=MACRO_IO_CALLING_CONVENTION)
  722. def create_nop():
  723. """Creates a value that performs a nop."""
  724. return DirectFunctionCall(
  725. NOP_MACRO_NAME, [],
  726. calling_convention=MACRO_IO_CALLING_CONVENTION,
  727. has_value=False)
  728. def create_gc_protect(protected_value, root):
  729. """Creates a value that protects the first from the GC by drawing an
  730. edge between it and the given root."""
  731. return DirectFunctionCall(
  732. GC_PROTECT_MACRO_NAME, [
  733. ('protected_value', protected_value),
  734. ('root', root)
  735. ],
  736. calling_convention=MACRO_POSITIONAL_CALLING_CONVENTION,
  737. has_value=False, has_side_effects=False,
  738. has_bidirectional_dependencies=True)
  739. def create_conditional_gc_protect(protected_value, root):
  740. """Creates a value that protects the first from the GC by drawing an
  741. edge between it and the given root, but only if the protected value
  742. is not None."""
  743. return DirectFunctionCall(
  744. MAYBE_GC_PROTECT_MACRO_NAME, [
  745. ('condition', protected_value),
  746. ('protected_value', protected_value),
  747. ('root', root)
  748. ],
  749. calling_convention=MACRO_POSITIONAL_CALLING_CONVENTION,
  750. has_value=False, has_side_effects=False,
  751. has_bidirectional_dependencies=True)
  752. def get_def_value(def_or_value):
  753. """Returns the given value, or the underlying value of the given definition, whichever is
  754. appropriate."""
  755. if isinstance(def_or_value, Definition):
  756. return get_def_value(def_or_value.value)
  757. else:
  758. return def_or_value
  759. def apply_to_value(function, def_or_value):
  760. """Applies the given function to the specified value, or the underlying value of the
  761. given definition."""
  762. return function(get_def_value(def_or_value))
  763. def is_literal(value):
  764. """Tests if the given value is a literal."""
  765. return isinstance(value, Literal)
  766. def is_literal_def(def_or_value):
  767. """Tests if the given value is a literal or a definition with an underlying literal."""
  768. return apply_to_value(is_literal, def_or_value)
  769. def is_value_def(def_or_value, class_or_type_or_tuple=Value):
  770. """Tests if the given definition or value is a value of the given type."""
  771. return isinstance(get_def_value(def_or_value), class_or_type_or_tuple)
  772. def get_def_variable(def_or_value):
  773. """Gets the 'variable' attribute of the given value, or the underlying value of the given
  774. definition, whichever is appropriate."""
  775. return get_def_value(def_or_value).variable
  776. def get_literal_value(value):
  777. """Gets the value of the given literal value."""
  778. return value.literal
  779. def get_literal_def_value(def_or_value):
  780. """Gets the value of the given literal value or definition with an underlying literal."""
  781. return apply_to_value(get_literal_value, def_or_value)
  782. def is_call(def_or_value, target_name=None, calling_convention=None):
  783. """Tells if the given definition or value is a direct call.
  784. The callee's name must match the given name, or the specified name must be None
  785. The call must have the given calling convention, or the calling convention must be None."""
  786. value = get_def_value(def_or_value)
  787. if isinstance(value, DirectFunctionCall):
  788. return ((target_name is None or value.target_name == target_name)
  789. and (calling_convention is None
  790. or calling_convention == value.calling_convention))
  791. else:
  792. return False
  793. def get_all_predecessor_blocks(entry_point):
  794. """Creates a mapping of blocks to their direct predecessors for every block in the control-flow
  795. graph defined by the given entry point."""
  796. # Use both lists and sets to keep the ordering of the resulting collections deterministic, and
  797. # to maintain the same complexity as a set-only approach.
  798. result_sets = {}
  799. result_lists = {}
  800. all_blocks = get_all_blocks(entry_point)
  801. for block in all_blocks:
  802. result_sets[block] = set()
  803. result_lists[block] = list()
  804. for block in all_blocks:
  805. for reachable_block in get_directly_reachable_blocks(block):
  806. if block not in result_sets[reachable_block]:
  807. result_lists[reachable_block].append(block)
  808. result_sets[reachable_block].add(block)
  809. return result_lists
  810. def get_directly_reachable_blocks(block):
  811. """Gets the set of all blocks that can be reached by taking a single branch from the
  812. given block."""
  813. return [branch.block for branch in block.flow.branches()]
  814. def get_reachable_blocks(entry_point):
  815. """Constructs the set of all reachable vertices from the given block."""
  816. # This is a simple O(n^2) algorithm. Maybe a faster algorithm is more appropriate here.
  817. def __add_block_children(block, results):
  818. for child in get_directly_reachable_blocks(block):
  819. if child not in results:
  820. results.add(child)
  821. __add_block_children(child, results)
  822. return results
  823. return __add_block_children(entry_point, set())
  824. def get_all_reachable_blocks(entry_point):
  825. """Constructs the set of all reachable vertices, for every block that is
  826. reachable from the given entry point."""
  827. # This is a simple O(n^3) algorithm. Maybe a faster algorithm is more appropriate here.
  828. results = {}
  829. all_blocks = get_reachable_blocks(entry_point)
  830. results[entry_point] = all_blocks
  831. for block in all_blocks:
  832. if block not in results:
  833. results[block] = get_reachable_blocks(block)
  834. return results
  835. def get_all_blocks(entry_point):
  836. """Gets all basic blocks in the control-flow graph defined by the given entry point."""
  837. def __find_blocks_step(block, results):
  838. if block in results:
  839. return
  840. results.add(block)
  841. for branch in block.flow.branches():
  842. __find_blocks_step(branch.block, results)
  843. all_blocks = set()
  844. __find_blocks_step(entry_point, all_blocks)
  845. # Sort the blocks to make their order deterministic.
  846. return list(sorted(all_blocks, key=lambda b: b.index))
  847. def get_trivial_phi_value(parameter_def, values):
  848. """Tests if the given parameter definition is an alias for another definition.
  849. If so, then the other definition is returned; otherwise, None."""
  850. result = None
  851. for elem in values:
  852. if elem is not parameter_def:
  853. if result is None:
  854. result = elem
  855. else:
  856. return None
  857. return result
  858. def find_all_def_uses(entry_point):
  859. """Finds all uses of all definitions in the given entry point.
  860. A (definition to list of users map, definition to defining block map)
  861. tuple is returned."""
  862. all_blocks = list(get_all_blocks(entry_point))
  863. # Find all definition users for each definition.
  864. def_users = defaultdict(list)
  865. def_blocks = {}
  866. for block in all_blocks:
  867. for parameter_def in block.parameters:
  868. def_blocks[parameter_def] = block
  869. for definition in block.definitions + [block.flow]:
  870. def_blocks[definition] = block
  871. for dependency in definition.get_all_dependencies():
  872. if not isinstance(dependency, Branch):
  873. def_users[dependency].append(definition)
  874. return def_users, def_blocks
  875. def match_and_rewrite(entry_point, match_def, match_use, rewrite_def, rewrite_use):
  876. """Matches and rewrites chains of definitions and uses in the graph defined by
  877. the given entry point."""
  878. ineligible_defs = set()
  879. used_defs = defaultdict(set)
  880. all_blocks = list(get_all_blocks(entry_point))
  881. connected_defs = defaultdict(set)
  882. # Figure out which defs and which uses match.
  883. for block in all_blocks:
  884. for definition in block.definitions + [block.flow]:
  885. is_def_of_def = False
  886. if isinstance(definition, Definition):
  887. if isinstance(definition.value, Definition):
  888. is_def_of_def = True
  889. connected_defs[definition].add(definition.value)
  890. connected_defs[definition.value].add(definition)
  891. elif not match_def(definition):
  892. ineligible_defs.add(definition)
  893. else:
  894. ineligible_defs.add(definition)
  895. if not is_def_of_def:
  896. for dependency in definition.get_all_filtered_dependencies(
  897. lambda dep: not isinstance(dep, Branch)):
  898. if (isinstance(dependency, Definition)
  899. and dependency not in ineligible_defs):
  900. if match_use(definition, dependency):
  901. used_defs[definition].add(dependency)
  902. else:
  903. ineligible_defs.add(dependency)
  904. for branch in block.flow.branches():
  905. for param, arg in zip(branch.block.parameters, branch.arguments):
  906. connected_defs[arg].add(param)
  907. connected_defs[param].add(arg)
  908. def spread_ineligible(ineligible_definition):
  909. """Spreads 'ineligible' to all connected definitions."""
  910. for connected in connected_defs[ineligible_definition]:
  911. if connected not in ineligible_defs:
  912. ineligible_defs.add(connected)
  913. spread_ineligible(connected)
  914. ineligible_roots = list(ineligible_defs)
  915. for root in ineligible_roots:
  916. spread_ineligible(root)
  917. # Replace defs and uses.
  918. for block in all_blocks:
  919. for definition in block.definitions + [block.flow]:
  920. if (definition not in ineligible_defs
  921. and not isinstance(definition.value, Definition)):
  922. rewrite_def(definition)
  923. for dependency in used_defs[definition]:
  924. if dependency not in ineligible_defs:
  925. rewrite_use(definition, dependency)