Use control-flow information to improve handling of returns

#16081 fixed an issue where a nested return statement would cause incorrect behaviour due to the inner return writing over the return stack slot that had already been written too. However, the check was very broad and picked many cases that wouldn't ever be affected by this issue.

As a result, the number of allocas increased dramatically and therefore stack-size increased. LLVM is not able to remove all of the extraneous allocas. Any code that had multiple return values in a compound expression at the end of a function (including loops) would be hit by the issue.

The check now uses a control-flow graph to only consider the case when the inner return is executed conditionally. By itself, this narrowed definition causes #15763 to return, so the control-flow graph is also used to avoid passing the return slot as a destination when the result won't be used.

This change allows the stack-size of the main rustc task to be reduced to 8MB from 32MB.
Well it's only for blocks that have a non-nil return type, and only when the destination is not `Ignore`. That pretty much limits it only to when this check is needed. i.e. when the result *should* be ignored, but it isn't obvious.