diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp index 24a166906f1f4..3604abb8e5277 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp @@ -1234,18 +1234,28 @@ static Instruction *foldAddToAshr(BinaryOperator &Add) { return nullptr; // Rounding is done by adding -1 if the dividend (X) is negative and has any - // low bits set. The canonical pattern for that is an "ugt" compare with SMIN: - // sext (icmp ugt (X & (DivC - 1)), SMIN) - const APInt *MaskC; + // low bits set. It recognizes two canonical patterns: + // 1. For an 'ugt' cmp with the signed minimum value (SMIN), the + // pattern is: sext (icmp ugt (X & (DivC - 1)), SMIN). + // 2. For an 'eq' cmp, the pattern's: sext (icmp eq X & (SMIN + 1), SMIN + 1). + // Note that, by the time we end up here, if possible, ugt has been + // canonicalized into eq. + const APInt *MaskC, *MaskCCmp; ICmpInst::Predicate Pred; if (!match(Add.getOperand(1), m_SExt(m_ICmp(Pred, m_And(m_Specific(X), m_APInt(MaskC)), - m_SignMask()))) || - Pred != ICmpInst::ICMP_UGT) + m_APInt(MaskCCmp))))) + return nullptr; + + if ((Pred != ICmpInst::ICMP_UGT || !MaskCCmp->isSignMask()) && + (Pred != ICmpInst::ICMP_EQ || *MaskCCmp != *MaskC)) return nullptr; APInt SMin = APInt::getSignedMinValue(Add.getType()->getScalarSizeInBits()); - if (*MaskC != (SMin | (*DivC - 1))) + bool IsMaskValid = Pred == ICmpInst::ICMP_UGT + ? (*MaskC == (SMin | (*DivC - 1))) + : (*DivC == 2 && *MaskC == SMin + 1); + if (!IsMaskValid) return nullptr; // (X / DivC) + sext ((X & (SMin | (DivC - 1)) >u SMin) --> X >>s log2(DivC) diff --git a/llvm/test/Transforms/InstCombine/add.ll b/llvm/test/Transforms/InstCombine/add.ll index c35d2af42a4be..b0b5f955c9fb0 100644 --- a/llvm/test/Transforms/InstCombine/add.ll +++ b/llvm/test/Transforms/InstCombine/add.ll @@ -2700,6 +2700,70 @@ define i32 @floor_sdiv(i32 %x) { ret i32 %r } +define i8 @floor_sdiv_by_2(i8 %x) { +; CHECK-LABEL: @floor_sdiv_by_2( +; CHECK-NEXT: [[RV:%.*]] = ashr i8 [[X:%.*]], 1 +; CHECK-NEXT: ret i8 [[RV]] +; + %div = sdiv i8 %x, 2 + %and = and i8 %x, -127 + %icmp = icmp eq i8 %and, -127 + %sext = sext i1 %icmp to i8 + %rv = add nsw i8 %div, %sext + ret i8 %rv +} + +define i8 @floor_sdiv_by_2_wrong_mask(i8 %x) { +; CHECK-LABEL: @floor_sdiv_by_2_wrong_mask( +; CHECK-NEXT: [[DIV:%.*]] = sdiv i8 [[X:%.*]], 2 +; CHECK-NEXT: [[AND:%.*]] = and i8 [[X]], 127 +; CHECK-NEXT: [[ICMP:%.*]] = icmp eq i8 [[AND]], 127 +; CHECK-NEXT: [[SEXT:%.*]] = sext i1 [[ICMP]] to i8 +; CHECK-NEXT: [[RV:%.*]] = add nsw i8 [[DIV]], [[SEXT]] +; CHECK-NEXT: ret i8 [[RV]] +; + %div = sdiv i8 %x, 2 + %and = and i8 %x, 127 + %icmp = icmp eq i8 %and, 127 + %sext = sext i1 %icmp to i8 + %rv = add nsw i8 %div, %sext + ret i8 %rv +} + +define i8 @floor_sdiv_by_2_wrong_constant(i8 %x) { +; CHECK-LABEL: @floor_sdiv_by_2_wrong_constant( +; CHECK-NEXT: [[DIV:%.*]] = sdiv i8 [[X:%.*]], 4 +; CHECK-NEXT: [[AND:%.*]] = and i8 [[X]], -125 +; CHECK-NEXT: [[ICMP:%.*]] = icmp eq i8 [[AND]], -125 +; CHECK-NEXT: [[SEXT:%.*]] = sext i1 [[ICMP]] to i8 +; CHECK-NEXT: [[RV:%.*]] = add nsw i8 [[DIV]], [[SEXT]] +; CHECK-NEXT: ret i8 [[RV]] +; + %div = sdiv i8 %x, 4 + %and = and i8 %x, -125 + %icmp = icmp eq i8 %and, -125 + %sext = sext i1 %icmp to i8 + %rv = add nsw i8 %div, %sext + ret i8 %rv +} + +define i8 @floor_sdiv_by_2_wrong_cast(i8 %x) { +; CHECK-LABEL: @floor_sdiv_by_2_wrong_cast( +; CHECK-NEXT: [[DIV:%.*]] = sdiv i8 [[X:%.*]], 2 +; CHECK-NEXT: [[AND:%.*]] = and i8 [[X]], -127 +; CHECK-NEXT: [[ICMP:%.*]] = icmp eq i8 [[AND]], -127 +; CHECK-NEXT: [[SEXT:%.*]] = zext i1 [[ICMP]] to i8 +; CHECK-NEXT: [[RV:%.*]] = add nsw i8 [[DIV]], [[SEXT]] +; CHECK-NEXT: ret i8 [[RV]] +; + %div = sdiv i8 %x, 2 + %and = and i8 %x, -127 + %icmp = icmp eq i8 %and, -127 + %sext = zext i1 %icmp to i8 + %rv = add nsw i8 %div, %sext + ret i8 %rv +} + ; vectors work too and commute is handled by complexity-based canonicalization define <2 x i32> @floor_sdiv_vec_commute(<2 x i32> %x) {