This is an archive of the discontinued LLVM Phabricator instance.

[SeparateConstOffsetFromGEP] Fix bug handling negative offsets
ClosedPublic

Authored by tstellar on Apr 28 2023, 8:09 PM.

Details

Summary

Fix bug constants and sub instructions

When finding constants in a chain starting with the RHS operator of
sub instructions, we were negating the constant before zero extending
it, which is incorrect.

Unfortunately, I was unable to find a simple way to implement this
transformation correctly, so for now I just disabled this optimization
for constants that feed into the RHS of a sub.

Resolves #62379

Transformation from alive2.llvm.org:

define i16 @src(i8 %a, i8 %b, i8 %c) {
entry:
%0 = sub nuw nsw i8 %c, %a
%1 = sub nuw nsw i8 %b, %0
%2 = zext i8 %1 to i16
ret i16 %2
}

Before/Bad:

define i16 @tgt(i8 %a, i8 %b, i8 %c) {
entry:
%0 = zext i8 %a to i16
%1 = zext i8 %b to i16
%c_neg = sub i8 0, %c
%c_zext = zext i8 %c_neg to i16
%2 = sub i16 0, %0
%3 = sub i16 %1, %2
%4 = add i16 %3, %c_zext
ret i16 %4
}

Correct:

define i16 @tgt(i8 %a, i8 %b, i8 %c) {
entry:
%0 = zext i8 %a to i16
%1 = zext i8 %b to i16
%c_zext = zext i8 %c to i16
%c_neg = sub i16 0, %c_zext
%2 = sub i16 0, %0
%3 = sub i16 %1, %2
%4 = add i16 %3, %c_neg
ret i16 %4
}

Diff Detail

Event Timeline

tstellar created this revision.Apr 28 2023, 8:09 PM
Herald added a project: Restricted Project. · View Herald TranscriptApr 28 2023, 8:09 PM
tstellar requested review of this revision.Apr 28 2023, 8:09 PM
Herald added a project: Restricted Project. · View Herald TranscriptApr 28 2023, 8:09 PM
nikic added a comment.Apr 29 2023, 1:27 AM

Haven't looked at the code change yet, but I'm pretty sure the test can use -passes='separate-const-offset-from-gep<lower-gep>' instead of adding a new opt flag.

Transforming zext(A op B) to zext(A) op zext(B) should guarantee that A and B are non-negative. I think it would be better to do this fix during ConstantOffsetExtractor::CanTraceInto.

Transforming zext(A op B) to zext(A) op zext(B) should guarantee that A and B are non-negative. I think it would be better to do this fix during ConstantOffsetExtractor::CanTraceInto.

The problem I'm running into is that it's very difficult to to prove a value is non-negative, so adding those kinds of checks into CanTraceInto more or less disables the pass. The pass also makes an incorrect assumption that operands to an inbounds GEP are always non-negative. And it's not just assuming that direct operands to inbounds GEPS are non-negative, it assumes that any operands in the tree of values feeding into the GEP are non-negative.

With some help from @nikic, I discovered that the bug is much more narrow in scope than I thought initially, so I should be able to do a more targeted fix.

tstellar updated this revision to Diff 518596.May 1 2023, 4:26 PM

Use a more targetted fix.

tstellar edited the summary of this revision. (Show Details)May 1 2023, 4:27 PM
tstellar edited the summary of this revision. (Show Details)
nikic accepted this revision.May 2 2023, 5:32 AM

This looks reasonable to me, but maybe wait a bit in case @Peakulorain has a better suggestion.

https://github.com/llvm/llvm-project/blob/1d0ccebcd725309399262af346494242b064e2ed/llvm/lib/Transforms/Scalar/SeparateConstOffsetFromGEP.cpp#L590-L593 is the code negating the offset.

This revision is now accepted and ready to land.May 2 2023, 5:32 AM

Since more knowledgeable people gived professional advice, it is also ok for me. :)

tstellar updated this revision to Diff 518708.May 2 2023, 6:49 AM

Delete now dead code that was negating the constant.

This looks reasonable to me, but maybe wait a bit in case @Peakulorain has a better suggestion.

https://github.com/llvm/llvm-project/blob/1d0ccebcd725309399262af346494242b064e2ed/llvm/lib/Transforms/Scalar/SeparateConstOffsetFromGEP.cpp#L590-L593 is the code negating the offset.

I actually meant to delete that code in this patch, so I've updated the patch to take it out.

nikic added a comment.May 2 2023, 6:51 AM

This looks reasonable to me, but maybe wait a bit in case @Peakulorain has a better suggestion.

https://github.com/llvm/llvm-project/blob/1d0ccebcd725309399262af346494242b064e2ed/llvm/lib/Transforms/Scalar/SeparateConstOffsetFromGEP.cpp#L590-L593 is the code negating the offset.

I actually meant to delete that code in this patch, so I've updated the patch to take it out.

Hm, why is it safe to delete that code? Don't we still need it in the case where we have no extension or a sign extension?

tstellar updated this revision to Diff 518754.May 2 2023, 8:34 AM

Add back negation code.

This looks reasonable to me, but maybe wait a bit in case @Peakulorain has a better suggestion.

https://github.com/llvm/llvm-project/blob/1d0ccebcd725309399262af346494242b064e2ed/llvm/lib/Transforms/Scalar/SeparateConstOffsetFromGEP.cpp#L590-L593 is the code negating the offset.

I actually meant to delete that code in this patch, so I've updated the patch to take it out.

Hm, why is it safe to delete that code? Don't we still need it in the case where we have no extension or a sign extension?

Yes, I've added it back.

This revision was landed with ongoing or failed builds.May 4 2023, 6:46 PM
This revision was automatically updated to reflect the committed changes.