cfg_ir.py 37 KB

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