This is an archive of the discontinued LLVM Phabricator instance.

[SimplifyCFG][PhaseOrdering] Defer lowering switch into an integer range comparison and branch until after at least the IPSCCP
ClosedPublic

Authored by lebedev.ri on Feb 15 2022, 8:55 AM.

Details

Summary

That transformation is lossy, as discussed in
https://github.com/llvm/llvm-project/issues/53853
and https://github.com/rust-lang/rust/issues/85133#issuecomment-904185574

This is an alternative to D119839.

Unlike lowering switch to lookup, we still want this transformation to happen
relatively early, but after giving a chance for the things like CVP to do their thing.
It seems like deferring it just until the IPSCCP is enough for the tests at hand,
but perhaps we need to be more aggressive and disable it until CVP.

Diff Detail

Event Timeline

lebedev.ri created this revision.Feb 15 2022, 8:55 AM
ormris removed a subscriber: ormris.Feb 15 2022, 10:40 AM
nikic added a comment.Feb 16 2022, 1:36 AM

This looks sensible to me.

Would it be sufficient to only block this transform in the very first (pre-inlining) SimplifyCFG run, which I think would allow IPSCCP to fold it? Or does only CVP handle this case?

lebedev.ri retitled this revision from [SimplifyCFG][CVP][PhaseOrdering] Defer lowering switch into an integer range comparison and branch until the end of function simplification pipeline to [SimplifyCFG][PhaseOrdering] Defer lowering switch into an integer range comparison and branch until after at least the IPSCCP.
lebedev.ri edited the summary of this revision. (Show Details)

This looks sensible to me.

Would it be sufficient to only block this transform in the very first (pre-inlining) SimplifyCFG run, which I think would allow IPSCCP to fold it? Or does only CVP handle this case?

For the tests in question it would appear IPSCCP is enough, so i've changed it accordingly.

wwei added a comment.Feb 16 2022, 3:56 AM

@lebedev.ri Thanks for the patch. Does convertSwitchRangeToICmp need to be set true for O1 pipeline? Why not keep the same with other SimplifyCFGOptions for O1?

@lebedev.ri Thanks for the patch. Does convertSwitchRangeToICmp need to be set true for O1 pipeline? Why not keep the same with other SimplifyCFGOptions for O1?

I'm not sure i understand the question.

This change disables the transform unless it's explicitly reenabled,
then explicitly reenables it for all the simplifycfg pass invocations in all pipelines,
and then un-enables it for those simplifycfg invocations that happen before IPSCCP.
Function simplification pipeline is after IPSCCP, so naturally the transform is enabled there.

wwei added a comment.Feb 16 2022, 4:25 AM

@lebedev.ri Thanks for the patch. Does convertSwitchRangeToICmp need to be set true for O1 pipeline? Why not keep the same with other SimplifyCFGOptions for O1?

I'm not sure i understand the question.

This change disables the transform unless it's explicitly reenabled,
then explicitly reenables it for all the simplifycfg pass invocations in all pipelines,
and then un-enables it for those simplifycfg invocations that happen before IPSCCP.
Function simplification pipeline is after IPSCCP, so naturally the transform is enabled there.

In buildO1FunctionSimplificationPipeline, adding SimplifyCFGOptions().convertSwitchRangeToICmp(true) for all CreateCFGSimplificationPass, I just wonder if this is necessary, since the performance for O1 is not that important

@lebedev.ri Thanks for the patch. Does convertSwitchRangeToICmp need to be set true for O1 pipeline? Why not keep the same with other SimplifyCFGOptions for O1?

I'm not sure i understand the question.

This change disables the transform unless it's explicitly reenabled,
then explicitly reenables it for all the simplifycfg pass invocations in all pipelines,
and then un-enables it for those simplifycfg invocations that happen before IPSCCP.
Function simplification pipeline is after IPSCCP, so naturally the transform is enabled there.

In buildO1FunctionSimplificationPipeline, adding SimplifyCFGOptions().convertSwitchRangeToICmp(true) for all CreateCFGSimplificationPass, I just wonder if this is necessary, since the performance for O1 is not that important

I don't know whether or not we should be doing that for -O1,
but that is a separate question from the one at hand.

nikic added inline comments.Feb 16 2022, 1:37 PM
llvm/include/llvm/Transforms/Utils/SimplifyCFGOptions.h
26

As we want to disable this essentially only for the first SimplifyCFG run, may make the default true?

llvm/lib/Transforms/Utils/SimplifyCFG.cpp
6566

This copy&pasted description doesn't sound quite right for this case. What we're losing here is information on values that branch to unreachable.

// The conversion from switch to comparison may lose information on
// impossible switch values, so disable it early in the pipeline.
lebedev.ri marked an inline comment as done.

Refine comment.

llvm/include/llvm/Transforms/Utils/SimplifyCFGOptions.h
26

I acknowledge that this is a tricky question,
but opting-into something lossy seems better
than ensuring that we opt-out everywhere,
so i've gone with that.
I don't think there is The Right choice here.

nikic accepted this revision.Feb 17 2022, 12:21 AM

LGTM

llvm/include/llvm/Transforms/Utils/SimplifyCFGOptions.h
26

I think this is mostly a pragmatic choice (if a new SimplifyCFG run gets added, which behavior should it most likely have?) but I don't care strongly about it...

This revision is now accepted and ready to land.Feb 17 2022, 12:21 AM
This revision was landed with ongoing or failed builds.Feb 17 2022, 1:14 AM
This revision was automatically updated to reflect the committed changes.