[MISched] Implement `UnanalyzableFrontier`-based DAG construction algorithm (#227375)
Introduces a new algorithm for constructing the control dependencies in
the schedule DAG. The new algorithm is gated behind a (temporary)
`cl::opt` (`-enable-unanalyzable-store-sequencing`), currently off by
default. With the option disabled, the change is an effective NFC: edge
insertion order changes slightly, but the DAGs do not change materially.
The difference between this algorithm and the existing algorithm is
that, rather than maintaining all unanalyzable memory operations and
repeatedly querying all of them, we instead maintain a frontier of loads
and stores since a 'sequencing store'. A sequencing store is either (a)
a store that writes to different set of base objects to the last seen
sequencing store or (b) any store if there has been a load from another
base object since the last sequencing store. We treat the sequencing
stores carefully to ensure that all previously seen unanalyzable memory
operations that do not belong to the frontier necessarily transitively
succeed the current sequencing store. This makes it sound to sequence
preceding memory operations against the sequencing store and only those
other memory operations in the frontier at the cost of some spurious
control dependencies. In large basic blocks this can dramatically reduce
the number of AA queries we issue.
The plan is to land this change first, and issue a follow-up to enable,
giving us a chance to deal with any performance bugs on other backends.
Once enabled, I will revisit the interaction with
`-dag-maps-huge-region` as, at present, the `-dag-maps-huge-region`
logic frequently fires needlessly in situations where the frontier
already successfully dealt with the complexity.