Skip to content

Commit a2609be

Browse files
committed
[ValueTracking] Checking haveNoCommonBitsSet for (x & y) and ~(x | y)
This one tries to fix: #53357. Simply, this one would check (x & y) and ~(x | y) in haveNoCommonBitsSet. Since they shouldn't have common bits (we could traverse the case by enumerating), and we could convert this one to (x & y) | ~(x | y) . Then the compiler could handle it in InstCombineAndOrXor. Further more, since ((x & y) + (~x & ~y)) would be converted to ((x & y) + ~(x | y)), this patch would fix it too. https://alive2.llvm.org/ce/z/qsKzRS Reviewed By: spatel, xbolva00, RKSimon, lebedev.ri Differential Revision: https://reviews.llvm.org/D118094
1 parent d30ca5e commit a2609be

File tree

3 files changed

+95
-41
lines changed

3 files changed

+95
-41
lines changed

llvm/lib/Analysis/ValueTracking.cpp

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -275,13 +275,25 @@ bool llvm::haveNoCommonBitsSet(const Value *LHS, const Value *RHS,
275275
assert(LHS->getType()->isIntOrIntVectorTy() &&
276276
"LHS and RHS should be integers");
277277
// Look for an inverted mask: (X & ~M) op (Y & M).
278-
Value *M;
279-
if (match(LHS, m_c_And(m_Not(m_Value(M)), m_Value())) &&
280-
match(RHS, m_c_And(m_Specific(M), m_Value())))
281-
return true;
282-
if (match(RHS, m_c_And(m_Not(m_Value(M)), m_Value())) &&
283-
match(LHS, m_c_And(m_Specific(M), m_Value())))
284-
return true;
278+
{
279+
Value *M;
280+
if (match(LHS, m_c_And(m_Not(m_Value(M)), m_Value())) &&
281+
match(RHS, m_c_And(m_Specific(M), m_Value())))
282+
return true;
283+
if (match(RHS, m_c_And(m_Not(m_Value(M)), m_Value())) &&
284+
match(LHS, m_c_And(m_Specific(M), m_Value())))
285+
return true;
286+
}
287+
// Look for: (A & B) op ~(A | B)
288+
{
289+
Value *A, *B;
290+
if (match(LHS, m_And(m_Value(A), m_Value(B))) &&
291+
match(RHS, m_Not(m_c_Or(m_Specific(A), m_Specific(B)))))
292+
return true;
293+
if (match(RHS, m_And(m_Value(A), m_Value(B))) &&
294+
match(LHS, m_Not(m_c_Or(m_Specific(A), m_Specific(B)))))
295+
return true;
296+
}
285297
IntegerType *IT = cast<IntegerType>(LHS->getType()->getScalarType());
286298
KnownBits LHSKnown(IT->getBitWidth());
287299
KnownBits RHSKnown(IT->getBitWidth());

llvm/test/Transforms/InstCombine/pr53357.ll

Lines changed: 20 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,9 @@
55
; (x & y) + ~(x | y)
66
define i32 @src(i32 %0, i32 %1) {
77
; CHECK-LABEL: @src(
8-
; CHECK-NEXT: [[TMP3:%.*]] = and i32 [[TMP1:%.*]], [[TMP0:%.*]]
9-
; CHECK-NEXT: [[TMP4:%.*]] = or i32 [[TMP1]], [[TMP0]]
10-
; CHECK-NEXT: [[TMP5:%.*]] = xor i32 [[TMP4]], -1
11-
; CHECK-NEXT: [[TMP6:%.*]] = add i32 [[TMP3]], [[TMP5]]
12-
; CHECK-NEXT: ret i32 [[TMP6]]
8+
; CHECK-NEXT: [[TMP3:%.*]] = xor i32 [[TMP1:%.*]], [[TMP0:%.*]]
9+
; CHECK-NEXT: [[TMP4:%.*]] = xor i32 [[TMP3]], -1
10+
; CHECK-NEXT: ret i32 [[TMP4]]
1311
;
1412
%3 = and i32 %1, %0
1513
%4 = or i32 %1, %0
@@ -21,11 +19,9 @@ define i32 @src(i32 %0, i32 %1) {
2119
; vector version of src
2220
define <2 x i32> @src_vec(<2 x i32> %0, <2 x i32> %1) {
2321
; CHECK-LABEL: @src_vec(
24-
; CHECK-NEXT: [[TMP3:%.*]] = and <2 x i32> [[TMP1:%.*]], [[TMP0:%.*]]
25-
; CHECK-NEXT: [[TMP4:%.*]] = or <2 x i32> [[TMP1]], [[TMP0]]
26-
; CHECK-NEXT: [[TMP5:%.*]] = xor <2 x i32> [[TMP4]], <i32 -1, i32 -1>
27-
; CHECK-NEXT: [[TMP6:%.*]] = add <2 x i32> [[TMP3]], [[TMP5]]
28-
; CHECK-NEXT: ret <2 x i32> [[TMP6]]
22+
; CHECK-NEXT: [[TMP3:%.*]] = xor <2 x i32> [[TMP1:%.*]], [[TMP0:%.*]]
23+
; CHECK-NEXT: [[TMP4:%.*]] = xor <2 x i32> [[TMP3]], <i32 -1, i32 -1>
24+
; CHECK-NEXT: ret <2 x i32> [[TMP4]]
2925
;
3026
%3 = and <2 x i32> %1, %0
3127
%4 = or <2 x i32> %1, %0
@@ -37,11 +33,9 @@ define <2 x i32> @src_vec(<2 x i32> %0, <2 x i32> %1) {
3733
; vector version of src with undef values
3834
define <2 x i32> @src_vec_undef(<2 x i32> %0, <2 x i32> %1) {
3935
; CHECK-LABEL: @src_vec_undef(
40-
; CHECK-NEXT: [[TMP3:%.*]] = and <2 x i32> [[TMP1:%.*]], [[TMP0:%.*]]
41-
; CHECK-NEXT: [[TMP4:%.*]] = or <2 x i32> [[TMP1]], [[TMP0]]
42-
; CHECK-NEXT: [[TMP5:%.*]] = xor <2 x i32> [[TMP4]], <i32 -1, i32 undef>
43-
; CHECK-NEXT: [[TMP6:%.*]] = add <2 x i32> [[TMP3]], [[TMP5]]
44-
; CHECK-NEXT: ret <2 x i32> [[TMP6]]
36+
; CHECK-NEXT: [[TMP3:%.*]] = xor <2 x i32> [[TMP1:%.*]], [[TMP0:%.*]]
37+
; CHECK-NEXT: [[TMP4:%.*]] = xor <2 x i32> [[TMP3]], <i32 -1, i32 -1>
38+
; CHECK-NEXT: ret <2 x i32> [[TMP4]]
4539
;
4640
%3 = and <2 x i32> %1, %0
4741
%4 = or <2 x i32> %1, %0
@@ -53,11 +47,9 @@ define <2 x i32> @src_vec_undef(<2 x i32> %0, <2 x i32> %1) {
5347
; (x & y) + ~(y | x)
5448
define i32 @src2(i32 %0, i32 %1) {
5549
; CHECK-LABEL: @src2(
56-
; CHECK-NEXT: [[TMP3:%.*]] = and i32 [[TMP1:%.*]], [[TMP0:%.*]]
57-
; CHECK-NEXT: [[TMP4:%.*]] = or i32 [[TMP0]], [[TMP1]]
58-
; CHECK-NEXT: [[TMP5:%.*]] = xor i32 [[TMP4]], -1
59-
; CHECK-NEXT: [[TMP6:%.*]] = add i32 [[TMP3]], [[TMP5]]
60-
; CHECK-NEXT: ret i32 [[TMP6]]
50+
; CHECK-NEXT: [[TMP3:%.*]] = xor i32 [[TMP1:%.*]], [[TMP0:%.*]]
51+
; CHECK-NEXT: [[TMP4:%.*]] = xor i32 [[TMP3]], -1
52+
; CHECK-NEXT: ret i32 [[TMP4]]
6153
;
6254
%3 = and i32 %1, %0
6355
%4 = or i32 %0, %1
@@ -69,11 +61,9 @@ define i32 @src2(i32 %0, i32 %1) {
6961
; (x & y) + (~x & ~y)
7062
define i32 @src3(i32 %0, i32 %1) {
7163
; CHECK-LABEL: @src3(
72-
; CHECK-NEXT: [[TMP3:%.*]] = and i32 [[TMP1:%.*]], [[TMP0:%.*]]
73-
; CHECK-NEXT: [[DOTDEMORGAN:%.*]] = or i32 [[TMP0]], [[TMP1]]
74-
; CHECK-NEXT: [[TMP4:%.*]] = xor i32 [[DOTDEMORGAN]], -1
75-
; CHECK-NEXT: [[TMP5:%.*]] = add i32 [[TMP3]], [[TMP4]]
76-
; CHECK-NEXT: ret i32 [[TMP5]]
64+
; CHECK-NEXT: [[TMP3:%.*]] = xor i32 [[TMP1:%.*]], [[TMP0:%.*]]
65+
; CHECK-NEXT: [[TMP4:%.*]] = xor i32 [[TMP3]], -1
66+
; CHECK-NEXT: ret i32 [[TMP4]]
7767
;
7868
%3 = and i32 %1, %0
7969
%4 = xor i32 %0, -1
@@ -86,11 +76,9 @@ define i32 @src3(i32 %0, i32 %1) {
8676
; ~(x | y) + (y & x)
8777
define i32 @src4(i32 %0, i32 %1) {
8878
; CHECK-LABEL: @src4(
89-
; CHECK-NEXT: [[TMP3:%.*]] = and i32 [[TMP0:%.*]], [[TMP1:%.*]]
90-
; CHECK-NEXT: [[TMP4:%.*]] = or i32 [[TMP1]], [[TMP0]]
91-
; CHECK-NEXT: [[TMP5:%.*]] = xor i32 [[TMP4]], -1
92-
; CHECK-NEXT: [[TMP6:%.*]] = add i32 [[TMP3]], [[TMP5]]
93-
; CHECK-NEXT: ret i32 [[TMP6]]
79+
; CHECK-NEXT: [[TMP3:%.*]] = xor i32 [[TMP0:%.*]], [[TMP1:%.*]]
80+
; CHECK-NEXT: [[TMP4:%.*]] = xor i32 [[TMP3]], -1
81+
; CHECK-NEXT: ret i32 [[TMP4]]
9482
;
9583
%3 = and i32 %0, %1
9684
%4 = or i32 %1, %0
@@ -102,11 +90,9 @@ define i32 @src4(i32 %0, i32 %1) {
10290
; ~(x | y) + (x & y)
10391
define i32 @src5(i32 %0, i32 %1) {
10492
; CHECK-LABEL: @src5(
105-
; CHECK-NEXT: [[TMP3:%.*]] = or i32 [[TMP1:%.*]], [[TMP0:%.*]]
93+
; CHECK-NEXT: [[TMP3:%.*]] = xor i32 [[TMP1:%.*]], [[TMP0:%.*]]
10694
; CHECK-NEXT: [[TMP4:%.*]] = xor i32 [[TMP3]], -1
107-
; CHECK-NEXT: [[TMP5:%.*]] = and i32 [[TMP1]], [[TMP0]]
108-
; CHECK-NEXT: [[TMP6:%.*]] = add i32 [[TMP5]], [[TMP4]]
109-
; CHECK-NEXT: ret i32 [[TMP6]]
95+
; CHECK-NEXT: ret i32 [[TMP4]]
11096
;
11197
%3 = or i32 %1, %0
11298
%4 = xor i32 %3, -1

llvm/unittests/Analysis/ValueTrackingTest.cpp

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1745,6 +1745,62 @@ TEST_F(ValueTrackingTest, HaveNoCommonBitsSet) {
17451745
EXPECT_TRUE(haveNoCommonBitsSet(LHS, RHS, DL));
17461746
EXPECT_TRUE(haveNoCommonBitsSet(RHS, LHS, DL));
17471747
}
1748+
{
1749+
// Check for (A & B) and ~(A | B)
1750+
auto M = parseModule(R"(
1751+
define void @test(i32 %A, i32 %B) {
1752+
%LHS = and i32 %A, %B
1753+
%or = or i32 %A, %B
1754+
%RHS = xor i32 %or, -1
1755+
1756+
%LHS2 = and i32 %B, %A
1757+
%or2 = or i32 %A, %B
1758+
%RHS2 = xor i32 %or2, -1
1759+
1760+
ret void
1761+
})");
1762+
1763+
auto *F = M->getFunction("test");
1764+
const DataLayout &DL = M->getDataLayout();
1765+
1766+
auto *LHS = findInstructionByNameOrNull(F, "LHS");
1767+
auto *RHS = findInstructionByNameOrNull(F, "RHS");
1768+
EXPECT_TRUE(haveNoCommonBitsSet(LHS, RHS, DL));
1769+
EXPECT_TRUE(haveNoCommonBitsSet(RHS, LHS, DL));
1770+
1771+
auto *LHS2 = findInstructionByNameOrNull(F, "LHS2");
1772+
auto *RHS2 = findInstructionByNameOrNull(F, "RHS2");
1773+
EXPECT_TRUE(haveNoCommonBitsSet(LHS2, RHS2, DL));
1774+
EXPECT_TRUE(haveNoCommonBitsSet(RHS2, LHS2, DL));
1775+
}
1776+
{
1777+
// Check for (A & B) and ~(A | B) in vector version
1778+
auto M = parseModule(R"(
1779+
define void @test(<2 x i32> %A, <2 x i32> %B) {
1780+
%LHS = and <2 x i32> %A, %B
1781+
%or = or <2 x i32> %A, %B
1782+
%RHS = xor <2 x i32> %or, <i32 -1, i32 -1>
1783+
1784+
%LHS2 = and <2 x i32> %B, %A
1785+
%or2 = or <2 x i32> %A, %B
1786+
%RHS2 = xor <2 x i32> %or2, <i32 -1, i32 -1>
1787+
1788+
ret void
1789+
})");
1790+
1791+
auto *F = M->getFunction("test");
1792+
const DataLayout &DL = M->getDataLayout();
1793+
1794+
auto *LHS = findInstructionByNameOrNull(F, "LHS");
1795+
auto *RHS = findInstructionByNameOrNull(F, "RHS");
1796+
EXPECT_TRUE(haveNoCommonBitsSet(LHS, RHS, DL));
1797+
EXPECT_TRUE(haveNoCommonBitsSet(RHS, LHS, DL));
1798+
1799+
auto *LHS2 = findInstructionByNameOrNull(F, "LHS2");
1800+
auto *RHS2 = findInstructionByNameOrNull(F, "RHS2");
1801+
EXPECT_TRUE(haveNoCommonBitsSet(LHS2, RHS2, DL));
1802+
EXPECT_TRUE(haveNoCommonBitsSet(RHS2, LHS2, DL));
1803+
}
17481804
}
17491805

17501806
class IsBytewiseValueTest : public ValueTrackingTest,

0 commit comments

Comments
 (0)