My opinion is that we should rewrite it. And not the speculation part, but the whole thing.
The first problem is that there is really no clear description of that this pass does. "Simplify CFG" is a catch-all term that includes every little change that could be argued to simplify things in certain circumstances, and this has lead to what we have now. We should specify what the callers can expect to happen. "Expect the CFG to be simplified" is not an adequate specification. This is not a pass where we should be making frequent changes, since anything that happens here can have far reaching consequences.
There are certain types of CFG transformations that are needed more frequently, like folding a branch to a branch, or eliminating empty blocks (as long as it doesn't damage loop structure). At the same time, things like generating switch statements is not something that needs to be attempted every time. Subtypes of CFG optimizations should be identified (e.g. cleanups, aggressive branch elimination, etc.) and there should be a parameter by which the caller would indicate which of these optimization groups should be run.
The recursive algorithm is not the best choice here. For a graph like a CFG, the entire structure of it is important. With the recursive nature of the code it can impossible to predict what it's going to do on any given graph, or determine why something predicted didn't actually happen. The algorithm should have a clear structure: first X happens, then Y, etc.
We should motivate the CFG simplification by what makes subsequent optimizations easier to implement and what exposes more opportunities to them, instead of "what helps my benchmark". Maybe targets should have hooks to perform specific modifications of the graph that may or may not be good for everyone.