Skip to content

Commit 7d5f79f

Browse files
[InstCombine] Handle equality comparison when flooring by constant 2
Support `icmp eq` when reducing signed divisions by power of 2 to arithmetic shift right, as `icmp ugt` may have been canonicalized into `icmp eq` by the time additions are folded into `ashr`. Fixes: #73622. Proof: https://alive2.llvm.org/ce/z/8-eUdb.
1 parent e78a45d commit 7d5f79f

File tree

2 files changed

+80
-6
lines changed

2 files changed

+80
-6
lines changed

llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp

+16-6
Original file line numberDiff line numberDiff line change
@@ -1234,18 +1234,28 @@ static Instruction *foldAddToAshr(BinaryOperator &Add) {
12341234
return nullptr;
12351235

12361236
// Rounding is done by adding -1 if the dividend (X) is negative and has any
1237-
// low bits set. The canonical pattern for that is an "ugt" compare with SMIN:
1238-
// sext (icmp ugt (X & (DivC - 1)), SMIN)
1239-
const APInt *MaskC;
1237+
// low bits set. It recognizes two canonical patterns:
1238+
// 1. For an 'ugt' cmp with the signed minimum value (SMIN), the
1239+
// pattern is: sext (icmp ugt (X & (DivC - 1)), SMIN).
1240+
// 2. For an 'eq' cmp, the pattern's: sext (icmp eq X & (SMIN + 1), SMIN + 1).
1241+
// Note that, by the time we end up here, if possible, ugt has been
1242+
// canonicalized into eq.
1243+
const APInt *MaskC, *MaskCCmp;
12401244
ICmpInst::Predicate Pred;
12411245
if (!match(Add.getOperand(1),
12421246
m_SExt(m_ICmp(Pred, m_And(m_Specific(X), m_APInt(MaskC)),
1243-
m_SignMask()))) ||
1244-
Pred != ICmpInst::ICMP_UGT)
1247+
m_APInt(MaskCCmp)))))
1248+
return nullptr;
1249+
1250+
if ((Pred != ICmpInst::ICMP_UGT || !MaskCCmp->isSignMask()) &&
1251+
(Pred != ICmpInst::ICMP_EQ || *MaskCCmp != *MaskC))
12451252
return nullptr;
12461253

12471254
APInt SMin = APInt::getSignedMinValue(Add.getType()->getScalarSizeInBits());
1248-
if (*MaskC != (SMin | (*DivC - 1)))
1255+
bool IsMaskValid = Pred == ICmpInst::ICMP_UGT
1256+
? (*MaskC == (SMin | (*DivC - 1)))
1257+
: (*DivC == 2 && *MaskC == SMin + 1);
1258+
if (!IsMaskValid)
12491259
return nullptr;
12501260

12511261
// (X / DivC) + sext ((X & (SMin | (DivC - 1)) >u SMin) --> X >>s log2(DivC)

llvm/test/Transforms/InstCombine/add.ll

+64
Original file line numberDiff line numberDiff line change
@@ -2700,6 +2700,70 @@ define i32 @floor_sdiv(i32 %x) {
27002700
ret i32 %r
27012701
}
27022702

2703+
define i8 @floor_sdiv_by_2(i8 %x) {
2704+
; CHECK-LABEL: @floor_sdiv_by_2(
2705+
; CHECK-NEXT: [[RV:%.*]] = ashr i8 [[X:%.*]], 1
2706+
; CHECK-NEXT: ret i8 [[RV]]
2707+
;
2708+
%div = sdiv i8 %x, 2
2709+
%and = and i8 %x, -127
2710+
%icmp = icmp eq i8 %and, -127
2711+
%sext = sext i1 %icmp to i8
2712+
%rv = add nsw i8 %div, %sext
2713+
ret i8 %rv
2714+
}
2715+
2716+
define i8 @floor_sdiv_by_2_wrong_mask(i8 %x) {
2717+
; CHECK-LABEL: @floor_sdiv_by_2_wrong_mask(
2718+
; CHECK-NEXT: [[DIV:%.*]] = sdiv i8 [[X:%.*]], 2
2719+
; CHECK-NEXT: [[AND:%.*]] = and i8 [[X]], 127
2720+
; CHECK-NEXT: [[ICMP:%.*]] = icmp eq i8 [[AND]], 127
2721+
; CHECK-NEXT: [[SEXT:%.*]] = sext i1 [[ICMP]] to i8
2722+
; CHECK-NEXT: [[RV:%.*]] = add nsw i8 [[DIV]], [[SEXT]]
2723+
; CHECK-NEXT: ret i8 [[RV]]
2724+
;
2725+
%div = sdiv i8 %x, 2
2726+
%and = and i8 %x, 127
2727+
%icmp = icmp eq i8 %and, 127
2728+
%sext = sext i1 %icmp to i8
2729+
%rv = add nsw i8 %div, %sext
2730+
ret i8 %rv
2731+
}
2732+
2733+
define i8 @floor_sdiv_by_2_wrong_constant(i8 %x) {
2734+
; CHECK-LABEL: @floor_sdiv_by_2_wrong_constant(
2735+
; CHECK-NEXT: [[DIV:%.*]] = sdiv i8 [[X:%.*]], 4
2736+
; CHECK-NEXT: [[AND:%.*]] = and i8 [[X]], -125
2737+
; CHECK-NEXT: [[ICMP:%.*]] = icmp eq i8 [[AND]], -125
2738+
; CHECK-NEXT: [[SEXT:%.*]] = sext i1 [[ICMP]] to i8
2739+
; CHECK-NEXT: [[RV:%.*]] = add nsw i8 [[DIV]], [[SEXT]]
2740+
; CHECK-NEXT: ret i8 [[RV]]
2741+
;
2742+
%div = sdiv i8 %x, 4
2743+
%and = and i8 %x, -125
2744+
%icmp = icmp eq i8 %and, -125
2745+
%sext = sext i1 %icmp to i8
2746+
%rv = add nsw i8 %div, %sext
2747+
ret i8 %rv
2748+
}
2749+
2750+
define i8 @floor_sdiv_by_2_wrong_cast(i8 %x) {
2751+
; CHECK-LABEL: @floor_sdiv_by_2_wrong_cast(
2752+
; CHECK-NEXT: [[DIV:%.*]] = sdiv i8 [[X:%.*]], 2
2753+
; CHECK-NEXT: [[AND:%.*]] = and i8 [[X]], -127
2754+
; CHECK-NEXT: [[ICMP:%.*]] = icmp eq i8 [[AND]], -127
2755+
; CHECK-NEXT: [[SEXT:%.*]] = zext i1 [[ICMP]] to i8
2756+
; CHECK-NEXT: [[RV:%.*]] = add nsw i8 [[DIV]], [[SEXT]]
2757+
; CHECK-NEXT: ret i8 [[RV]]
2758+
;
2759+
%div = sdiv i8 %x, 2
2760+
%and = and i8 %x, -127
2761+
%icmp = icmp eq i8 %and, -127
2762+
%sext = zext i1 %icmp to i8
2763+
%rv = add nsw i8 %div, %sext
2764+
ret i8 %rv
2765+
}
2766+
27032767
; vectors work too and commute is handled by complexity-based canonicalization
27042768

27052769
define <2 x i32> @floor_sdiv_vec_commute(<2 x i32> %x) {

0 commit comments

Comments
 (0)