Skip to content

Commit a9402ae

Browse files
committed
[InstCombine] Handle trunc i1 pattern in eq-of-parts fold
Equality/inequality of the low bit can be represented by `(trunc (xor x, y) to i1)`, possibly with an extra not. We have to handle this in the eq-of-parts fold now that we no longer canonicalize this to a masked icmp. Proofs: https://alive2.llvm.org/ce/z/qidkzq Fixes #110919.
1 parent d9cd607 commit a9402ae

File tree

3 files changed

+20
-16
lines changed

3 files changed

+20
-16
lines changed

llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1185,14 +1185,25 @@ static Value *extractIntPart(const IntPart &P, IRBuilderBase &Builder) {
11851185
/// (icmp eq X0, Y0) & (icmp eq X1, Y1) -> icmp eq X01, Y01
11861186
/// (icmp ne X0, Y0) | (icmp ne X1, Y1) -> icmp ne X01, Y01
11871187
/// where X0, X1 and Y0, Y1 are adjacent parts extracted from an integer.
1188-
Value *InstCombinerImpl::foldEqOfParts(ICmpInst *Cmp0, ICmpInst *Cmp1,
1189-
bool IsAnd) {
1188+
Value *InstCombinerImpl::foldEqOfParts(Value *Cmp0, Value *Cmp1, bool IsAnd) {
11901189
if (!Cmp0->hasOneUse() || !Cmp1->hasOneUse())
11911190
return nullptr;
11921191

11931192
CmpInst::Predicate Pred = IsAnd ? CmpInst::ICMP_EQ : CmpInst::ICMP_NE;
1194-
auto GetMatchPart = [&](ICmpInst *Cmp,
1193+
auto GetMatchPart = [&](Value *CmpV,
11951194
unsigned OpNo) -> std::optional<IntPart> {
1195+
Value *X, *Y;
1196+
// icmp ne (and x, 1), (and y, 1) <=> trunc (xor x, y) to i1
1197+
// icmp eq (and x, 1), (and y, 1) <=> not (trunc (xor x, y) to i1)
1198+
if (Pred == CmpInst::ICMP_NE
1199+
? match(CmpV, m_Trunc(m_Xor(m_Value(X), m_Value(Y))))
1200+
: match(CmpV, m_Not(m_Trunc(m_Xor(m_Value(X), m_Value(Y))))))
1201+
return {{OpNo == 0 ? X : Y, 0, 1}};
1202+
1203+
auto *Cmp = dyn_cast<ICmpInst>(CmpV);
1204+
if (!Cmp)
1205+
return std::nullopt;
1206+
11961207
if (Pred == Cmp->getPredicate())
11971208
return matchIntPart(Cmp->getOperand(OpNo));
11981209

@@ -3413,9 +3424,6 @@ Value *InstCombinerImpl::foldAndOrOfICmps(ICmpInst *LHS, ICmpInst *RHS,
34133424
return X;
34143425
}
34153426

3416-
if (Value *X = foldEqOfParts(LHS, RHS, IsAnd))
3417-
return X;
3418-
34193427
// (icmp ne A, 0) | (icmp ne B, 0) --> (icmp ne (A|B), 0)
34203428
// (icmp eq A, 0) & (icmp eq B, 0) --> (icmp eq (A|B), 0)
34213429
// TODO: Remove this and below when foldLogOpOfMaskedICmps can handle undefs.
@@ -3538,6 +3546,9 @@ Value *InstCombinerImpl::foldBooleanAndOr(Value *LHS, Value *RHS,
35383546
if (Value *Res = foldLogicOfFCmps(LHSCmp, RHSCmp, IsAnd, IsLogical))
35393547
return Res;
35403548

3549+
if (Value *Res = foldEqOfParts(LHS, RHS, IsAnd))
3550+
return Res;
3551+
35413552
return nullptr;
35423553
}
35433554

llvm/lib/Transforms/InstCombine/InstCombineInternal.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -411,7 +411,7 @@ class LLVM_LIBRARY_VISIBILITY InstCombinerImpl final
411411
bool IsAnd, bool IsLogical = false);
412412
Value *foldXorOfICmps(ICmpInst *LHS, ICmpInst *RHS, BinaryOperator &Xor);
413413

414-
Value *foldEqOfParts(ICmpInst *Cmp0, ICmpInst *Cmp1, bool IsAnd);
414+
Value *foldEqOfParts(Value *Cmp0, Value *Cmp1, bool IsAnd);
415415

416416
Value *foldAndOrOfICmpsUsingRanges(ICmpInst *ICmp1, ICmpInst *ICmp2,
417417
bool IsAnd);

llvm/test/Transforms/InstCombine/eq-of-parts.ll

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1441,11 +1441,7 @@ define i1 @ne_optimized_highbits_cmp_todo_overlapping(i32 %x, i32 %y) {
14411441

14421442
define i1 @and_trunc_i1(i8 %a1, i8 %a2) {
14431443
; CHECK-LABEL: @and_trunc_i1(
1444-
; CHECK-NEXT: [[XOR:%.*]] = xor i8 [[A1:%.*]], [[A2:%.*]]
1445-
; CHECK-NEXT: [[CMP:%.*]] = icmp ult i8 [[XOR]], 2
1446-
; CHECK-NEXT: [[LOBIT:%.*]] = trunc i8 [[XOR]] to i1
1447-
; CHECK-NEXT: [[LOBIT_INV:%.*]] = xor i1 [[LOBIT]], true
1448-
; CHECK-NEXT: [[AND:%.*]] = and i1 [[CMP]], [[LOBIT_INV]]
1444+
; CHECK-NEXT: [[AND:%.*]] = icmp eq i8 [[A1:%.*]], [[A2:%.*]]
14491445
; CHECK-NEXT: ret i1 [[AND]]
14501446
;
14511447
%xor = xor i8 %a1, %a2
@@ -1494,10 +1490,7 @@ define i1 @and_trunc_i1_wrong_operands(i8 %a1, i8 %a2, i8 %a3) {
14941490

14951491
define i1 @or_trunc_i1(i64 %a1, i64 %a2) {
14961492
; CHECK-LABEL: @or_trunc_i1(
1497-
; CHECK-NEXT: [[XOR:%.*]] = xor i64 [[A2:%.*]], [[A1:%.*]]
1498-
; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i64 [[XOR]], 1
1499-
; CHECK-NEXT: [[TRUNC:%.*]] = trunc i64 [[XOR]] to i1
1500-
; CHECK-NEXT: [[OR:%.*]] = or i1 [[CMP]], [[TRUNC]]
1493+
; CHECK-NEXT: [[OR:%.*]] = icmp ne i64 [[A2:%.*]], [[A1:%.*]]
15011494
; CHECK-NEXT: ret i1 [[OR]]
15021495
;
15031496
%xor = xor i64 %a2, %a1

0 commit comments

Comments
 (0)