Closed
Description
#33566 introduces an optimisation which speeds up LLVM greatly. My suspicion is that this optimisation is also very relevant to the MIR pipeline (i.e. MIR transformations ought to be slower to analyse and transform the switches with more branches). Thus we should port this optimisation over to a MIR pass down the line.
Moreover, the code in the PR relies on the assumption that the otherwise
branch of the switches is always unreachable. This assumption has potential to become not true after we get more complex optimisations on the MIR going. Having such optimisation to be a plain MIR transformation would help with this too.
cc @dotdash
Metadata
Metadata
Assignees
Type
Projects
Milestone
Relationships
Development
No branches or pull requests
Activity
Aatch commentedon May 19, 2016
The question is whether to change the
Switch
terminator to be non-exhaustive or make a new terminator instead. MakingSwitch
non-exhaustive seems like the better option to me, as I'm not sure what the value of having two almost-identical instructions is.Also, it being non-exhaustive means we can build the initial MIR a bit smarter. There are often cases where we can narrow down the candidates based on the fact that previous arms weren't taken:
I'm pretty sure the existing code tries to handle this already, I know old trans does.
nagisa commentedon May 20, 2016
IMO we should remove switch altogether. A big part of MIR is getting rid of things tied to language (e.g. we have no for, while etc loops, only a goto), but we (due to historical accidents, already!) have both the
Switch
andSwitchInt
, whereSwitch
is just a glorified version ofSwitchInt
that works on enum discriminants only.What I think we ought to do, is:
Lvalue
projection for the discriminant;Switch
and replace that withSwitchInt
ondiscr(Lvalue)
.The only downside I see – we would end up duplicating the values being
Switch
ed on with ones inAdtDef
, but if we want to makeSwitch
non-exhaustive that is necessary anyway.nagisa commentedon May 20, 2016
Incidentally that should also decrease our reliance on trans::adt greatly.
nagisa commentedon May 20, 2016
also cc @nikomatsakis, in case you want to discuss this.
nikomatsakis commentedon May 20, 2016
Unsurprisingly, I do have an opinion:
Switch
andSwitchInt
. I see why it's appealing, and it may well make sense -- along these lines, maybe we should unifySwitchInt
andIf
-- but I have two reservations:let discrim = if x != null { 1 } else { 0 }; if discrim == 1 { ... } else { ... }
)I'm not sure how much to weigh the first point. It seems like it's probably good to keep in mind, but bad to be overly constrained by this -- after all, if we want to change things later, we can do so, and it's clear that we don't know the full set of constraints right now.
Another way to look at unifying
Switch
andSwitchInt
is that it's the kind of lowering that makes sense to do before trans for sure, but it's a semantic distinction I could imagine wanting to preserve during static checking.Finally, I imagine we could bridge the gap just by making
Switch
kind of polymorphic over the type of discriminant:In other words, we wouldn't generate code like:
but just
nikomatsakis commentedon May 23, 2016
So @scottcarr is starting up an internship and I was thinking this would make a good starter problem for him (presuming nobody else is hacking on it just now?). I was thinking specifically not of modifying the MIR in any particular way, but just modifying the MIR generation to not build a basic block for every variant, but instead to be more selective. (In other words, it would directly generate the IR that we wind up optimizing to.)
We could also change the IR, but the two things seem somewhat orthogonal to me.
nikomatsakis commentedon May 26, 2016
Here are some test cases (just for reference) that exhibit the N^2 blowup we observed (at least initially). Note that the one that uses integral constants does not: I think the simplest fix to the blowup is just to have the enum case use a similar pattern to what constants do, where it figures out which variants are "of interest" and creates an otherwise-like block to use as the target for the remainder (we might also change the IR; just seems orthogonal).
https://gist.github.com/nikomatsakis/dc3641659919d11b01a6fc14051831bd
nagisa commentedon Mar 12, 2017
I think this is done now after we switched to the SwitchInt everywhere.