Skip to content

Commit 1bbd613

Browse files
[InstCombine] Fold lshr 1, X into zext (X == 0) (#200669)
This PR implements the missed optimisation reported in #200538. `1 >> X` produces 1 only when X == 0, and 0 for all other in-range values. Fold it directly into `zext (icmp eq X, 0)`.
1 parent 8635024 commit 1bbd613

6 files changed

Lines changed: 66 additions & 16 deletions

File tree

llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1402,6 +1402,10 @@ Instruction *InstCombinerImpl::visitLShr(BinaryOperator &I) {
14021402
const APInt *C;
14031403
unsigned BitWidth = Ty->getScalarSizeInBits();
14041404

1405+
// lshr 1, X --> zext (X == 0)
1406+
if (match(Op0, m_One()))
1407+
return new ZExtInst(Builder.CreateIsNull(Op1), Ty);
1408+
14051409
// (iN (~X) u>> (N - 1)) --> zext (X > -1)
14061410
if (match(Op0, m_OneUse(m_Not(m_Value(X)))) &&
14071411
match(Op1, m_SpecificIntAllowPoison(BitWidth - 1)))

llvm/test/Analysis/ValueTracking/recurrence-knownbits.ll

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -278,7 +278,8 @@ define i64 @test_ashr_wrong_op(i1 %c, i64 %start) {
278278
; CHECK-NEXT: br label [[LOOP:%.*]]
279279
; CHECK: loop:
280280
; CHECK-NEXT: [[IV_ASHR:%.*]] = phi i64 [ [[START:%.*]], [[ENTRY:%.*]] ], [ [[IV_ASHR_NEXT:%.*]], [[LOOP]] ]
281-
; CHECK-NEXT: [[IV_ASHR_NEXT]] = lshr i64 1, [[IV_ASHR]]
281+
; CHECK-NEXT: [[TMP0:%.*]] = icmp eq i64 [[IV_ASHR]], 0
282+
; CHECK-NEXT: [[IV_ASHR_NEXT]] = zext i1 [[TMP0]] to i64
282283
; CHECK-NEXT: br i1 [[C:%.*]], label [[EXIT:%.*]], label [[LOOP]]
283284
; CHECK: exit:
284285
; CHECK-NEXT: [[RES:%.*]] = or i64 [[IV_ASHR]], 1023

llvm/test/Transforms/InstCombine/and2.ll

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,8 @@ define <2 x i8> @and1_shl1_is_cmp_eq_0_vec_poison(<2 x i8> %x) {
183183

184184
define i8 @and1_lshr1_is_cmp_eq_0(i8 %x) {
185185
; CHECK-LABEL: @and1_lshr1_is_cmp_eq_0(
186-
; CHECK-NEXT: [[SH:%.*]] = lshr i8 1, [[X:%.*]]
186+
; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i8 [[X:%.*]], 0
187+
; CHECK-NEXT: [[SH:%.*]] = zext i1 [[TMP1]] to i8
187188
; CHECK-NEXT: ret i8 [[SH]]
188189
;
189190
%sh = lshr i8 1, %x
@@ -193,8 +194,8 @@ define i8 @and1_lshr1_is_cmp_eq_0(i8 %x) {
193194

194195
define i8 @and1_lshr1_is_cmp_eq_0_multiuse(i8 %x) {
195196
; CHECK-LABEL: @and1_lshr1_is_cmp_eq_0_multiuse(
196-
; CHECK-NEXT: [[SH:%.*]] = lshr i8 1, [[X:%.*]]
197-
; CHECK-NEXT: [[ADD:%.*]] = shl nuw nsw i8 [[SH]], 1
197+
; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i8 [[X:%.*]], 0
198+
; CHECK-NEXT: [[ADD:%.*]] = select i1 [[TMP1]], i8 2, i8 0
198199
; CHECK-NEXT: ret i8 [[ADD]]
199200
;
200201
%sh = lshr i8 1, %x
@@ -207,7 +208,8 @@ define i8 @and1_lshr1_is_cmp_eq_0_multiuse(i8 %x) {
207208

208209
define <2 x i8> @and1_lshr1_is_cmp_eq_0_vec(<2 x i8> %x) {
209210
; CHECK-LABEL: @and1_lshr1_is_cmp_eq_0_vec(
210-
; CHECK-NEXT: [[SH:%.*]] = lshr <2 x i8> splat (i8 1), [[X:%.*]]
211+
; CHECK-NEXT: [[TMP1:%.*]] = icmp eq <2 x i8> [[X:%.*]], zeroinitializer
212+
; CHECK-NEXT: [[SH:%.*]] = zext <2 x i1> [[TMP1]] to <2 x i8>
211213
; CHECK-NEXT: ret <2 x i8> [[SH]]
212214
;
213215
%sh = lshr <2 x i8> <i8 1, i8 1>, %x
@@ -217,7 +219,8 @@ define <2 x i8> @and1_lshr1_is_cmp_eq_0_vec(<2 x i8> %x) {
217219

218220
define <2 x i8> @and1_lshr1_is_cmp_eq_0_vec_poison(<2 x i8> %x) {
219221
; CHECK-LABEL: @and1_lshr1_is_cmp_eq_0_vec_poison(
220-
; CHECK-NEXT: [[AND:%.*]] = lshr <2 x i8> <i8 1, i8 poison>, [[X:%.*]]
222+
; CHECK-NEXT: [[TMP1:%.*]] = icmp eq <2 x i8> [[X:%.*]], zeroinitializer
223+
; CHECK-NEXT: [[AND:%.*]] = zext <2 x i1> [[TMP1]] to <2 x i8>
221224
; CHECK-NEXT: ret <2 x i8> [[AND]]
222225
;
223226
%sh = lshr <2 x i8> <i8 1, i8 poison>, %x

llvm/test/Transforms/InstCombine/conditional-variable-length-signext-after-high-bit-extract.ll

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1140,10 +1140,8 @@ define i32 @n290_or_with_wrong_magic(i32 %data, i32 %nbits) {
11401140

11411141
define i32 @bitwidth_does_not_fit(i3 %arg) {
11421142
; CHECK-LABEL: @bitwidth_does_not_fit(
1143-
; CHECK-NEXT: [[NEG:%.*]] = sub i3 0, [[ARG:%.*]]
1144-
; CHECK-NEXT: [[NEG_EXT:%.*]] = zext i3 [[NEG]] to i32
1145-
; CHECK-NEXT: [[SHR:%.*]] = lshr i32 1, [[NEG_EXT]]
1146-
; CHECK-NEXT: [[INC:%.*]] = add nuw nsw i32 [[SHR]], 1
1143+
; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i3 [[ARG:%.*]], 0
1144+
; CHECK-NEXT: [[INC:%.*]] = select i1 [[TMP1]], i32 2, i32 1
11471145
; CHECK-NEXT: ret i32 [[INC]]
11481146
;
11491147
%neg = sub i3 0, %arg

llvm/test/Transforms/InstCombine/lshr.ll

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1585,3 +1585,45 @@ entry:
15851585
%conv = and i32 %shift, 32767
15861586
ret i32 %conv
15871587
}
1588+
1589+
; lshr 1, X --> zext (X == 0)
1590+
1591+
define i32 @lshr_one_i32(i32 %x) {
1592+
; CHECK-LABEL: @lshr_one_i32(
1593+
; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i32 [[X:%.*]], 0
1594+
; CHECK-NEXT: [[SHR:%.*]] = zext i1 [[TMP1]] to i32
1595+
; CHECK-NEXT: ret i32 [[SHR]]
1596+
;
1597+
%shr = lshr i32 1, %x
1598+
ret i32 %shr
1599+
}
1600+
1601+
define i64 @lshr_one_i64(i64 %x) {
1602+
; CHECK-LABEL: @lshr_one_i64(
1603+
; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i64 [[X:%.*]], 0
1604+
; CHECK-NEXT: [[SHR:%.*]] = zext i1 [[TMP1]] to i64
1605+
; CHECK-NEXT: ret i64 [[SHR]]
1606+
;
1607+
%shr = lshr i64 1, %x
1608+
ret i64 %shr
1609+
}
1610+
1611+
define <4 x i32> @lshr_one_v4i32(<4 x i32> %x) {
1612+
; CHECK-LABEL: @lshr_one_v4i32(
1613+
; CHECK-NEXT: [[TMP1:%.*]] = icmp eq <4 x i32> [[X:%.*]], zeroinitializer
1614+
; CHECK-NEXT: [[SHR:%.*]] = zext <4 x i1> [[TMP1]] to <4 x i32>
1615+
; CHECK-NEXT: ret <4 x i32> [[SHR]]
1616+
;
1617+
%shr = lshr <4 x i32> <i32 1, i32 1, i32 1, i32 1>, %x
1618+
ret <4 x i32> %shr
1619+
}
1620+
1621+
; Negative test: constant is not 1
1622+
define i32 @lshr_two_i32(i32 %x) {
1623+
; CHECK-LABEL: @lshr_two_i32(
1624+
; CHECK-NEXT: [[SHR:%.*]] = lshr i32 2, [[X:%.*]]
1625+
; CHECK-NEXT: ret i32 [[SHR]]
1626+
;
1627+
%shr = lshr i32 2, %x
1628+
ret i32 %shr
1629+
}

llvm/test/Transforms/InstCombine/shift-direction-in-bit-test.ll

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -225,10 +225,11 @@ define i1 @t12_shift_of_const0(i32 %x, i32 %y, i32 %z) {
225225
}
226226
define i1 @t13_shift_of_const1(i32 %x, i32 %y, i32 %z) {
227227
; CHECK-LABEL: @t13_shift_of_const1(
228-
; CHECK-NEXT: [[T0:%.*]] = lshr i32 1, [[Y:%.*]]
229-
; CHECK-NEXT: [[T1:%.*]] = and i32 [[T0]], [[Z:%.*]]
228+
; CHECK-NEXT: [[TMP1:%.*]] = icmp ne i32 [[Y:%.*]], 0
229+
; CHECK-NEXT: [[T1:%.*]] = and i32 [[Z:%.*]], 1
230230
; CHECK-NEXT: [[T2:%.*]] = icmp eq i32 [[T1]], 0
231-
; CHECK-NEXT: ret i1 [[T2]]
231+
; CHECK-NEXT: [[T3:%.*]] = select i1 [[TMP1]], i1 true, i1 [[T2]]
232+
; CHECK-NEXT: ret i1 [[T3]]
232233
;
233234
%t0 = lshr i32 1, %y
234235
%t1 = and i32 %t0, %z
@@ -238,10 +239,11 @@ define i1 @t13_shift_of_const1(i32 %x, i32 %y, i32 %z) {
238239

239240
define i1 @t14_and_with_const0(i32 %x, i32 %y, i32 %z) {
240241
; CHECK-LABEL: @t14_and_with_const0(
241-
; CHECK-NEXT: [[TMP1:%.*]] = lshr i32 1, [[Y:%.*]]
242-
; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[X:%.*]], [[TMP1]]
242+
; CHECK-NEXT: [[TMP1:%.*]] = icmp ne i32 [[Y:%.*]], 0
243+
; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[X:%.*]], 1
243244
; CHECK-NEXT: [[T2:%.*]] = icmp eq i32 [[TMP2]], 0
244-
; CHECK-NEXT: ret i1 [[T2]]
245+
; CHECK-NEXT: [[T3:%.*]] = select i1 [[TMP1]], i1 true, i1 [[T2]]
246+
; CHECK-NEXT: ret i1 [[T3]]
245247
;
246248
%t0 = shl i32 %x, %y
247249
%t1 = and i32 %t0, 1

0 commit comments

Comments
 (0)