This is an archive of the discontinued LLVM Phabricator instance.

[InstCombine] Whitelist non-refining folds in SimplifyWithOpReplaced
ClosedPublic

Authored by nikic on Mar 20 2021, 1:08 PM.

Details

Summary

This is an alternative to D98391/D98585, playing things more conservatively. If AllowRefinement == false, then we don't use InstSimplify methods at all, and instead explicitly implement some non-refining folds. Most cases are handled by constant folding, and I only had to add two folds to cover our test cases. While this may lose some optimization power, I think it is safer to approach from this direction, given how many issues this has already caused.

Diff Detail

Event Timeline

nikic created this revision.Mar 20 2021, 1:08 PM
nikic requested review of this revision.Mar 20 2021, 1:08 PM
Herald added a project: Restricted Project. · View Herald TranscriptMar 20 2021, 1:08 PM
aqjune accepted this revision.Mar 20 2021, 8:01 PM

It is impressive that leaving the few patterns was enough to cover all existing unit tests.
If more patterns are needed, we can factor out the non-refined foldings from SimplifyXXInst as a static function and call it here.

Since ConstantFoldInstOperands can return a refined value as well, I gave a shot and disabled the folding if AllowRefinement = false.
However, it resulted in many unit test failures (implying that it will prevent a lot of optimizations). I couldn't write an input that involves constant folding but results in miscompilation either; so I think it is fine.

LGTM, but it would be good if someone else can double-check the diffs as well.

llvm/lib/Analysis/InstructionSimplify.cpp
3995–3996

This might make the result more refined as well, is it? ConstantFoldBinaryInstruction may fold undef/poison into a well-defined value.
I think it is better to leave a comment here saying the issue.

This revision is now accepted and ready to land.Mar 20 2021, 8:01 PM

LGTM - but see inline for general question/comment.

llvm/lib/Analysis/InstructionSimplify.cpp
3959–3960

I lost track of exactly what we mean by "refinement". The existing example in the code comment below + the test diffs in this patch suggest it is something like:
"Substitution with another value can't let poison flow where it did not before." ?
Are we getting in trouble with selects only or are there other opcodes with problems?

It can be independent of this patch, but we should make "refinement" clearer in the code comments here or in the header file comment where SimplifyWithOpReplaced() is declared.

nikic updated this revision to Diff 332158.Mar 21 2021, 8:00 AM

Add fold for binop + identity element. This is the only other relevant fold I found in test-suite. Shuffle comments a bit.

nikic added inline comments.Mar 21 2021, 8:16 AM
llvm/lib/Analysis/InstructionSimplify.cpp
3959–3960

Refinement means making a replacement like poison -> 0. This is legal. The select transform in question will take the simplification result (0) and replace it with the original instruction (poison). If the original simplification was a refinement, then this is a de-refinement, which is not legal. We can only make replacements that are valid in both directions, which requires the simplification result to be identical to the input. I believe the select optimization is the only place where we try to do something like this.

3995–3996

There is a TODO For this in the canCreatePoison comment, but it ended up a bit far from the code it affects. I've moved it directly before the constant folding code now, which is hopefully clearer.

aqjune added inline comments.Mar 21 2021, 7:51 PM
llvm/lib/Analysis/InstructionSimplify.cpp
3996

ok, looks good.

This revision was landed with ongoing or failed builds.Mar 22 2021, 2:13 PM
This revision was automatically updated to reflect the committed changes.