Skip to content

Commit 4dc267e

Browse files
committed
[InstCombine] Canonicalize xor with disjoint ops to or disjoint
Change-Id: Ib278c8c6a2893b0f9f75a0a6fb0430437b9cff14
1 parent 77ac5a2 commit 4dc267e

File tree

2 files changed

+54
-0
lines changed

2 files changed

+54
-0
lines changed

llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4993,6 +4993,11 @@ Instruction *InstCombinerImpl::visitXor(BinaryOperator &I) {
49934993
if (Instruction *Abs = canonicalizeAbs(I, Builder))
49944994
return Abs;
49954995

4996+
if (KnownBits::haveNoCommonBitsSet(
4997+
computeKnownBits(I.getOperand(0), /*Depth=*/0, &I),
4998+
computeKnownBits(I.getOperand(1), /*Depth=*/0, &I)))
4999+
return BinaryOperator::CreateDisjointOr(I.getOperand(0), I.getOperand(1));
5000+
49965001
// Otherwise, if all else failed, try to hoist the xor-by-constant:
49975002
// (X ^ C) ^ Y --> (X ^ Y) ^ C
49985003
// Just like we do in other places, we completely avoid the fold

llvm/test/Transforms/InstCombine/xor.ll

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1664,3 +1664,52 @@ entry:
16641664
%or = or <2 x i32> %add, %c
16651665
ret <2 x i32> %or
16661666
}
1667+
1668+
declare i32 @callee()
1669+
1670+
define i32 @xor_disjoint() {
1671+
; CHECK-LABEL: @xor_disjoint(
1672+
; CHECK-NEXT: [[CALL1:%.*]] = call i32 @callee(), !range [[RNG0:![0-9]+]]
1673+
; CHECK-NEXT: [[XOR:%.*]] = or disjoint i32 [[CALL1]], 4096
1674+
; CHECK-NEXT: ret i32 [[XOR]]
1675+
;
1676+
%call1 = call i32 @callee(), !range !0
1677+
%xor = xor i32 %call1, 4096
1678+
ret i32 %xor
1679+
}
1680+
1681+
define i32 @xor_disjoint2() {
1682+
; CHECK-LABEL: @xor_disjoint2(
1683+
; CHECK-NEXT: [[CALL1:%.*]] = call i32 @callee(), !range [[RNG1:![0-9]+]]
1684+
; CHECK-NEXT: [[XOR:%.*]] = or disjoint i32 [[CALL1]], 512
1685+
; CHECK-NEXT: ret i32 [[XOR]]
1686+
;
1687+
%call1 = call i32 @callee(), !range !1
1688+
%xor = xor i32 %call1, 512
1689+
ret i32 %xor
1690+
}
1691+
1692+
define i32 @xor_non_disjoint() {
1693+
; CHECK-LABEL: @xor_non_disjoint(
1694+
; CHECK-NEXT: [[CALL1:%.*]] = call i32 @callee(), !range [[RNG0]]
1695+
; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[CALL1]], 1024
1696+
; CHECK-NEXT: ret i32 [[XOR]]
1697+
;
1698+
%call1 = call i32 @callee(), !range !0
1699+
%xor = xor i32 %call1, 1024
1700+
ret i32 %xor
1701+
}
1702+
1703+
define i32 @xor_non_disjoint2() {
1704+
; CHECK-LABEL: @xor_non_disjoint2(
1705+
; CHECK-NEXT: [[CALL1:%.*]] = call i32 @callee(), !range [[RNG1]]
1706+
; CHECK-NEXT: [[XOR:%.*]] = and i32 [[CALL1]], 511
1707+
; CHECK-NEXT: ret i32 [[XOR]]
1708+
;
1709+
%call1 = call i32 @callee(), !range !1
1710+
%xor = xor i32 %call1, 1024
1711+
ret i32 %xor
1712+
}
1713+
1714+
!0 = !{ i32 0, i32 2048 }
1715+
!1 = !{ i32 1024, i32 1536 }

0 commit comments

Comments
 (0)