Add `ashr` instruction to the DAG post-dominated by `trunc`, allowing `TruncInstCombine` to reduce bitwidth of expressions containing these instructions. We should be shifting by less than the target bitwidth. Also it is sufficient to require that all truncated bits of the value-to-be-shifted are sign bits (all zeros or ones) and one sign bit is left untruncated: https://alive2.llvm.org/ce/z/Ajo2__ Part of https://reviews.llvm.org/D107766
Details
Diff Detail
- Repository
- rG LLVM Github Monorepo
Event Timeline
I'm pretty sure we should count the number of sign bits here, much like how we count the number of leading zeros:
https://godbolt.org/z/vGsf664Gf => https://alive2.llvm.org/ce/z/gIc43E
Ok, I've extended both lshr and ashr to use countMinSignBits(), unifying both cases, but we have to computeKnownBits() one more time here.
llvm/lib/Transforms/AggressiveInstCombine/TruncInstCombine.cpp | ||
---|---|---|
299–307 |
llvm/lib/Transforms/AggressiveInstCombine/TruncInstCombine.cpp | ||
---|---|---|
295–298 | Ok, I'm to split this | |
299–307 | I've intentionally merged this two cases, since ashr and lshr processing doesn't differ. What really matters is positivity/negativity of their operand. This is symmetrical cases (see updated summary). For instance, for your change we still have to replace ashr with lshr if sign bits were zeros and with ashr if sign bits were ones. Why not to do the same for lshr? | |
409–410 | If sign bits were ones we have to replace original shift with ashr, lshr doesn't work (see @lshr_negative_operand_but_short() test). |
This patch does not apply for me.
Please precommit the tests, and rebase the patch so that it applies to main.
llvm/lib/Transforms/AggressiveInstCombine/TruncInstCombine.cpp | ||
---|---|---|
299–307 | (note that there's a typo in my diff, it should be |
llvm/lib/Transforms/AggressiveInstCombine/TruncInstCombine.cpp | ||
---|---|---|
409–410 | But, this brings another question - should this assert that the sign bit is known? |
llvm/lib/Transforms/AggressiveInstCombine/TruncInstCombine.cpp | ||
---|---|---|
409–410 | Actually, let me backtrack this. |
Make step back, leaving lshr untouched and counting sign bits for ashr only.
The motivation is such that for natural cases unsigned values are
zexted and lshred whereas signed values are sexted and ashred.
So it is naturally to grasp only these two cases. We miss here cases like truncation of ashr(zext(*)),
but it is transformed for AIC by preceding IC to lshr(zext(*)). Also remove unrelated tests.
llvm/lib/Transforms/AggressiveInstCombine/TruncInstCombine.cpp | ||
---|---|---|
299–307 | Ok, thanks, used CountMinSignBits() for ashr. | |
409–410 | Ok, I've changed that lines. |
llvm/lib/Transforms/AggressiveInstCombine/TruncInstCombine.cpp | ||
---|---|---|
409–410 |
Sure, I've eventually done it that way: lshr is transformed as before, ashr transformation works for numbers treated as signed ones. |
llvm/lib/Transforms/AggressiveInstCombine/TruncInstCombine.cpp | ||
---|---|---|
411–413 | FWIW i think we can generalize this like that in the future. |
Update setting exactness
llvm/lib/Transforms/AggressiveInstCombine/TruncInstCombine.cpp | ||
---|---|---|
411–413 | Thanks, done. |
Sorry - I missed the earlier ping.
LGTM.
llvm/lib/Transforms/AggressiveInstCombine/TruncInstCombine.cpp | ||
---|---|---|
290–293 | if (I->isShift()) { |
llvm/lib/Transforms/AggressiveInstCombine/TruncInstCombine.cpp | ||
---|---|---|
290–293 | Thanks, done |