Skip to content

Commit 9885505

Browse files
committed
[InstCombine] reduce icmp_eq0-of-and-of-select-of-constants
This is the most basic patch to handle fixing issue #57666. D133919 proposes to handle much more than this in a single patch, but I've used 10 regression tests just to make sure this part is doing what I expected and nothing more, and it already shows even more potential TODO items. The more general proofs from D133919 are correct, but I want to enable this in smaller steps to reduce risk: https://alive2.llvm.org/ce/z/RrVEyX Differential Revision: https://reviews.llvm.org/D142847
1 parent e1cebe9 commit 9885505

File tree

2 files changed

+40
-9
lines changed

2 files changed

+40
-9
lines changed

llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp

+19
Original file line numberDiff line numberDiff line change
@@ -1888,6 +1888,25 @@ Instruction *InstCombinerImpl::foldICmpAndConstant(ICmpInst &Cmp,
18881888
return new ICmpInst(NewPred, X, SubOne(cast<Constant>(Cmp.getOperand(1))));
18891889
}
18901890

1891+
// If we are testing the intersection of 2 select-of-nonzero-constants with no
1892+
// common bits set, it's the same as checking if exactly one select condition
1893+
// is set:
1894+
// ((A ? TC : FC) & (B ? TC : FC)) == 0 --> xor A, B
1895+
// TODO: Generalize for non-constant values.
1896+
// TODO: Invert with a "ne" predicate.
1897+
// TODO: Handle signed/unsigned predicates.
1898+
// TODO: Handle other bitwise logic connectors.
1899+
// TODO: Extend to handle a non-zero compare constant.
1900+
if (Pred == CmpInst::ICMP_EQ && C.isZero()) {
1901+
Value *A, *B;
1902+
const APInt *TC, *FC;
1903+
if (match(X, m_Select(m_Value(A), m_APInt(TC), m_APInt(FC))) &&
1904+
match(Y,
1905+
m_Select(m_Value(B), m_SpecificInt(*TC), m_SpecificInt(*FC))) &&
1906+
!TC->isZero() && !FC->isZero() && !TC->intersects(*FC))
1907+
return BinaryOperator::CreateXor(A, B);
1908+
}
1909+
18911910
// ((zext i1 X) & Y) == 0 --> !((trunc Y) & X)
18921911
// ((zext i1 X) & Y) != 0 --> ((trunc Y) & X)
18931912
// ((zext i1 X) & Y) == 1 --> ((trunc Y) & X)

llvm/test/Transforms/InstCombine/icmp-select.ll

+21-9
Original file line numberDiff line numberDiff line change
@@ -262,10 +262,7 @@ define i1 @umin_seq_comparison(i8 %x, i8 %y) {
262262

263263
define i1 @select_constants_and_icmp_eq0(i1 %x, i1 %y) {
264264
; CHECK-LABEL: @select_constants_and_icmp_eq0(
265-
; CHECK-NEXT: [[S1:%.*]] = select i1 [[X:%.*]], i8 2, i8 1
266-
; CHECK-NEXT: [[S2:%.*]] = select i1 [[Y:%.*]], i8 2, i8 1
267-
; CHECK-NEXT: [[AND:%.*]] = and i8 [[S1]], [[S2]]
268-
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[AND]], 0
265+
; CHECK-NEXT: [[CMP:%.*]] = xor i1 [[X:%.*]], [[Y:%.*]]
269266
; CHECK-NEXT: ret i1 [[CMP]]
270267
;
271268
%s1 = select i1 %x, i8 2, i8 1
@@ -275,6 +272,8 @@ define i1 @select_constants_and_icmp_eq0(i1 %x, i1 %y) {
275272
ret i1 %cmp
276273
}
277274

275+
; extra uses on all intermediates are ok
276+
278277
define i1 @select_constants_and_icmp_eq0_uses(i1 %x, i1 %y) {
279278
; CHECK-LABEL: @select_constants_and_icmp_eq0_uses(
280279
; CHECK-NEXT: [[S1:%.*]] = select i1 [[X:%.*]], i8 2, i8 1
@@ -283,7 +282,7 @@ define i1 @select_constants_and_icmp_eq0_uses(i1 %x, i1 %y) {
283282
; CHECK-NEXT: call void @use(i8 [[S2]])
284283
; CHECK-NEXT: [[AND:%.*]] = and i8 [[S1]], [[S2]]
285284
; CHECK-NEXT: call void @use(i8 [[AND]])
286-
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[AND]], 0
285+
; CHECK-NEXT: [[CMP:%.*]] = xor i1 [[X]], [[Y]]
287286
; CHECK-NEXT: ret i1 [[CMP]]
288287
;
289288
%s1 = select i1 %x, i8 2, i8 1
@@ -296,12 +295,11 @@ define i1 @select_constants_and_icmp_eq0_uses(i1 %x, i1 %y) {
296295
ret i1 %cmp
297296
}
298297

298+
; vector splat constants are ok
299+
299300
define <2 x i1> @select_constants_and_icmp_eq0_vec_splat(<2 x i1> %x, <2 x i1> %y) {
300301
; CHECK-LABEL: @select_constants_and_icmp_eq0_vec_splat(
301-
; CHECK-NEXT: [[S1:%.*]] = select <2 x i1> [[X:%.*]], <2 x i9> <i9 3, i9 3>, <2 x i9> <i9 48, i9 48>
302-
; CHECK-NEXT: [[S2:%.*]] = select <2 x i1> [[Y:%.*]], <2 x i9> <i9 3, i9 3>, <2 x i9> <i9 48, i9 48>
303-
; CHECK-NEXT: [[AND:%.*]] = and <2 x i9> [[S1]], [[S2]]
304-
; CHECK-NEXT: [[CMP:%.*]] = icmp eq <2 x i9> [[AND]], zeroinitializer
302+
; CHECK-NEXT: [[CMP:%.*]] = xor <2 x i1> [[X:%.*]], [[Y:%.*]]
305303
; CHECK-NEXT: ret <2 x i1> [[CMP]]
306304
;
307305
%s1 = select <2 x i1> %x, <2 x i9> <i9 3, i9 3>, <2 x i9> <i9 48, i9 48>
@@ -311,6 +309,8 @@ define <2 x i1> @select_constants_and_icmp_eq0_vec_splat(<2 x i1> %x, <2 x i1> %
311309
ret <2 x i1> %cmp
312310
}
313311

312+
; common bit set - simplified via known bits
313+
314314
define i1 @select_constants_and_icmp_eq0_common_bit(i1 %x, i1 %y) {
315315
; CHECK-LABEL: @select_constants_and_icmp_eq0_common_bit(
316316
; CHECK-NEXT: ret i1 false
@@ -322,6 +322,8 @@ define i1 @select_constants_and_icmp_eq0_common_bit(i1 %x, i1 %y) {
322322
ret i1 %cmp
323323
}
324324

325+
; negative test - need matching constants
326+
325327
define i1 @select_constants_and_icmp_eq0_no_common_op1(i1 %x, i1 %y) {
326328
; CHECK-LABEL: @select_constants_and_icmp_eq0_no_common_op1(
327329
; CHECK-NEXT: [[S1:%.*]] = select i1 [[X:%.*]], i8 16, i8 3
@@ -337,6 +339,8 @@ define i1 @select_constants_and_icmp_eq0_no_common_op1(i1 %x, i1 %y) {
337339
ret i1 %cmp
338340
}
339341

342+
; negative test - need matching constants
343+
340344
define i1 @select_constants_and_icmp_eq0_no_common_op2(i1 %x, i1 %y) {
341345
; CHECK-LABEL: @select_constants_and_icmp_eq0_no_common_op2(
342346
; CHECK-NEXT: [[S1:%.*]] = select i1 [[X:%.*]], i8 16, i8 3
@@ -352,6 +356,8 @@ define i1 @select_constants_and_icmp_eq0_no_common_op2(i1 %x, i1 %y) {
352356
ret i1 %cmp
353357
}
354358

359+
; reduces via FoldOpInstSelect, but this could be a simple 'or'
360+
355361
define i1 @select_constants_and_icmp_eq0_zero_tval(i1 %x, i1 %y) {
356362
; CHECK-LABEL: @select_constants_and_icmp_eq0_zero_tval(
357363
; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[X:%.*]], i1 true, i1 [[Y:%.*]]
@@ -364,6 +370,8 @@ define i1 @select_constants_and_icmp_eq0_zero_tval(i1 %x, i1 %y) {
364370
ret i1 %cmp
365371
}
366372

373+
; reduces via FoldOpInstSelect, but this could be a simple 'not-of-and'
374+
367375
define i1 @select_constants_and_icmp_eq0_zero_fval(i1 %x, i1 %y) {
368376
; CHECK-LABEL: @select_constants_and_icmp_eq0_zero_fval(
369377
; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[X:%.*]], i1 [[Y:%.*]], i1 false
@@ -377,6 +385,8 @@ define i1 @select_constants_and_icmp_eq0_zero_fval(i1 %x, i1 %y) {
377385
ret i1 %cmp
378386
}
379387

388+
; TODO: x & y
389+
380390
define i1 @select_constants_and_icmp_eq_tval(i1 %x, i1 %y) {
381391
; CHECK-LABEL: @select_constants_and_icmp_eq_tval(
382392
; CHECK-NEXT: [[S1:%.*]] = select i1 [[X:%.*]], i8 6, i8 1
@@ -392,6 +402,8 @@ define i1 @select_constants_and_icmp_eq_tval(i1 %x, i1 %y) {
392402
ret i1 %cmp
393403
}
394404

405+
; TODO: ~(x | y)
406+
395407
define i1 @select_constants_and_icmp_eq_fval(i1 %x, i1 %y) {
396408
; CHECK-LABEL: @select_constants_and_icmp_eq_fval(
397409
; CHECK-NEXT: [[S1:%.*]] = select i1 [[X:%.*]], i8 12, i8 3

0 commit comments

Comments
 (0)