This is an archive of the discontinued LLVM Phabricator instance.

[ValueTracking] Fix a misuse of APInt in GetPointerBaseWithConstantOffset
ClosedPublic

Authored by mppf on Oct 3 2017, 6:21 AM.

Details

Summary

GetPointerBaseWithConstantOffset include this code, where ByteOffset
and GEPOffset are both of type llvm::APInt :

ByteOffset += GEPOffset.getSExtValue();

The problem with this line is that getSExtValue() returns an int64_t, but
the += matches an overload for uint64_t. The problem is that the resulting
APInt is no longer considered to be signed. That in turn causes assertion
failures later on if the relevant pointer type is > 64 bits in width and
the GEPOffset was negative.

Changing it to

ByteOffset += GEPOffset.sextOrTrunc(ByteOffset.getBitWidth());

resolves the issue and explicitly performs the sign-extending
or truncation. Additionally, instead of asserting later if the result
is > 64 bits, it breaks out of the loop in that case.

See also
https://reviews.llvm.org/D24729
https://reviews.llvm.org/D24772

This commit must be merged after D38662 in order for the test to pass.

Diff Detail

Repository
rL LLVM

Event Timeline

mppf created this revision.Oct 3 2017, 6:21 AM
aprantl added a subscriber: aprantl.Oct 3 2017, 9:14 AM

It would be better if the test would check for an actual different result rather than "it doesn't crash".

It would be better if the test would check for an actual different result rather than "it doesn't crash".

I agree.

lib/Analysis/ValueTracking.cpp
3081 ↗(On Diff #117516)

Do we need to add a check here that the offset can actually be represented in 64 bits? I don't think that a truncated return value here actually makes sense.

mppf added inline comments.Oct 4 2017, 7:51 AM
lib/Analysis/ValueTracking.cpp
3081 ↗(On Diff #117516)

getSExtValue does make sure it can be represented in an int64_t. If you were talking about using sextOrTrunc above, I think we need that truncation so that we can handle overflow in GEP operations so that we can handle negative GEP offsets correctly. (see my recent comment in D38499).

mppf edited the summary of this revision. (Show Details)Oct 5 2017, 7:19 AM
mppf updated this revision to Diff 117818.Oct 5 2017, 7:41 AM
  • [ValueTracking] Fix a misuse of APInt in GetPointerBaseWithConstantOffset
  • Improve test
mppf added a comment.Oct 5 2017, 7:47 AM

@aprantl / @hfinkel - I improved the test, does it look better? Oddly enough the code necessary to trigger the assert is in a section that isn't meaningfully changed by GVN. I just beefed up the test to also show a related case that GVN did usefully change. I'm having trouble doing any better than that with a reasonable amount of effort.

This one needs to merge after D38499, but other than that is it ready to go? Or does something else need to happen here?

Thanks!

The testcase seems fine now. I'll defer to Hal for the semantics of the actual change.

hfinkel added inline comments.Oct 5 2017, 1:33 PM
lib/Analysis/ValueTracking.cpp
3068 ↗(On Diff #117818)

We still need to make sure that the result doesn't overflow. I think something like this would work:

APInt OrigByteOffset(ByteOffset);

ByteOffset += GEPOffset.sextOrTrunc(ByteOffset.getBitWidth());
if (ByteOffset.getActiveBits() >= 64) {
  ByteOffset = OrigByteOffset;
  break;
}
efriedma added inline comments.
lib/Analysis/ValueTracking.cpp
3068 ↗(On Diff #117818)

Why does it matter if the result overflows? GEP arithmetic is wrapping.

3081 ↗(On Diff #117818)

Yes, you need a check to make sure the value can be represented in 64 bits. getSExtValue() will cause an assertion failure if it doesn't.

Granted, that's only relevant if you have pointers wider than 64 bits.

hfinkel added inline comments.Oct 5 2017, 1:59 PM
lib/Analysis/ValueTracking.cpp
3068 ↗(On Diff #117818)

Why does it matter if the result overflows? GEP arithmetic is wrapping.

For large pointers (as noted below). Since you mentioned the assertion, I'll note that its condition is a bit different, and we should match it here:

APInt OrigByteOffset(ByteOffset);

ByteOffset += GEPOffset.sextOrTrunc(ByteOffset.getBitWidth());
if (ByteOffset.getMinSignedBits() > 64) {
  ByteOffset = OrigByteOffset;
  break;
}
3081 ↗(On Diff #117818)

Yes, you need a check to make sure the value can be represented in 64 bits. getSExtValue() will cause an assertion failure if it doesn't.

You're right (I had thought it would silently saturate, so the situation is better than I thought).

Granted, that's only relevant if you have pointers wider than 64 bits.

Yes. Isn't that the point of this patch?

Yes. Isn't that the point of this patch?

Well, in theory there's a crash on trunk that can happen without exotic pointers (something like "gep i64, i64* %x, i128 INT128_MIN" will cause an assertion failure in getSExtValue().)

Well, in theory there's a crash on trunk that can happen without exotic pointers (something like "gep i64, i64* %x, i128 INT128_MIN" will cause an assertion failure in getSExtValue().)

Err, wait, nevermind, I misread the patch; that can't happen because it's calling accumulateConstantOffset, not visiting the offsets itself.

mppf updated this revision to Diff 117992.Oct 6 2017, 7:04 AM
  • Break from loop instead of asserting if size > 64 bits
mppf edited the summary of this revision. (Show Details)Oct 6 2017, 7:05 AM
mppf added a comment.Oct 6 2017, 7:07 AM

@hfinkel - I've made the change you requested. I think this one is good to go, but as I mentioned we need to commit it after another fix to BasicAA (such as D38499), or else the new test will fail with BasicAA assertions.

hfinkel accepted this revision.Oct 7 2017, 9:04 PM
In D38501#890491, @mppf wrote:

@hfinkel - I've made the change you requested. I think this one is good to go, but as I mentioned we need to commit it after another fix to BasicAA (such as D38499), or else the new test will fail with BasicAA assertions.

LGTM

This revision is now accepted and ready to land.Oct 7 2017, 9:04 PM
mppf added a comment.Jan 2 2019, 9:32 AM

Now that we have D38662, I'll look at getting this patch up to date and tested.

mppf edited the summary of this revision. (Show Details)Jan 2 2019, 9:32 AM
mppf updated this revision to Diff 179947.Jan 2 2019, 3:01 PM

Rebasing on current LLVM master

mppf added a comment.Jan 3 2019, 6:57 AM

@hfinkel - I think this change is ready to merge. I've rebased it on current LLVM trunk and run the tests. I've also verified that the new test fails (with an assertion failure) on LLVM trunk without this change. Thanks!

aprantl removed a subscriber: aprantl.Jan 3 2019, 12:54 PM
fhahn added a subscriber: fhahn.Jan 4 2019, 3:18 AM

Thanks! Do you need someone to commit the change on your behalf?

Thanks! Do you need someone to commit the change on your behalf?

He does. I'm planning to do it this morning, but if you do it first, that's fine too :-)

fhahn added a comment.Jan 4 2019, 5:59 AM

Thanks! Do you need someone to commit the change on your behalf?

He does. I'm planning to do it this morning, but if you do it first, that's fine too :-)

Right, I can commit it in a bit.

This revision was automatically updated to reflect the committed changes.