[PATCH] D109807: [InstCombine] Narrow type of logical operation chains in certain cases
Sanjay Patel via Phabricator via llvm-commits
llvm-commits at lists.llvm.org
Wed Oct 13 09:10:41 PDT 2021
spatel added inline comments.
================
Comment at: llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp:1613
CastInst *Cast0 = dyn_cast<CastInst>(Op0);
- if (!Cast0)
- return nullptr;
+ if (!Cast0) {
+ std::swap(Op0, Op1);
----------------
mnadeem wrote:
> spatel wrote:
> > It's not clear to me why this swap is necessary. Do you have a test case where a logic binop has a cast as operand 0 and a binop as operand 1? Complexity-based canonicalization is supposed to prevent that. See InstCombinerImpl::SimplifyAssociativeOrCommutative().
> I think you have it the other way around, the code currently only checks for the cast to be on the LHS.
> This swap handles the case when the Op0 (higher complexity) is another binop.
Ah, I see.
I wonder if it would be easier to read if we just match this in its "natural" form then:
(extend(X) | Y) | extend(Z) --> (extend(X) | extend(Z)) | Y
You would hoist this code above the current bailout for !Cast0 if you did it that way.
================
Comment at: llvm/test/Transforms/InstCombine/and-xor-or.ll:511
define i64 @sext_or_chain_two_uses2(i64 %a, i16 %b, i16 %c, i64 %d) {
; CHECK-LABEL: @sext_or_chain_two_uses2(
----------------
This test doesn't add much value. In InstCombine, I don't think we ever care if the instruction that is being replaced has multiple uses.
================
Comment at: llvm/test/Transforms/InstCombine/and-xor-or.ll:551
define i64 @sext_or_chain_two_uses4(i64 %a, i16 %b, i16 %c, i64 %d) {
; CHECK-LABEL: @sext_or_chain_two_uses4(
----------------
Similar to test comment above: this does not add value vs. the previous test if it is just an extra use of the final value.
================
Comment at: llvm/test/Transforms/InstCombine/and-xor-or.ll:591-592
; CHECK-NEXT: [[CONV2:%.*]] = sext i16 [[C:%.*]] to i64
-; CHECK-NEXT: [[XOR:%.*]] = xor i64 [[CONV]], [[A:%.*]]
-; CHECK-NEXT: [[XOR2:%.*]] = xor i64 [[XOR]], [[CONV2]]
+; CHECK-NEXT: [[TMP1:%.*]] = xor i64 [[CONV2]], [[CONV]]
+; CHECK-NEXT: [[XOR2:%.*]] = xor i64 [[TMP1]], [[A:%.*]]
; CHECK-NEXT: ret i64 [[XOR2]]
----------------
That seems like a reasonable canonicalization (and the 'and' test below shows a potential win)...
But we should note that this is intentional in a code comment.
But what happens if "%conv" is `trunc` or `fptoui` or some other non-ext cast?
Please add test(s) with those patterns.
================
Comment at: llvm/test/Transforms/InstCombine/and-xor-or.ll:474
; Negative test with more uses.
define i64 @sext_or_chain_two_uses1(i64 %a, i16 %b, i16 %c, i64 %d) {
----------------
spatel wrote:
> I think we're missing tests:
> 1. Negative test with different logic opcodes.
> 2. Negative test with different cast opcodes.
> 3. Test with different cast source types.
> 4. Test with multiple uses of cast instruction(s).
> 5. Tests where the first cast is operand 1 of the logic op (notice in the original tests that the operands are commuted from where they started - search around the test directory for "thwart complexity-based canonicalization" for ways to prevent that).
I don't see an example of "3" here yet. I'm imagining something like this:
```
define i64 @f(i64 %a, i8 %b, i16 %c) {
%conv = zext i8 %b to i64
%conv2 = sext i16 %c to i64
%xor = xor i64 %conv, %a
%xor2 = xor i64 %xor, %conv2
ret i64 %xor2
}
```
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D109807/new/
https://reviews.llvm.org/D109807
More information about the llvm-commits
mailing list