Replies: 19 comments 22 replies
-
|
Code: https://github.com/maheshejs/cs6120pr Dominance Utilities Constructing Dominator Tree Computing Dominance Frontier Testing Example computed dominator tree: More visualizations can be found here: https://github.com/maheshejs/cs6120pr/tree/master/graphics/dom Hardest Part Conclusion GenAI |
Beta Was this translation helpful? Give feedback.
-
Code https://github.com/jeffreyqdd/rust_bril/Dominance Utilities + TestingI ran the tests on all of the files in the bril benchmarks, so I have reasonable confidence that the path coverage is good. 1. Finding DominatorsI implemented the pseudocode discussed in class, adding reverse post-order traversal for the optimal time complexity. testing To show the backwards, I leverage the contrapositive (A does not dominate B => B is reachable from entry). If N is all nodes and 2. Constructing a Dominator TreeFor every domination set testing 3. Generating a Dominator FrontierBecause of the data structures I used, I found it easy to pick an arbitrary node To test, I wrote a check based on the definition discussed in class. Hardest PartThis was surprisingly non-trivial. I initially thought this would take me less than 4 hours, but I'm now on hour 8 due to my poor decisions. I spent the last 2 hours debugging an infinite loop inside my tree, and nearing the end, my entire worldview almost imploded because I started to think my CFG construction algorithm was wrong. TURNS OUT that dead blocks posed a problem. Since all non-initial blocks start with the set of all nodes, dead blocks are never iterated upon, and thus they incorrectly believe they dominate all other nodes upon convergence. After I went back and implemented a method called ConclusionI think I deserve a Michelin star for putting in the effort to prove the correctness of the algorithms. AII used Copilot to write my test cases and tedious traversal algorithms, e.g., post-order, flood fill for reachability, and traversing predecessors in the dominance tree. |
Beta Was this translation helpful? Give feedback.
-
Team MembersJake Hyun SummaryIn this assignment, I built a tool that:
Together, these analyses provide a clear picture of the dominance structure in a program’s control flow. TestingI verified correctness in two ways:
Here’s an example visualization of the Palindrome benchmark: Hardest PartThe hardest part was ensuring that the mathematical definitions of dominance and dominance frontier were precisely matched by the code. Generative AII used ChatGPT to:
CodeYou can find the implementation here: Lesson 5 Code. |
Beta Was this translation helpful? Give feedback.
-
|
In this task, I implemented algorithms to compute dominators, construct the dominator tree, and determine dominance frontiers. A Cool ObservationWhile designing the testing algorithm for dominator computation, I realized that the definition requires enumerating all paths from the entry block to a given block. However, since the CFG may contain loops, the number of such paths is infinite. Interestingly, I found that removing back edges from the CFG does not affect dominator analysis. The intuition is as follows: when enumerating paths from the entry, a loop can be traversed any number of times (0 to ∞). For a back edge with destination block For constructing the dominator tree, I found it more straightforward to work directly on this DAG. My approach was to first compute a topological order of the DAG. Since the entry block is unique, its immediate dominator is set to I compared the results of this approach against the brute-force implementation across bril benchmark suite (commit |
Beta Was this translation helpful? Give feedback.
-
|
Team Members Find DominatorsFinding the dominators ( Dominance TreeTo find the dominance tree, we constructed Dominance FrontierThe function for finding the dominance frontier ( TestingFor testing, we decided that the most reasonable way to test our code is the manually verify our test results. We chose some simple test cases to run our program on, and manually drew out the dominance graph and verified that the dominators, dominance tree, and dominance frontier that was outputted by our program matched the results we manually derived. Hardest PartThe hardest part of the assignment was not the coding itself, but the process of carefully reviewing the test results. To make sure our implementation was correct, this involved manually laying out the basic blocks, drawing the control-flow graph, and tracking all the connections. Manually checking dominators, immediate dominators, and dominance frontiers required meticulous detail, as one small mistake could throw off all later computations. Michelin StarWe believe that we deserve a michelin star as our program is well-tested, and we came up with protocols with reasonable time-complexity to correctly calculate the dominators, dominance tree, and dominance frontier. |
Beta Was this translation helpful? Give feedback.
-
|
Source: https://github.com/Mond45/cs6120_tasks/tree/master/task5 What I DoI implemented algorithms for finding dominators, dominance frontiers, and the dominator tree for a Bril control flow graph in Rust. The dominator-finding algorithm iterates through the blocks in reverse postorder to ensure linear-time complexity. The algorithms for computing dominance frontiers and the dominator tree build upon the dominator-finding algorithm, following the definitions discussed in class. I also implemented a utility for converting a CFG into GraphViz's DOT format for easier visualization. Both the dominator finder and CFG utility output JSON files to facilitate integration with my testing scripts. TestingI first verified each algorithm by hand, greatly helped by my DOT CFG converter. Later, I implemented a dominators verifier in Python. It checks that for each output "A dominates B", every simple path from the entry block to B includes A. I believe this check is sufficient, though I have not fully proven it. My intuition is that cycles in the CFG don't add new information to the domination relation. I ran this verifier across the entire Bril benchmark suite. For dominance frontiers and the dominator tree, I only tested my outputs against the test cases in the Bril repository. I am still wondering if there's a systematic way, beyond handwriting test cases, to test these algorithms more thoroughly. The Hardest PartI found mapping the formal definitions to code implementation quite challenging, though the implementations themselves are not that complicated. I admit I might not fully understand the intuition for dominance frontiers and immediate dominators. ConclusionI believe I deserve a Michelin star for this work. I successfully implemented all three algorithms and verified their correctness. That said, I could spend more time testing the dominator tree and dominance frontier algorithms, as well as learning their definitions. |
Beta Was this translation helpful? Give feedback.
-
|
See here for the bulk of the implementation. SummaryI implemented a function which finds the dominator tree of each block. To do this I used a worklist algorithm to compute all blocks which dominate any given node. I then reverse the relation. This gives an adjacency list for the dominator tree rooted at a given node. To compute the dominator frontier, I then take the transitive closure of this adjacency list relation and iterate over nodes, adding them to the dominator frontier of a given node based on the two criteria in the definition. The step where I iterate to take the transitive closure introduces some pretty bad avoidable inefficiency (though it doesn't show in any of the tests as all the functions I tested on are fairly small). A more efficient implementation could have not taken a transitive closure and instead computed the frontier of a node with a simple recursive traversal (also computing the frontier of the children at the same time). I didn't do this because it is slightly more complicated. TestingFirstly, I manually tested the frontier and dominator tree functions using solutions I manually created and worked through from my own tests as well as from the benchmarks. I additionally wrote a checker for the domination relation which given nodes As in the last assignment, the hardest part was verifying my implementation is correct. Manually working through dominator trees is tedious and while the checker can be used to test my implementation, I still needed to think really hard about the (albeit simpler) checker as well as test the checker! 🛞 ⭐I provide an implementation of a couple dominance utilities and implement a programmatic way to check the results. I don't think the spots of poor efficiency is enough to preclude a star. I think this work deserves one ⭐. |
Beta Was this translation helpful? Give feedback.
-
Codehttps://github.com/YoruCathy/cs6120-tasks/tree/main/lesson5 ImplementationI implemented a tool to
My implementation follows this algorithm from the lecture I didn't do any pruning of unreachable nodes and assumed the full graph in this implementation. TestingI tried 3 testing methods. The first one is manual verification. I ran my code on multiple Bril benchmarks. But I realized it's not very efficient, and once the tree becomes large, it's not very scalable (e.g. GenAI usageI used GPT-5 for the following tasks:
Detailed version of GPT's thinking processThe hardest partManually checking the results (especially when the graph gets big) is very hard, so I tried to find ways to make testing easier. I think GPT's answer makes sense, but because it is a black box we can't rely on it. And comparing against a common library (assume it's correct) is a scalable way. StarI claim a star for my implementation and attempts toward scalable and reliable testing. |
Beta Was this translation helpful? Give feedback.
-
Team MembersNing Wang (nw366), Jiale Lao (jl4492) Source Codehttps://github.com/NingWang0123/cs6120/tree/main/assa5 ImplementationsWe implement the functions to (1) find the dominators for a function, (2) construct the dominance tree, (3) compute the dominance frontier in Python. The hardest partI think for the tasks of these weeks, one of the most challenging part is how to do testing to ensure that our implementation is correct. How to make sure that, the test cases are complete to cover all situations and identify all possible bugs? Also, it would require many efforts to prepare a complete set of test cases, and then how about the evaluation? We can use the existing benchmarks for experiments, but what about ground truth and evaluation? Testing and Visualization (Also the Generative AI Part)Since LLMs are just so good at generating test cases and visualizing results, our final solution is to use GPT-5 to generatec 5 test cases, combined with one test case from the benchmark, and visualization figures, and then we manually check whether these results are correct. As shown in the figure, with good visualizations, it is very easy to tell whether the construction is correct or not. Michelin StarI think we deserve a star, given that we implement all the functions, good testing, and good visualization. |
Beta Was this translation helpful? Give feedback.
-
|
I implemented the functions for finding dominators, building the dominance tree, and finding the dominance frontier. The most challenging part was testing. For finding dominators, I verified correctness by programmatically validating that the output meets the condition: if block0 dominates block1, then all paths from the entry block to block1 include block0. I ran this on the 2 tests under Testing revealed two issues. First, apparently when I had initially implemented the cfg building utilities in lesson2, I didn't consider the case where a program did not have a unique entry block; this resulted in some weird output for I did not implement some form of systematic checker for I asked ChatGPT to write the function to print the tree. Star? I'm reasonably confident that my implementation is complete and correct, so I would say I deserve a star. The output formatting/visualization is not the nicest, but it works. |
Beta Was this translation helpful? Give feedback.
-
|
Team Members Link to Implementation Implementation Overview
Testing Methodology
Each category used Hardest Part
Results/Output
Each benchmark generates Self-Assessment GAI Tools Disclaimer |
Beta Was this translation helpful? Give feedback.
-
Beta Was this translation helpful? Give feedback.
-
|
Amanda Wang @arw274 and I worked together on this. What we didWe implemented algorithms for finding dominators, constructing a dominator tree, and finding dominance frontiers. The algorithm for finding dominators proceeded as shown in the lesson. Our algorithm for constructing the dominator tree leans heavily on the basic fact that allows the dominator tree to exist: that if A and B both dominate C (and C is reachable, i.e. nontrivially dominated), then it must be that A dominates B or vice versa, so the dominators of any node form a path ending at that node in the dominator tree. Our algorithm involves constructing that path explicitly for every node n (by sorting the dominators d of n in order of how many dominators each d has) and adding those paths to the tree. Our dominance frontier algorithm updates frontiers iteratively: each node's dominance frontier is whichever nodes it does not dominate among its own successors and the dominance frontiers of its children in the dominator tree. We perform these updates in reverse postorder so that we do not have to iterate many times. TestingWe implemented brute-force versions of the dominator-finding algorithm (DFS with an excluded node) and the dominance frontier algorithm in order to compare against our versions, and then confirmed that they match on all the For the second week in a row, this testing revealed a bug in a more fundamental algorithm (it turned out my fix for AppraisalWe believe we deserve a Michelin star for clean implementations of all the algorithms and thorough testing. |
Beta Was this translation helpful? Give feedback.
-
|
Who / Where Pedro Pontes Garcia, Helen Ge; https://github.com/mercure67/bril/tree/feat Summarize what you did. We completed a set of tools for reasoning about block domination in a function's CFG. This includes a mapping of each block to the set of blocks which dominate it, a domination tree, and a function which returns the domination frontier. We also have some basic pretty printing for these elements. For more information about the algorithm we used to find the domination frontier, see Explain how you know your implementation works—how did you test it? Which test inputs did you use? Do you have any quantitative results to report? We wrote our code to hew pretty closely to the reference algorithms discussed in class. To test our output, we used a specific example (see What was the hardest part of the task? How did you solve this problem? Testing. We manually tested a special case (discussed above) and manually checked some other programs. Working is shown in Do you think your work deserves a Michelin star? Yes. The implementation works. In addition to testing on some example cases, we tested some important corner cases which Pedro found in his reading. Further, we think our implementations are fairly idiomatic, and spent a decent amount of time refining code and documentation for this and previous tasks, including documentation of the code plus its use; as well as flattening nested conditionals throughout. We also used the reverse post-order traversal optimisation suggested in lecture. |
Beta Was this translation helpful? Give feedback.
-
|
Code: HERE Summary: In this task I upgraded my program to build the dominance tree and the frontier of a CFG (in this case a map between node names and sets of nodes which it dominates/its frontier, which is isomorphic). I did this using the pseudo code and rusts internal set functions, which were extremely useful as I could do true intersections. The only issue I had was when initializing the new set I intersected the empty set with a predecessors (which is obviously empty). Realizing I had to initialize to at least one of the predecessors set fixed this. The frontier algorithm was even more trivial. I simply traversed the descendants of a dominator's children, and if any were not dominated I added them to the frontier. Testing: Testing added its own implementation issues, as Rust's typing system and my novice level with the language led to some inefficient and confusing code. I'm improving however, and after an insidious bug relating to the order of two function inputs (which, due to the HashMaps and the randomization of hashes in Rust, disappeared occasionally when adding print statements) I was able to build a checker. This functioned via manually traversing the tree, and ensuring every path from the entry to a given node passed through it's dominator. It's a slow but exhaustive method. I'd say this was the hardest part, and certainly the most frustrating (the fact that commenting print statements seemingly changed the semantics was infuriating). Using turnt, I used this to test every single bril benchmark in the core benchmarks. With all successes, I know my code is likely correct. Michelin Star: I completed the assignment and proved it correct, and did so in a way that built on previous assignments. I think this deserves a Michelin star. I will say however, I wish I started this assignment earlier. There were a lot of cool visualizations possible, but I wanted to do them right and not just mess up my codebase with AI code (as I noted in my previous GenAI statements), and that takes time and effort. I think as a result I'll try to start the others a little earlier to leave room for any cool post-script items. This is one of those assignments that, if I had more time, I think I could do work worthy of two Michelin stars with the post-script addons. Perhaps I'll be able to do it next week, since we have extra time |
Beta Was this translation helpful? Give feedback.
-
|
I implemented the algorithm for computing dominators within the worklist framwork, and implemented naive algorithms to compute the dominant tree and the dominance frontier with that results. The hardest part was to reason about more efficient algorithms on the CFG structure and how to check correctness. I used GenAI to suggest Python expressions fast (e.g. Me: set Len or size; AI: Use len() to get the size of a set). I do not claim a star. |
Beta Was this translation helpful? Give feedback.
-
|
Repo: https://github.com/Nikil-Shyamsunder/compilers-cs6120/ Finally, I implemented the dominance frontier. I followed the rule that q is in the dominance frontier of p if:
Testing and Evaluation To strengthen testing, I wrote a “naive” checker that enumerates all paths to a node in the CFG via DFS. Using this, I verified that if block B was identified as a dominator of block A by my algorithm, then B appeared on all paths to A. I wrote a Python script (verify.py) to automate this check across the full Bril core benchmark suite. It reported no errors, which gave me confidence that my dominator analysis was correct. Hardest Part Gen AI Statement Michelin Star |
Beta Was this translation helpful? Give feedback.
-
ImplementationI implemented a control flow graph (CFG) that breaks a program into basic blocks, connects them by control flow edges, and then analyzes their dominance relationships. The code computes dominators, builds the dominator tree, and determines dominance frontiers. It also includes checks to verify correctness and utilities to print the results / summary. TestingI tested my code on both Michelin StarI’ll claim one Michelin star for completing this task. Understanding the concept is fine, but I still found implementing, debugging, and testing it all together challenging. |
Beta Was this translation helpful? Give feedback.
-
|
open source: here Cynthia Shao and Jonathan Brown worked together on this task. SummaryWe implemented a finding dominators algorithm, as well as a verifying dominators algorithm. We verified correctness via snapshot testing and the verification algorithm for dominators. We debugged our cfg from identifying interprocedural dominators and changed it to just a global analysis. BenchmarkWe utilized the core benchmark suite to snapshot test and debug across a variety of different programs, catching bugs for labels without bodies. The naive algorithmic testing for the dominators was super helpful, as it provided insight into all the paths enumerated and checked what dominators didn’t follow the concrete definition. This algorithm is meant to throw an error if the dominators are incorrect, and thus all our snapshot testing passed without exiting, giving us reasonable confidence to believe our dominators algorithm is correct. DominatorFor the dominator, I implemented it as specified in the lecture. However, on creating the find_pred function, I realized quickly that if my result did not start out as a set, I could not do the set intersections to see all the predecessors of a given block. (I initially had it so that my result was the empty set, and then realized the empty set’s intersection with any set would be… the empty set. It took me a bit of time to realize that was the reason no predecessors were being found). Furthermore, I learned more about python’s semantics, specifically the fact that you could shorthand sets if you want to make an index (For example, for all i in items make an empty table). It was a really cool feature that I played around with a bit (but was a bit cautious using in code as I wasn’t perfectly comfortable with it). There were also some problems with the logic of the dominator creation where I mixed up the cfg with the blocks, assuming they did the same thing (which was not noticeable at first, but caused many errors, such as no dominators being found). Otherwise, the dominator creation was made as follows from the lecture. TestingTo create an algorithm for checking the output of dominators, I first approached the verification from the definition. For all basic blocks A, basic block B is a dominator if all paths to B pass through A. Thus, I devised two functions. One function The second algorithm parsed through all blocks A, and for each dominator B in the set for block A, I naively checked to see if dominator B occurred before the first instance of block A. I think this algorithm is probably on the order of O(n^4), where n is the number of total blocks due to worst case parsing through all blocks, the dominators of each block, all paths to that block, and each item in the path. This is supposing that the number of paths to traverse isn’t terribly large, because the programs I am running this algorithm on are somewhat sparse, and usually have natural loops. I think some cool next steps would be to possibly optimize this algorithm, due to the possibility that there be an exponential amount of paths! Hardest PartThe hardest part was debugging our implementation. Implementing the algorithmic testing function revealed a lot of bugs within our dominators and CFG implementation. The core bug was that our cfg implementation was interprocedural, and Jonathan thought that functions within a bril program would automatically execute one after the other, and he linked the cfg accordingly. Thus, our dominator set went through the global program, which is cool, but not what we wanted. So, we refactored our cfg to be function based, as well as adding unique naming to labels that used the same names within functions. Self AssessmentWe believe we deserve a Michelin star because we are proud of our work! We brainstormed an implementation of dominators, and thoroughly tested. We tested thoroughly using both hand implemented benchmarks, against the core bril benchmark suite, and devised a naive algorithm that correctly enumerated all paths to test correctness. Additionally, we analyzed the runtime of our naive verification algorithm, and realized that brute force verification could be very slow. Overall, we collaborated on the dominator’s design decisions and ensured correctness. We also practiced good team coding practices with git, and learned a lot about dominators and global analysis as a whole! We believe we deserve a Michelin star for the creativity and persistence put into the task. |
Beta Was this translation helpful? Give feedback.






Uh oh!
There was an error while loading. Please reload this page.
-
In this task, you have implemented some fundamental operators on CFGs involving dominators!
Beta Was this translation helpful? Give feedback.
All reactions