This is an archive of the discontinued LLVM Phabricator instance.

Fixed several correctness issues on mishandling s/zext in SeparateConstOffsetFromGEP
ClosedPublic

Authored by jingyue on Jun 1 2014, 7:31 PM.

Details

Reviewers
eliben
meheff
Summary

Fixes:

  • When rebuilding new indices, s/zext should be distributed to sub-expressions. e.g., sext(a +nsw (b +nsw 5)) = sext(a) + sext(b) + 5 but not sext(a + b) + 5. This also affects the logic of recursively looking for a constant offset, we need to include s/zext into the context of the searching.
  • Function find should return the bitwidth of the constant offset instead of always sign-extending it to i64.
  • Stop shortcutting zext'ed GEP indices. LLVM conceptually sign-extends GEP indices to pointer-size before computing the address. Therefore, gep base, zext(a + b) != gep base, a + b

Improvements:

  • Add an optimization for splitting sext(a + b): if a + b is proven non-negative (e.g., used as an index of an inbound GEP) and one of a, b is non-negative, sext(a + b) = sext(a) + sext(b)
  • Function Distributable checks whether both sext and zext can be distributed to operands of a binary operator. This helps us split zext(sext(a + b)) to zext(sext(a) + zext(sext(b)) when a + b does not signed or unsigned overflow.

Refactor:

  • Merge some common logic of handling add/sub/or in find.

Add many tests in split-gep.ll and split-gep-and-gvn.ll to verify the changes we made.

Diff Detail

Event Timeline

jingyue updated this revision to Diff 9999.Jun 1 2014, 7:31 PM
jingyue retitled this revision from to Fixed several correctness issues in SeparateConstOffsetFromGEP.
jingyue updated this object.
jingyue edited the test plan for this revision. (Show Details)
jingyue added a reviewer: eliben.
jingyue added a subscriber: Unknown Object (MLST).
eliben edited edge metadata.Jun 2 2014, 9:19 AM

The amount of change here is very large - seems like you combined the functional fixes with some refactoring. It would be helpful if the commit message went into more detail about the refactoring as well.

jingyue retitled this revision from Fixed several correctness issues in SeparateConstOffsetFromGEP to Fixed several correctness issues on mishandling s/zext in SeparateConstOffsetFromGEP.Jun 2 2014, 2:48 PM
jingyue updated this object.
jingyue edited edge metadata.
meheff edited edge metadata.Jun 3 2014, 11:44 PM

Looks pretty good, in general. It was a bit tough to reason about in places, but I think that had to do with the complexity of wrapping my head around how sext/zext work across operators as much as anything. I don't have great suggestions for making it significantly simpler.

lib/Transforms/Scalar/SeparateConstOffsetFromGEP.cpp
279

Are XOR and AND handled properly? OR is limited to cases where it is equivalent to add so no problem there, but it seems like hoisting a constant out of a XOR or AND expression would be problematic.

374

Can this OR logic be moved up into Distributable or maybe move Distributable logic here? In general, I found find() a bit tricky to follow and reason about. Some of it is due to the complexity about the sext/zext identities you have to use, but some it was because the logic for checking whether you can traverse beneath an operator is in more than one place.

391

Is UserChain updated properly in the case where the constant is negative? Seems like you could have some elements added to UserChain in the call to findInEitherOperand above then it hits this condition and returns 0 and searching begins along another branch in the expression with stale elements in UserChain.

Also, if ConstOffset is nonnegative does that necessarily guarantee that one of the operands of the add is nonnegative? The constant could be down more than one level in the expression, right?

466

Why is the type of ExtInsts[0] used here rather than the last element of ExtInsts which would be closest to the constant?

485

Should be: ...is *not* the RHS of a sub. Also, I think it'd be a bit clearer if your logic was in the same form as your comment like so:

if (I->isZero() && !(BO->getOpcode() == Instruction::Sub && OpNo == 0)) {

Or alternatively change the comment logic.

jingyue updated this revision to Diff 10154.Jun 5 2014, 1:21 PM
jingyue edited edge metadata.

Mark, thanks for your reviews! I fixed all the issues you spotted. PTAL

jingyue added inline comments.Jun 5 2014, 1:36 PM
lib/Transforms/Scalar/SeparateConstOffsetFromGEP.cpp
279

Good catch! Fixed by ignoring XOR and AND.

374

Merged the logics for OR, ADD and SUB into CanTraceInto.

391

Good catch * 2!

The new code only traces into sext(a + b) (without nsw) if a + b >= 0 and one of a and b is non-negative. Therefore, we needn't worry about restoring UserChain any more.

466

We distribute s/zext all the way down UserChain, so the type should be the outmost type.

e.g., after distributing s/zext, zext(sext(a + (b + 5)) (assuming no overflow) becomes zext(sext(a)) + (zext(sext(b)) + zext(sext(5))). Then, removing constant offset 5 leaves zext(sext(a)) + (zext(sext(b)) + zext(sext(0))). The type of zext(sext(0)) is the type of the outmost zext.

To make the logic of rebuildWithoutConstOffset clearer, I split it into two steps: distributing s/zext and removing the constant offset. Although the code may run slower (two passes instead of one), the logic should be much simpler to follow. PTAL

485

You're right. Done

meheff added a comment.Jun 5 2014, 2:16 PM

LGTM. I like the restructuring of the traversal logic. It's easier to follow now.

lib/Transforms/Scalar/SeparateConstOffsetFromGEP.cpp
302

True for zext as well? If so, please add to comment.

429–461

nit: maybe call function distributeExtsAndCloneChain.

503

Can number of users ever be zero? That is, can't you assert B0->getNumUses() == 1?

504

If you change the name of distributeExt, you'll have to change it here as well.

jingyue updated this revision to Diff 10157.Jun 5 2014, 2:47 PM

Addressed all Mark's comments.

lib/Transforms/Scalar/SeparateConstOffsetFromGEP.cpp
302

Yes, although not leveraged just yet.

429–461

done

503

UserChain[0], the future GEP index, is not linked in the program yet, and is unused.

504

Done.

meheff accepted this revision.Jun 5 2014, 3:17 PM
meheff edited edge metadata.
This revision is now accepted and ready to land.Jun 5 2014, 3:17 PM
jingyue closed this revision.Jun 5 2014, 3:18 PM

r210291