|
@@ -988,20 +988,22 @@ def is_call(def_or_value, target_name=None, calling_convention=None):
|
|
def get_all_predecessor_blocks(entry_point):
|
|
def get_all_predecessor_blocks(entry_point):
|
|
"""Creates a mapping of blocks to their direct predecessors for every block in the control-flow
|
|
"""Creates a mapping of blocks to their direct predecessors for every block in the control-flow
|
|
graph defined by the given entry point."""
|
|
graph defined by the given entry point."""
|
|
- results = defaultdict(set)
|
|
|
|
- processed = set()
|
|
|
|
- def __find_predecessors_step(block):
|
|
|
|
- if block in processed:
|
|
|
|
- return
|
|
|
|
|
|
+ # Use both lists and sets to keep the ordering of the resulting collections deterministic, and
|
|
|
|
+ # to maintain the same complexity as a set-only approach.
|
|
|
|
+ result_sets = {}
|
|
|
|
+ result_lists = {}
|
|
|
|
+ all_blocks = get_all_blocks(entry_point)
|
|
|
|
+ for block in all_blocks:
|
|
|
|
+ result_sets[block] = set()
|
|
|
|
+ result_lists[block] = list()
|
|
|
|
|
|
- processed.add(block)
|
|
|
|
- for branch in block.flow.branches():
|
|
|
|
- target_block = branch.block
|
|
|
|
- results[target_block].add(block)
|
|
|
|
- __find_predecessors_step(target_block)
|
|
|
|
|
|
+ for block in all_blocks:
|
|
|
|
+ for reachable_block in get_directly_reachable_blocks(block):
|
|
|
|
+ if block not in result_sets[reachable_block]:
|
|
|
|
+ result_lists[reachable_block].append(block)
|
|
|
|
+ result_sets[reachable_block].add(block)
|
|
|
|
|
|
- __find_predecessors_step(entry_point)
|
|
|
|
- return results
|
|
|
|
|
|
+ return result_lists
|
|
|
|
|
|
def get_directly_reachable_blocks(block):
|
|
def get_directly_reachable_blocks(block):
|
|
"""Gets the set of all blocks that can be reached by taking a single branch from the
|
|
"""Gets the set of all blocks that can be reached by taking a single branch from the
|
|
@@ -1035,9 +1037,18 @@ def get_all_reachable_blocks(entry_point):
|
|
|
|
|
|
def get_all_blocks(entry_point):
|
|
def get_all_blocks(entry_point):
|
|
"""Gets all basic blocks in the control-flow graph defined by the given entry point."""
|
|
"""Gets all basic blocks in the control-flow graph defined by the given entry point."""
|
|
- reachable_blocks = get_reachable_blocks(entry_point)
|
|
|
|
- reachable_blocks.add(entry_point)
|
|
|
|
- return reachable_blocks
|
|
|
|
|
|
+ def __find_blocks_step(block, results):
|
|
|
|
+ if block in results:
|
|
|
|
+ return
|
|
|
|
+
|
|
|
|
+ results.add(block)
|
|
|
|
+ for branch in block.flow.branches():
|
|
|
|
+ __find_blocks_step(branch.block, results)
|
|
|
|
+
|
|
|
|
+ all_blocks = set()
|
|
|
|
+ __find_blocks_step(entry_point, all_blocks)
|
|
|
|
+ # Sort the blocks to make their order deterministic.
|
|
|
|
+ return list(sorted(all_blocks, key=lambda b: b.index))
|
|
|
|
|
|
def get_trivial_phi_value(parameter_def, values):
|
|
def get_trivial_phi_value(parameter_def, values):
|
|
"""Tests if the given parameter definition is an alias for another definition.
|
|
"""Tests if the given parameter definition is an alias for another definition.
|