stdlibCore now always lowers ownership /after/ running the diagnostic passes

Hello everyone!

Early this morning, I flipped the switch causing stdlibCore to always lower ownership /after/ running the diagnostic passes. This is a large milestone for ownership in general since this is the first time we have exposed some passes downstream of the Mandatory Inlining to ownership in the build itself (vs tests). It will ensure that changes in tree do not break basic functionality when we are in this mode (something that I have run into).

A few big notes:

  1. This is just a temporary staging measure as I push ownership lowering further back into the pipeline and maintain correctness. The next step is to expand it first to the overlays and then to the "world".
  2. The select group of passes in between Mandatory Inlining and the beginning of the diagnostic pipeline must handle both ossa and non-ossa code.

For those just listening in, I put a description of what is happening below:


For anyone who is unaware, the larger piece of work here is moving ossa back through the pass pipeline to be after serialization. There are a number of interlocking challenges here that are incrementally being worked around:

  • We cannot inline functions that have already had ownership lowered into functions with ownership** (NOTE: We can go the other way).
  • Since the diagnostic passes never lower ownership when we are compiling with this flag enabled, we need to ensure that any transparent functions we need to mandatory inline have not had ownership lowered. This means that whenever we must always serialize transparent functions without ownership lowered.
  • At -O, we have not updated all of the optimizer passes for ownership meaning that they may not be safe or be ineffective to run on ossa. This is an issue since many of these passes run before we serialize at -O, implying that we must lower ownership before those passes and thus before serialization.

So we get the implication that at -O if we want to optimize functions before serialization, we must lower ownership, yet we cannot lower ownership for transparent functions until after serialization. A contradiction!

To work around this, we take advantage of the nature of transparent functions: they are always inlined except if they are used via indirection (e.x.: calling via a class_method instruction via a witness table from a different module). So even if we disable the front 1/2 of the pass pipeline, in 99% of the use sites we will just inline into callers and then optimize there. Even in the cases where we have a witness table, we re-run a large part of the pipeline after we serialize so we shouldn't hit perf.

Thus, the way that I am threading the needle here is that:

  1. If the option is enabled, then when we compile -O, we run:
-O:
1. Diagnostic Passes.
2. Lower ownership on everything except for transparent functions.
3. Run optimization passes up to serialization, skipping any functions that still have ownership (which will be only transparent functions).
4. Serialize.
5. Lower ownership from everything and lower ownership from any code that is further deserialized.
6. Rest of performance passes.

The key thing to notice is that since we haven't lowered/optimized the transparent functions, any code that links in transparent functions for Mandatory Inlining.

  1. If the option is enabled, then for -Onone we do the obvious thing:
-Onone:
1. Diagnostic Passes.
2. Serialize.
3. Lower ownership.
4. Run use specialized and small late passes.
  1. If this option is disabled, we lower ownership before we deserialize anything (in the guaranteed passes) and will lower ownership on any functions from other functions that we link in as we deserialize. So the "world" according to the compiler when the option is disabled is unchanged.

NOTE: In the previous I assumed that the option was staged in by enabling it first on stdlibCore, then overlays/tests, and finally on everything. This ensures that no libraries at each point that are compiled with the new mode are downstream of any code compiling in the early ownership lowering mode.

13 Likes

Exciting! I wonder if these changes (moving ossa later in the compiler pipeline) have user-facing impact?

It will in that I will be able to move the new ARC optimizer further back and add some inlining/load promotion before it magnifying its overall effect on performance.

It also will enable us to fix correctness issues in the current pass pipeline as we go (since we will have to express the optimizations in a safe manner, redesigning slightly potentially since some of the unsafe things we do not can not even be expressed in ossa.

5 Likes

Very awesome! Loving seeing these improvements moving forward, looking forward to seeing what this unlocks for the ARC optimiser.

Just as a follow up to this, I just enabled this on the overlays. Now the vast majority of tests that just depend on the stdlib/overlays can run in either mode. This is going to help me to finish landing this by allowing me to modify certain *.swift test files to run in both modes to prevent them from breaking.

In other words, once I finish fixing one of these tests (some of which I have fixed 3 times ; p), I will not have to re-fix them.