Skip to content

Commit c3175c5

Browse files
authored
[InstCombine] Fold (X & C1) - (X & C2) --> X & (C1 ^ C2) if (C1 & C2) == C2 (#119316)
if (C1 & C2) == C2 then (X & C1) - (X & C2) --> X & (C1 ^ C2) Alive2: https://alive2.llvm.org/ce/z/JvQU8w
1 parent 9ab016f commit c3175c5

File tree

2 files changed

+93
-0
lines changed

2 files changed

+93
-0
lines changed

llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2280,6 +2280,16 @@ Instruction *InstCombinerImpl::visitSub(BinaryOperator &I) {
22802280
if (match(Op0, m_OneUse(m_Add(m_Value(X), m_AllOnes()))))
22812281
return BinaryOperator::CreateAdd(Builder.CreateNot(Op1), X);
22822282

2283+
// if (C1 & C2) == C2 then (X & C1) - (X & C2) -> X & (C1 ^ C2)
2284+
Constant *C1, *C2;
2285+
if (match(Op0, m_And(m_Value(X), m_ImmConstant(C1))) &&
2286+
match(Op1, m_And(m_Specific(X), m_ImmConstant(C2)))) {
2287+
Value *AndC = ConstantFoldBinaryInstruction(Instruction::And, C1, C2);
2288+
if (C2->isElementWiseEqual(AndC))
2289+
return BinaryOperator::CreateAnd(
2290+
X, ConstantFoldBinaryInstruction(Instruction::Xor, C1, C2));
2291+
}
2292+
22832293
// Reassociate sub/add sequences to create more add instructions and
22842294
// reduce dependency chains:
22852295
// ((X - Y) + Z) - Op1 --> (X + Z) - (Y + Op1)
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2+
; RUN: opt < %s -passes=instcombine -S | FileCheck %s
3+
4+
define i8 @and_sub(i8 %a) {
5+
; CHECK-LABEL: @and_sub(
6+
; CHECK-NEXT: [[RET:%.*]] = and i8 [[A:%.*]], 12
7+
; CHECK-NEXT: ret i8 [[RET]]
8+
;
9+
%and1 = and i8 %a, 15
10+
%and2 = and i8 %a, 3
11+
12+
%ret = sub i8 %and1, %and2
13+
ret i8 %ret
14+
}
15+
16+
declare void @use(i8)
17+
define i8 @and_sub_multi_use(i8 %a) {
18+
; CHECK-LABEL: @and_sub_multi_use(
19+
; CHECK-NEXT: [[AND1:%.*]] = and i8 [[A:%.*]], 15
20+
; CHECK-NEXT: call void @use(i8 [[AND1]])
21+
; CHECK-NEXT: [[AND2:%.*]] = and i8 [[A]], 3
22+
; CHECK-NEXT: call void @use(i8 [[AND2]])
23+
; CHECK-NEXT: [[RET:%.*]] = and i8 [[A]], 12
24+
; CHECK-NEXT: ret i8 [[RET]]
25+
;
26+
%and1 = and i8 %a, 15
27+
call void @use(i8 %and1)
28+
%and2 = and i8 %a, 3
29+
call void @use(i8 %and2)
30+
%ret = sub i8 %and1, %and2
31+
ret i8 %ret
32+
}
33+
34+
define <2 x i32> @and_sub_vec(<2 x i32> %a) {
35+
; CHECK-LABEL: @and_sub_vec(
36+
; CHECK-NEXT: [[RET:%.*]] = and <2 x i32> [[A:%.*]], <i32 3, i32 8>
37+
; CHECK-NEXT: ret <2 x i32> [[RET]]
38+
;
39+
%and1 = and <2 x i32> %a, <i32 11, i32 10>
40+
%and2 = and <2 x i32> %a, <i32 8, i32 2>
41+
42+
%ret = sub <2 x i32> %and1, %and2
43+
ret <2 x i32> %ret
44+
}
45+
46+
define <2 x i32> @and_sub_vec_posion(<2 x i32> %a) {
47+
; CHECK-LABEL: @and_sub_vec_posion(
48+
; CHECK-NEXT: ret <2 x i32> poison
49+
;
50+
%and1 = and <2 x i32> %a, <i32 11, i32 poison>
51+
%and2 = and <2 x i32> %a, <i32 poison, i32 2>
52+
53+
%ret = sub <2 x i32> %and1, %and2
54+
ret <2 x i32> %ret
55+
}
56+
57+
define <2 x i32> @and_sub_vec_undef(<2 x i32> %a) {
58+
; CHECK-LABEL: @and_sub_vec_undef(
59+
; CHECK-NEXT: [[AND1:%.*]] = and <2 x i32> [[A:%.*]], <i32 11, i32 undef>
60+
; CHECK-NEXT: [[AND2:%.*]] = and <2 x i32> [[A]], <i32 undef, i32 2>
61+
; CHECK-NEXT: [[RET:%.*]] = sub <2 x i32> [[AND1]], [[AND2]]
62+
; CHECK-NEXT: ret <2 x i32> [[RET]]
63+
;
64+
%and1 = and <2 x i32> %a, <i32 11, i32 undef>
65+
%and2 = and <2 x i32> %a, <i32 undef, i32 2>
66+
67+
%ret = sub <2 x i32> %and1, %and2
68+
ret <2 x i32> %ret
69+
}
70+
71+
define i8 @and_sub_negtive(i8 %a) {
72+
; CHECK-LABEL: @and_sub_negtive(
73+
; CHECK-NEXT: [[AND1:%.*]] = and i8 [[A:%.*]], 10
74+
; CHECK-NEXT: [[AND2:%.*]] = and i8 [[A]], 9
75+
; CHECK-NEXT: [[RET:%.*]] = sub nsw i8 [[AND1]], [[AND2]]
76+
; CHECK-NEXT: ret i8 [[RET]]
77+
;
78+
%and1 = and i8 %a, 10
79+
%and2 = and i8 %a, 9
80+
81+
%ret = sub i8 %and1, %and2
82+
ret i8 %ret
83+
}

0 commit comments

Comments
 (0)