This is an archive of the discontinued LLVM Phabricator instance.

[InstCombine] reverse canonicalization of binops to allow more shuffle folding
ClosedPublic

Authored by spatel on Jun 27 2018, 10:42 AM.

Details

Summary

This is a superset of D48485 that includes transforming an 'or' back into an 'add' in addition to the shl+mul case shown there.

Here, we need value tracking to determine that the 'or' can be reversed into an 'add'.

IIUC, there are only a handful of opcodes where we'll try this. To repeat from the other review - I think we're distinguishing this pattern from the scenario where we have eliminated a binop completely and need to materialize a 'ghost' op with an identity constant.

Diff Detail

Repository
rL LLVM

Event Timeline

spatel created this revision.Jun 27 2018, 10:42 AM

I'm guessing this superseded D48485, which should be closed?
Also, is D48678 supposed to go on top of this, or trunk?

I'm guessing this superseded D48485, which should be closed?
Also, is D48678 supposed to go on top of this, or trunk?

Each patch can be applied to trunk as-is. I posted this one to show one way that D48485 could be extended, so yes this one would obsolete D48485 if we want to make a larger change all at once. But my preference is to make the smaller change first to reduce risk. Ie, I think D48485 should be reviewed/committed, then we can make some NFC changes in preparation for this patch (and I need to add more tests). If we take that route, this patch will shrink to just adding one more 'case' to the switch.

D48678 is also against trunk, so it can be reviewed as a stand-alone patch. I wanted to demonstrate that the 2-variable case is a small add-on either way. Given that, maybe it's easier to start there because that part won't have any follow-ups AFAIK.

I'm guessing this superseded D48485, which should be closed?
Also, is D48678 supposed to go on top of this, or trunk?

Each patch can be applied to trunk as-is. I posted this one to show one way that D48485 could be extended, so yes this one would obsolete D48485 if we want to make a larger change all at once. But my preference is to make the smaller change first to reduce risk. Ie, I think D48485 should be reviewed/committed, then we can make some NFC changes in preparation for this patch (and I need to add more tests). If we take that route, this patch will shrink to just adding one more 'case' to the switch.

Then i would suggest to do so now:

  1. Update D48485 with this patch minus the Instruction::Or handling.
  2. Update this D48662 - on top of D48485 (so the diff is relative), add Instruction::Or handling.

Will simplify reviewing, and signal the review order :)

D48678 is also against trunk, so it can be reviewed as a stand-alone patch. I wanted to demonstrate that the 2-variable case is a small add-on either way. Given that, maybe it's easier to start there because that part won't have any follow-ups AFAIK.

Yeah, that one looks really simple. I'll try to review that one..

Please rebase once D48678 lands too.

spatel updated this revision to Diff 153502.Jun 29 2018, 8:43 AM

Patch updated:

  1. Rebased now that D48485 / D48678 are committed.
  2. Added more tests with rL335984.
RKSimon added inline comments.Jun 29 2018, 9:02 AM
lib/Transforms/InstCombine/InstCombineVectorOps.cpp
1155 ↗(On Diff #153502)

Better to do this as an Optional<BinopElts> ?

lebedev.ri added inline comments.Jun 29 2018, 9:20 AM
lib/Transforms/InstCombine/InstCombineVectorOps.cpp
1158 ↗(On Diff #153502)
// shl X, C --> mul X, (1 << C)
1215–1216 ↗(On Diff #153502)
  1. Why are you checking isa<Constant>()? Right now that can be an assertion. Future-proofing?
  2. How about just adding BinopElts::operator bool() const and doing
if(BinopElts AltB0 = getAlternateBinop(B0, DL))

Or Optional<> like @RKSimon suggests.
?

spatel updated this revision to Diff 153526.Jun 29 2018, 10:29 AM
spatel marked 2 inline comments as done.

Patch updated - no functional changes from the last rev, but:

  1. Add a "operator bool()" to make the code cleaner.
  2. Assert that operand 1 of the alternate binop is a constant (might change as we add more cases).
  3. Improve formula in code comment with parens.

Other than the flags question, i think this is ok.

lib/Transforms/InstCombine/InstCombineVectorOps.cpp
1181 ↗(On Diff #153526)

return {}; doesn't work?
Elsewhere too, i don't think you need to specify BinopElts.

test/Transforms/InstCombine/shuffle_select.ll
600 ↗(On Diff #153526)

Too bad alive does not work with vectors :/
I'm not sure i understand why we drop nuw but keep nsw.
If anything, i'd guess the or is implicit nuw,
so i would be less suprized if we dropped nsw instead.

spatel planned changes to this revision.Jun 29 2018, 12:22 PM
spatel added inline comments.
lib/Transforms/InstCombine/InstCombineVectorOps.cpp
1181 ↗(On Diff #153526)

That works. I wasn't sure if there's some LLVM pref/reason to do it this way (example: return SDValue() in codegen).

test/Transforms/InstCombine/shuffle_select.ll
600 ↗(On Diff #153526)

This transform drops the flags since 'or' has no wrapping.
We add back the 'nsw' in visitAdd, but it doesn't find 'nuw' is possible (a shortcoming in computeOverflowForUnsignedAdd)...it should be both I think.

spatel updated this revision to Diff 153557.Jun 29 2018, 12:43 PM

Patch updated:
Use less wordy {} struct initialization for return vals.

RKSimon accepted this revision.Jul 2 2018, 9:24 AM

LGTM - thanks

lib/Transforms/InstCombine/InstCombineVectorOps.cpp
1181 ↗(On Diff #153526)

Hmm, still think using Optional<> is cleaner, but this is OK.

test/Transforms/InstCombine/shuffle_select.ll
600 ↗(On Diff #153526)

Please can you raise this as a poor codegen bug?

This revision is now accepted and ready to land.Jul 2 2018, 9:24 AM
spatel added inline comments.Jul 2 2018, 10:22 AM
test/Transforms/InstCombine/shuffle_select.ll
600 ↗(On Diff #153526)
This revision was automatically updated to reflect the committed changes.