cfg_ir.py 45 KB

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