Skip to content

Commit e477989

Browse files
authored
[InstCombine] Handle trunc i1 pattern in eq-of-parts fold (#112704)
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 612f8ec commit e477989

File tree

3 files changed

+22
-16
lines changed

3 files changed

+22
-16
lines changed

llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1185,14 +1185,27 @@ 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+
assert(CmpV->getType()->isIntOrIntVectorTy(1) && "Must be bool");
1196+
1197+
Value *X, *Y;
1198+
// icmp ne (and x, 1), (and y, 1) <=> trunc (xor x, y) to i1
1199+
// icmp eq (and x, 1), (and y, 1) <=> not (trunc (xor x, y) to i1)
1200+
if (Pred == CmpInst::ICMP_NE
1201+
? match(CmpV, m_Trunc(m_Xor(m_Value(X), m_Value(Y))))
1202+
: match(CmpV, m_Not(m_Trunc(m_Xor(m_Value(X), m_Value(Y))))))
1203+
return {{OpNo == 0 ? X : Y, 0, 1}};
1204+
1205+
auto *Cmp = dyn_cast<ICmpInst>(CmpV);
1206+
if (!Cmp)
1207+
return std::nullopt;
1208+
11961209
if (Pred == Cmp->getPredicate())
11971210
return matchIntPart(Cmp->getOperand(OpNo));
11981211

@@ -3404,9 +3417,6 @@ Value *InstCombinerImpl::foldAndOrOfICmps(ICmpInst *LHS, ICmpInst *RHS,
34043417
return X;
34053418
}
34063419

3407-
if (Value *X = foldEqOfParts(LHS, RHS, IsAnd))
3408-
return X;
3409-
34103420
// (icmp ne A, 0) | (icmp ne B, 0) --> (icmp ne (A|B), 0)
34113421
// (icmp eq A, 0) & (icmp eq B, 0) --> (icmp eq (A|B), 0)
34123422
// TODO: Remove this and below when foldLogOpOfMaskedICmps can handle undefs.
@@ -3529,6 +3539,9 @@ Value *InstCombinerImpl::foldBooleanAndOr(Value *LHS, Value *RHS,
35293539
if (Value *Res = foldLogicOfFCmps(LHSCmp, RHSCmp, IsAnd, IsLogical))
35303540
return Res;
35313541

3542+
if (Value *Res = foldEqOfParts(LHS, RHS, IsAnd))
3543+
return Res;
3544+
35323545
return nullptr;
35333546
}
35343547

llvm/lib/Transforms/InstCombine/InstCombineInternal.h

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

415-
Value *foldEqOfParts(ICmpInst *Cmp0, ICmpInst *Cmp1, bool IsAnd);
415+
Value *foldEqOfParts(Value *Cmp0, Value *Cmp1, bool IsAnd);
416416

417417
Value *foldAndOrOfICmpsUsingRanges(ICmpInst *ICmp1, ICmpInst *ICmp2,
418418
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)