Skip to content

Commit 4725583

Browse files
committed
[ValueTracking] A and (B & ~A) have no common bits set
This extends haveNoCommonBitsSet() to two additional cases, allowing the following folds: * `A + (B & ~A)` --> `A | (B & ~A)` (https://alive2.llvm.org/ce/z/crxxhN) * `A + ((A & B) ^ B)` --> `A | ((A & B) ^ B)` (https://alive2.llvm.org/ce/z/A_wsH_) These should further fold to just `A | B`, though this currently only works in the first case. The reason why the second fold is necessary is that we consider this to be the canonical form if B is a constant. (I did check whether we can change that, but it looks like a number of folds depend on the current canonicalization, so I ended up adding both patterns here.) Differential Revision: https://reviews.llvm.org/D124763
1 parent 6c57b0d commit 4725583

File tree

2 files changed

+29
-23
lines changed

2 files changed

+29
-23
lines changed

llvm/lib/Analysis/ValueTracking.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,20 @@ bool llvm::haveNoCommonBitsSet(const Value *LHS, const Value *RHS,
282282
match(LHS, m_c_And(m_Specific(M), m_Value())))
283283
return true;
284284
}
285+
286+
// X op (Y & ~X)
287+
if (match(RHS, m_c_And(m_Not(m_Specific(LHS)), m_Value())) ||
288+
match(LHS, m_c_And(m_Not(m_Specific(RHS)), m_Value())))
289+
return true;
290+
291+
// X op ((X & Y) ^ Y) -- this is the canonical form of the previous pattern
292+
// for constant Y.
293+
Value *Y;
294+
if (match(RHS,
295+
m_c_Xor(m_c_And(m_Specific(LHS), m_Value(Y)), m_Deferred(Y))) ||
296+
match(LHS, m_c_Xor(m_c_And(m_Specific(RHS), m_Value(Y)), m_Deferred(Y))))
297+
return true;
298+
285299
// Look for: (A & B) op ~(A | B)
286300
{
287301
Value *A, *B;

llvm/test/Transforms/InstCombine/add.ll

Lines changed: 15 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1395,9 +1395,7 @@ define i8 @add_like_or_t2_extrause(i8 %x) {
13951395

13961396
define i8 @add_and_xor(i8 %x, i8 %y) {
13971397
; CHECK-LABEL: @add_and_xor(
1398-
; CHECK-NEXT: [[XOR:%.*]] = xor i8 [[X:%.*]], -1
1399-
; CHECK-NEXT: [[AND:%.*]] = and i8 [[XOR]], [[Y:%.*]]
1400-
; CHECK-NEXT: [[ADD:%.*]] = add i8 [[AND]], [[X]]
1398+
; CHECK-NEXT: [[ADD:%.*]] = or i8 [[Y:%.*]], [[X:%.*]]
14011399
; CHECK-NEXT: ret i8 [[ADD]]
14021400
;
14031401
%xor = xor i8 %x, -1
@@ -1435,9 +1433,7 @@ define i8 @add_and_xor_wrong_op(i8 %x, i8 %y, i8 %z) {
14351433
define i8 @add_and_xor_commuted1(i8 %x, i8 %_y) {
14361434
; CHECK-LABEL: @add_and_xor_commuted1(
14371435
; CHECK-NEXT: [[Y:%.*]] = udiv i8 42, [[_Y:%.*]]
1438-
; CHECK-NEXT: [[XOR:%.*]] = xor i8 [[X:%.*]], -1
1439-
; CHECK-NEXT: [[AND:%.*]] = and i8 [[Y]], [[XOR]]
1440-
; CHECK-NEXT: [[ADD:%.*]] = add i8 [[AND]], [[X]]
1436+
; CHECK-NEXT: [[ADD:%.*]] = or i8 [[Y]], [[X:%.*]]
14411437
; CHECK-NEXT: ret i8 [[ADD]]
14421438
;
14431439
%y = udiv i8 42, %_y ; thwart complexity-based canonicalization
@@ -1450,9 +1446,7 @@ define i8 @add_and_xor_commuted1(i8 %x, i8 %_y) {
14501446
define i8 @add_and_xor_commuted2(i8 %_x, i8 %y) {
14511447
; CHECK-LABEL: @add_and_xor_commuted2(
14521448
; CHECK-NEXT: [[X:%.*]] = udiv i8 42, [[_X:%.*]]
1453-
; CHECK-NEXT: [[XOR:%.*]] = xor i8 [[X]], -1
1454-
; CHECK-NEXT: [[AND:%.*]] = and i8 [[XOR]], [[Y:%.*]]
1455-
; CHECK-NEXT: [[ADD:%.*]] = add i8 [[X]], [[AND]]
1449+
; CHECK-NEXT: [[ADD:%.*]] = or i8 [[X]], [[Y:%.*]]
14561450
; CHECK-NEXT: ret i8 [[ADD]]
14571451
;
14581452
%x = udiv i8 42, %_x ; thwart complexity-based canonicalization
@@ -1466,9 +1460,7 @@ define i8 @add_and_xor_commuted3(i8 %_x, i8 %_y) {
14661460
; CHECK-LABEL: @add_and_xor_commuted3(
14671461
; CHECK-NEXT: [[X:%.*]] = udiv i8 42, [[_X:%.*]]
14681462
; CHECK-NEXT: [[Y:%.*]] = udiv i8 42, [[_Y:%.*]]
1469-
; CHECK-NEXT: [[XOR:%.*]] = xor i8 [[X]], -1
1470-
; CHECK-NEXT: [[AND:%.*]] = and i8 [[Y]], [[XOR]]
1471-
; CHECK-NEXT: [[ADD:%.*]] = add nuw nsw i8 [[X]], [[AND]]
1463+
; CHECK-NEXT: [[ADD:%.*]] = or i8 [[X]], [[Y]]
14721464
; CHECK-NEXT: ret i8 [[ADD]]
14731465
;
14741466
%x = udiv i8 42, %_x ; thwart complexity-based canonicalization
@@ -1485,7 +1477,7 @@ define i8 @add_and_xor_extra_use(i8 %x, i8 %y) {
14851477
; CHECK-NEXT: call void @use(i8 [[XOR]])
14861478
; CHECK-NEXT: [[AND:%.*]] = and i8 [[XOR]], [[Y:%.*]]
14871479
; CHECK-NEXT: call void @use(i8 [[AND]])
1488-
; CHECK-NEXT: [[ADD:%.*]] = add i8 [[AND]], [[X]]
1480+
; CHECK-NEXT: [[ADD:%.*]] = or i8 [[Y]], [[X]]
14891481
; CHECK-NEXT: ret i8 [[ADD]]
14901482
;
14911483
%xor = xor i8 %x, -1
@@ -1500,7 +1492,7 @@ define i8 @add_xor_and_const(i8 %x) {
15001492
; CHECK-LABEL: @add_xor_and_const(
15011493
; CHECK-NEXT: [[AND:%.*]] = and i8 [[X:%.*]], 42
15021494
; CHECK-NEXT: [[XOR:%.*]] = xor i8 [[AND]], 42
1503-
; CHECK-NEXT: [[ADD:%.*]] = add i8 [[XOR]], [[X]]
1495+
; CHECK-NEXT: [[ADD:%.*]] = or i8 [[XOR]], [[X]]
15041496
; CHECK-NEXT: ret i8 [[ADD]]
15051497
;
15061498
%and = and i8 %x, 42
@@ -1527,7 +1519,7 @@ define i8 @add_xor_and_var(i8 %x, i8 %y) {
15271519
; CHECK-NEXT: [[AND:%.*]] = and i8 [[X:%.*]], [[Y:%.*]]
15281520
; CHECK-NEXT: call void @use(i8 [[AND]])
15291521
; CHECK-NEXT: [[XOR:%.*]] = xor i8 [[AND]], [[Y]]
1530-
; CHECK-NEXT: [[ADD:%.*]] = add i8 [[XOR]], [[X]]
1522+
; CHECK-NEXT: [[ADD:%.*]] = or i8 [[XOR]], [[X]]
15311523
; CHECK-NEXT: ret i8 [[ADD]]
15321524
;
15331525
%and = and i8 %x, %y
@@ -1572,7 +1564,7 @@ define i8 @add_xor_and_var_commuted1(i8 %x, i8 %y) {
15721564
; CHECK-NEXT: [[AND:%.*]] = and i8 [[Y:%.*]], [[X:%.*]]
15731565
; CHECK-NEXT: call void @use(i8 [[AND]])
15741566
; CHECK-NEXT: [[XOR:%.*]] = xor i8 [[AND]], [[Y]]
1575-
; CHECK-NEXT: [[ADD:%.*]] = add i8 [[XOR]], [[X]]
1567+
; CHECK-NEXT: [[ADD:%.*]] = or i8 [[XOR]], [[X]]
15761568
; CHECK-NEXT: ret i8 [[ADD]]
15771569
;
15781570
%and = and i8 %y, %x
@@ -1588,7 +1580,7 @@ define i8 @add_xor_and_var_commuted2(i8 %x, i8 %_y) {
15881580
; CHECK-NEXT: [[AND:%.*]] = and i8 [[Y]], [[X:%.*]]
15891581
; CHECK-NEXT: call void @use(i8 [[AND]])
15901582
; CHECK-NEXT: [[XOR:%.*]] = xor i8 [[Y]], [[AND]]
1591-
; CHECK-NEXT: [[ADD:%.*]] = add i8 [[XOR]], [[X]]
1583+
; CHECK-NEXT: [[ADD:%.*]] = or i8 [[XOR]], [[X]]
15921584
; CHECK-NEXT: ret i8 [[ADD]]
15931585
;
15941586
%y = udiv i8 42, %_y ; thwart complexity-based canonicalization
@@ -1605,7 +1597,7 @@ define i8 @add_xor_and_var_commuted3(i8 %x, i8 %_y) {
16051597
; CHECK-NEXT: [[AND:%.*]] = and i8 [[Y]], [[X:%.*]]
16061598
; CHECK-NEXT: call void @use(i8 [[AND]])
16071599
; CHECK-NEXT: [[XOR:%.*]] = xor i8 [[Y]], [[AND]]
1608-
; CHECK-NEXT: [[ADD:%.*]] = add i8 [[XOR]], [[X]]
1600+
; CHECK-NEXT: [[ADD:%.*]] = or i8 [[XOR]], [[X]]
16091601
; CHECK-NEXT: ret i8 [[ADD]]
16101602
;
16111603
%y = udiv i8 42, %_y ; thwart complexity-based canonicalization
@@ -1622,7 +1614,7 @@ define i8 @add_xor_and_var_commuted4(i8 %_x, i8 %y) {
16221614
; CHECK-NEXT: [[AND:%.*]] = and i8 [[X]], [[Y:%.*]]
16231615
; CHECK-NEXT: call void @use(i8 [[AND]])
16241616
; CHECK-NEXT: [[XOR:%.*]] = xor i8 [[AND]], [[Y]]
1625-
; CHECK-NEXT: [[ADD:%.*]] = add i8 [[X]], [[XOR]]
1617+
; CHECK-NEXT: [[ADD:%.*]] = or i8 [[X]], [[XOR]]
16261618
; CHECK-NEXT: ret i8 [[ADD]]
16271619
;
16281620
%x = udiv i8 42, %_x ; thwart complexity-based canonicalization
@@ -1639,7 +1631,7 @@ define i8 @add_xor_and_var_commuted5(i8 %_x, i8 %y) {
16391631
; CHECK-NEXT: [[AND:%.*]] = and i8 [[X]], [[Y:%.*]]
16401632
; CHECK-NEXT: call void @use(i8 [[AND]])
16411633
; CHECK-NEXT: [[XOR:%.*]] = xor i8 [[AND]], [[Y]]
1642-
; CHECK-NEXT: [[ADD:%.*]] = add i8 [[X]], [[XOR]]
1634+
; CHECK-NEXT: [[ADD:%.*]] = or i8 [[X]], [[XOR]]
16431635
; CHECK-NEXT: ret i8 [[ADD]]
16441636
;
16451637
%x = udiv i8 42, %_x ; thwart complexity-based canonicalization
@@ -1657,7 +1649,7 @@ define i8 @add_xor_and_var_commuted6(i8 %_x, i8 %_y) {
16571649
; CHECK-NEXT: [[AND:%.*]] = and i8 [[X]], [[Y]]
16581650
; CHECK-NEXT: call void @use(i8 [[AND]])
16591651
; CHECK-NEXT: [[XOR:%.*]] = xor i8 [[Y]], [[AND]]
1660-
; CHECK-NEXT: [[ADD:%.*]] = add nuw nsw i8 [[X]], [[XOR]]
1652+
; CHECK-NEXT: [[ADD:%.*]] = or i8 [[X]], [[XOR]]
16611653
; CHECK-NEXT: ret i8 [[ADD]]
16621654
;
16631655
%x = udiv i8 42, %_x ; thwart complexity-based canonicalization
@@ -1676,7 +1668,7 @@ define i8 @add_xor_and_var_commuted7(i8 %_x, i8 %_y) {
16761668
; CHECK-NEXT: [[AND:%.*]] = and i8 [[Y]], [[X]]
16771669
; CHECK-NEXT: call void @use(i8 [[AND]])
16781670
; CHECK-NEXT: [[XOR:%.*]] = xor i8 [[Y]], [[AND]]
1679-
; CHECK-NEXT: [[ADD:%.*]] = add nuw nsw i8 [[X]], [[XOR]]
1671+
; CHECK-NEXT: [[ADD:%.*]] = or i8 [[X]], [[XOR]]
16801672
; CHECK-NEXT: ret i8 [[ADD]]
16811673
;
16821674
%x = udiv i8 42, %_x ; thwart complexity-based canonicalization
@@ -1694,7 +1686,7 @@ define i8 @add_xor_and_var_extra_use(i8 %x, i8 %y) {
16941686
; CHECK-NEXT: call void @use(i8 [[AND]])
16951687
; CHECK-NEXT: [[XOR:%.*]] = xor i8 [[AND]], [[Y]]
16961688
; CHECK-NEXT: call void @use(i8 [[XOR]])
1697-
; CHECK-NEXT: [[ADD:%.*]] = add i8 [[XOR]], [[X]]
1689+
; CHECK-NEXT: [[ADD:%.*]] = or i8 [[XOR]], [[X]]
16981690
; CHECK-NEXT: ret i8 [[ADD]]
16991691
;
17001692
%and = and i8 %x, %y

0 commit comments

Comments
 (0)