This is an archive of the discontinued LLVM Phabricator instance.

[InstSimplify] Propagate AllowRefinement info from SimplifyWithOpReplaced
AbandonedPublic

Authored by aqjune on Mar 10 2021, 9:19 PM.

Details

Summary

SimplifyWithOpReplaced has AllowRefinement argument, but when it further calls SimplifyXXX,
the flag isn't properly passed.
This causes the simplifying calls to fold possibly-poison values into non-poison constant
even if AllowRefinement is set to false.

This causes miscompilation https://llvm.org/pr49495.
simplifySelectWithICmpCond calls SimplifyWithOpReplaced with AllowRefinement set to false.
However, the information is lost, causing computePointerICmp to do folding based on inbounds flag.
computePointerICmp transforms (gep inbounds x, -1) >u x into -1 >s 0 which is correct only if
inbounds is set (https://alive2.llvm.org/ce/z/mGwYxH vs. https://alive2.llvm.org/ce/z/e-2KQh ).

To fix this, this patch updates simplifySelectWithICmpCond to call SimplifyWithOpReplaced with Q.getWithoutRefinement().
SimplifyQuery::getWithoutRefinement() is a new method that simply returns a new object with relevant flags set to false.
If this flag is set, simplifications cannot fold the value into a more defined one.

This wasn't enough to fix the pointer folding, and I updated computePointerICmp and its relevant calls to respect relevant flags.

Diff Detail

Event Timeline

aqjune created this revision.Mar 10 2021, 9:19 PM
aqjune requested review of this revision.Mar 10 2021, 9:19 PM
Herald added a project: Restricted Project. · View Herald TranscriptMar 10 2021, 9:19 PM
aqjune added inline comments.Mar 10 2021, 9:22 PM
llvm/test/Transforms/InstCombine/select.ll
2766 ↗(On Diff #329838)

This is a regression; after this patch is landed, I'll make a fix for this.

aqjune updated this revision to Diff 329842.Mar 10 2021, 9:28 PM

Fix deoptimized case

Confirmed that this resolves the regression (https://reviews.llvm.org/D95026#2610334) from two-stage build!

nikic added a comment.Mar 12 2021, 2:27 AM

I'm not sure this is moving in the right direction. It should be noted that the primary refinement problem in SimplifyWithOpReplaced, which we have encountered in various forms in the past, is along the lines of folding add nuw UINT_MAX, 1 to 0 and thus refining poision to zero. The key here is that this would be valid without the nuw flag. This is the converse problem of what UseInstrInfo is solving. In fact, if add nuw UINT_MAX, 1 is folded to poison, then that result is okay to use, as no refinement occurs. This can also be seen in the changes to stripPointerCasts you are making -- effectively you are preventing optimization across inbounds GEP, even though the point of UseInstrInfo is to optimize without making use of the inbounds information.

I don't think there's any easy principled solution here, so what I'd do instead is to just extend the existing canCreatePoison() hack, which has served us well enough in practice, to also go one level up for compare instructions. (The more definitive way to prevent issues is to check that it isGuaranteedNotUndefOrPoison, but I expect that this would break many transforms.)

TBH, I don't feel comfortable with extending the canCreatePoison() check. :( Even if it requires inspection of foldings in InstSimplify, I think a safer way is to add a flag that disallows foldings returning refined values.
Let me update this patch and write following patches for updating them.

aqjune retitled this revision from [InstSimplify] Set UseInstrInfo to false when calling SimplifyWithOpReplaced to [InstSimplify] Propagate AllowRefinement info from SimplifyWithOpReplaced.Mar 13 2021, 8:34 AM
aqjune edited the summary of this revision. (Show Details)
aqjune updated this revision to Diff 330452.Mar 13 2021, 8:34 AM

Add AllowRefinement field

aqjune updated this revision to Diff 330453.Mar 13 2021, 8:36 AM

minor updates

aqjune updated this revision to Diff 330506.Mar 14 2021, 6:58 AM

Make computePointerICmp slightly more conservative if Q.AllowRefinement is false

It is folding possibly poison/undef value into a well-defined constant.

aqjune edited the summary of this revision. (Show Details)Mar 14 2021, 7:00 AM

Does this direction look okay? @nikic
One benefit of this approach is that it detects unsafe replacements that have non-poison-creating instructions as well.
For example, this transformation is illegal:

  %v = select (x == 0), 0, (x & y)
=>
  %v = x & y

If x = 0 and y was poison this makes the result more undefined. However, the current check relying on canCreatePoison cannot detect this.
D98585 fixes this by making the relevant transformation respect Q.AllowRefinement.

This change is about making the existing check safer than before: if the change causes a problem with generating optimal code I'll look into it.

aqjune added a comment.EditedMar 17 2021, 6:26 AM

In terms of maintenance: if reviewers think the complexity this patch is introducing is big to maintain, I'll turn this patch to using canCreatePoison check since it will fix the bug (pr49495) anyway.

nikic added a comment.Mar 20 2021, 2:04 PM

I've put up D99027 as a possible alternative, though I'm not really sure yet which approach is best here. My premise is that for the AllowRefinement=false case the main thing we care about are the constant folding cases, plus a small set of additional folds. This avoids infecting the rest of InstSimplify with another parameter, and we can't run into issues when we forgot the check the flag somewhere. On the other hand, this approach may lose optimization power.

aqjune abandoned this revision.Mar 22 2021, 5:33 PM

Closed in favor of D99027