The test_dominance function verifies the correctness of the computed dominators. It does this by:
It iterates through all nodes in the CFG except the entry node.
For each node, it considers all of its computed dominators (excluding the node itself and the entry node).
For each dominator, it temporarily removes that node from the CFG using the remove_node_from_cfg function.
It then checks if the original node is still reachable from the entry node in this modified CFG using the is_reachable function.
If the node is still reachable after removing a supposed dominator, it means that dominator wasn’t actually necessary to reach the node, so the test fails.
If all nodes pass this test for all their dominators, the function returns True. Also, in the code directory I tested this code with two different inputs and both passed the test function.
Hardest Part of the Task and How We Addressed It
The hardest part of this task was likely the correct implementation of the dominator tree construction, specifically in the build_dominator_tree function. This is challenging because:
It requires finding the immediate dominator for each node, which is the closest strict dominator in the dominator graph.
The naive approach of simply choosing any dominator can lead to incorrect results in complex control flow structures.
We addressed this challenge by:
Sorting the dominators of each node based on the size of their own dominator sets, in descending order.
This sorting ensures that we consider closer dominators first, as nodes closer in the dominator tree will have larger dominator sets.
We then select the first dominator from this sorted list (excluding the node itself) as the immediate dominator.