In my experience the biggest (or most annoying?) problem though is not setting up the dependencies and executing the steps along the DAG but doing the configuration part of a build: What libraries are installed on the system, giving the user ways to opt in/out of build-time features, figuring out how to build shared libraries on the target OS, how to crosscompile, there’s tons of of these that may need solving depending on your project.
ninja does a fantastic job about handling the core and leaving all the other annoying things for someone else to solve (like cmake with the ninja backend :)
I am not convinced it's that simple if 1 application of jump threading creates a new opportunity.
The endlessly unreliable loop example in the post suggests that is is a halting problem to find out whether we should stop jump threading because we are unrolling an endless loop or not.
And there is a script bisecting functions when given assembly produced by working baseline and “bad” compiler to compare: https://github.com/llvm/llvm-project/blob/main/llvm/utils/ab...