Skip to content

Commit 2614672

Browse files
authored
[InstCombine] Fold ((cst << x) & 1) --> x == 0 when cst is odd (#79772)
Fold ((cst << x) & 1) to zext(x == 0) when cst is odd. Fixes: #73384 Alive2: https://alive2.llvm.org/ce/z/5RbaK6
1 parent ae92f6e commit 2614672

File tree

2 files changed

+90
-3
lines changed

2 files changed

+90
-3
lines changed

llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2263,10 +2263,12 @@ Instruction *InstCombinerImpl::visitAnd(BinaryOperator &I) {
22632263
Value *Op0 = I.getOperand(0), *Op1 = I.getOperand(1);
22642264

22652265
Value *X, *Y;
2266-
if (match(Op0, m_OneUse(m_LogicalShift(m_One(), m_Value(X)))) &&
2266+
const APInt *C;
2267+
if ((match(Op0, m_OneUse(m_LogicalShift(m_One(), m_Value(X)))) ||
2268+
(match(Op0, m_OneUse(m_Shl(m_APInt(C), m_Value(X)))) && (*C)[0])) &&
22672269
match(Op1, m_One())) {
2268-
// (1 << X) & 1 --> zext(X == 0)
22692270
// (1 >> X) & 1 --> zext(X == 0)
2271+
// (C << X) & 1 --> zext(X == 0), when C is odd
22702272
Value *IsZero = Builder.CreateICmpEQ(X, ConstantInt::get(Ty, 0));
22712273
return new ZExtInst(IsZero, Ty);
22722274
}
@@ -2289,7 +2291,6 @@ Instruction *InstCombinerImpl::visitAnd(BinaryOperator &I) {
22892291
isKnownToBeAPowerOfTwo(Y, /*OrZero*/ true, /*Depth*/ 0, &I))
22902292
return BinaryOperator::CreateAnd(Builder.CreateNot(X), Y);
22912293

2292-
const APInt *C;
22932294
if (match(Op1, m_APInt(C))) {
22942295
const APInt *XorC;
22952296
if (match(Op0, m_OneUse(m_Xor(m_Value(X), m_APInt(XorC))))) {

llvm/test/Transforms/InstCombine/and.ll

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,92 @@ declare void @use32(i32)
77

88
; There should be no 'and' instructions left in any test.
99

10+
define i32 @test_with_1(i32 %x) {
11+
; CHECK-LABEL: @test_with_1(
12+
; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i32 [[X:%.*]], 0
13+
; CHECK-NEXT: [[AND:%.*]] = zext i1 [[TMP1]] to i32
14+
; CHECK-NEXT: ret i32 [[AND]]
15+
;
16+
%shl = shl i32 1, %x
17+
%and = and i32 %shl, 1
18+
ret i32 %and
19+
}
20+
21+
define i32 @test_with_3(i32 %x) {
22+
; CHECK-LABEL: @test_with_3(
23+
; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i32 [[X:%.*]], 0
24+
; CHECK-NEXT: [[AND:%.*]] = zext i1 [[TMP1]] to i32
25+
; CHECK-NEXT: ret i32 [[AND]]
26+
;
27+
%shl = shl i32 3, %x
28+
%and = and i32 %shl, 1
29+
ret i32 %and
30+
}
31+
32+
define i32 @test_with_5(i32 %x) {
33+
; CHECK-LABEL: @test_with_5(
34+
; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i32 [[X:%.*]], 0
35+
; CHECK-NEXT: [[AND:%.*]] = zext i1 [[TMP1]] to i32
36+
; CHECK-NEXT: ret i32 [[AND]]
37+
;
38+
%shl = shl i32 5, %x
39+
%and = and i32 %shl, 1
40+
ret i32 %and
41+
}
42+
43+
define i32 @test_with_neg_5(i32 %x) {
44+
; CHECK-LABEL: @test_with_neg_5(
45+
; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i32 [[X:%.*]], 0
46+
; CHECK-NEXT: [[AND:%.*]] = zext i1 [[TMP1]] to i32
47+
; CHECK-NEXT: ret i32 [[AND]]
48+
;
49+
%shl = shl i32 -5, %x
50+
%and = and i32 %shl, 1
51+
ret i32 %and
52+
}
53+
54+
define i32 @test_with_even(i32 %x) {
55+
; CHECK-LABEL: @test_with_even(
56+
; CHECK-NEXT: ret i32 0
57+
;
58+
%shl = shl i32 4, %x
59+
%and = and i32 %shl, 1
60+
ret i32 %and
61+
}
62+
63+
define <2 x i32> @test_vec(<2 x i32> %x) {
64+
; CHECK-LABEL: @test_vec(
65+
; CHECK-NEXT: [[TMP1:%.*]] = icmp eq <2 x i32> [[X:%.*]], zeroinitializer
66+
; CHECK-NEXT: [[AND:%.*]] = zext <2 x i1> [[TMP1]] to <2 x i32>
67+
; CHECK-NEXT: ret <2 x i32> [[AND]]
68+
;
69+
%shl = shl <2 x i32> <i32 5, i32 5>, %x
70+
%and = and <2 x i32> %shl, <i32 1, i32 1>
71+
ret <2 x i32> %and
72+
}
73+
74+
define i32 @test_with_neg_even(i32 %x) {
75+
; CHECK-LABEL: @test_with_neg_even(
76+
; CHECK-NEXT: ret i32 0
77+
;
78+
%shl = shl i32 -4, %x
79+
%and = and i32 %shl, 1
80+
ret i32 %and
81+
}
82+
83+
define i32 @test_with_more_one_use(i32 %x) {
84+
; CHECK-LABEL: @test_with_more_one_use(
85+
; CHECK-NEXT: [[SHL:%.*]] = shl i32 7, [[X:%.*]]
86+
; CHECK-NEXT: [[AND:%.*]] = and i32 [[SHL]], 1
87+
; CHECK-NEXT: call void @use32(i32 [[SHL]])
88+
; CHECK-NEXT: ret i32 [[AND]]
89+
;
90+
%shl = shl i32 7, %x
91+
%and = and i32 %shl, 1
92+
call void @use32(i32 %shl)
93+
ret i32 %and
94+
}
95+
1096
define i32 @test1(i32 %A) {
1197
; CHECK-LABEL: @test1(
1298
; CHECK-NEXT: ret i32 0

0 commit comments

Comments
 (0)