diff --git a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp --- a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp @@ -1787,6 +1787,17 @@ return SelectInst::Create(Cmp, ConstantInt::getNullValue(Ty), Op0); } + // For "(X + 1) % Op1" and if (X u< Op1) => (X + 1) == Op1 ? 0 : X + 1 . + if (match(Op0, m_Add(m_Value(X), m_One()))) { + Value *Val = + simplifyICmpInst(ICmpInst::ICMP_ULT, X, Op1, SQ.getWithInstruction(&I)); + if (Val && match(Val, m_One())) { + Value *FrozenOp0 = Builder.CreateFreeze(Op0, Op0->getName() + ".frozen"); + Value *Cmp = Builder.CreateICmpEQ(FrozenOp0, Op1); + return SelectInst::Create(Cmp, ConstantInt::getNullValue(Ty), FrozenOp0); + } + } + return nullptr; } diff --git a/llvm/test/Transforms/InstCombine/urem-via-cmp-select.ll b/llvm/test/Transforms/InstCombine/urem-via-cmp-select.ll --- a/llvm/test/Transforms/InstCombine/urem-via-cmp-select.ll +++ b/llvm/test/Transforms/InstCombine/urem-via-cmp-select.ll @@ -1,13 +1,15 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py ; RUN: opt < %s -passes=instcombine -S | FileCheck %s -; TODO: https://alive2.llvm.org/ce/z/5eCiWi +; https://alive2.llvm.org/ce/z/5eCiWi define i8 @urem_assume(i8 %x, i8 %n) { ; CHECK-LABEL: @urem_assume( -; CHECK-NEXT: [[CMP:%.*]] = icmp ult i8 [[X:%.*]], [[N:%.*]] +; CHECK-NEXT: [[X_FR:%.*]] = freeze i8 [[X:%.*]] +; CHECK-NEXT: [[CMP:%.*]] = icmp ult i8 [[X_FR]], [[N:%.*]] ; CHECK-NEXT: tail call void @llvm.assume(i1 [[CMP]]) -; CHECK-NEXT: [[ADD:%.*]] = add nuw i8 [[X]], 1 -; CHECK-NEXT: [[OUT:%.*]] = urem i8 [[ADD]], [[N]] +; CHECK-NEXT: [[ADD:%.*]] = add i8 [[X_FR]], 1 +; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i8 [[ADD]], [[N]] +; CHECK-NEXT: [[OUT:%.*]] = select i1 [[TMP1]], i8 0, i8 [[ADD]] ; CHECK-NEXT: ret i8 [[OUT]] ; %cmp = icmp ult i8 %x, %n @@ -17,13 +19,15 @@ ret i8 %out } -; TODO: https://alive2.llvm.org/ce/z/MGgtYN +; https://alive2.llvm.org/ce/z/MGgtYN define i8 @urem_assume_without_nuw(i8 %x, i8 %n) { ; CHECK-LABEL: @urem_assume_without_nuw( -; CHECK-NEXT: [[CMP:%.*]] = icmp ult i8 [[X:%.*]], [[N:%.*]] +; CHECK-NEXT: [[X_FR:%.*]] = freeze i8 [[X:%.*]] +; CHECK-NEXT: [[CMP:%.*]] = icmp ult i8 [[X_FR]], [[N:%.*]] ; CHECK-NEXT: tail call void @llvm.assume(i1 [[CMP]]) -; CHECK-NEXT: [[ADD:%.*]] = add i8 [[X]], 1 -; CHECK-NEXT: [[OUT:%.*]] = urem i8 [[ADD]], [[N]] +; CHECK-NEXT: [[ADD:%.*]] = add i8 [[X_FR]], 1 +; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i8 [[ADD]], [[N]] +; CHECK-NEXT: [[OUT:%.*]] = select i1 [[TMP1]], i8 0, i8 [[ADD]] ; CHECK-NEXT: ret i8 [[OUT]] ; %cmp = icmp ult i8 %x, %n @@ -83,12 +87,14 @@ ret i8 %out } -; TODO: https://alive2.llvm.org/ce/z/gNhZ2x +; https://alive2.llvm.org/ce/z/gNhZ2x define i8 @urem_without_assume(i8 %arg, i8 %arg2) { ; CHECK-LABEL: @urem_without_assume( ; CHECK-NEXT: [[X:%.*]] = urem i8 [[ARG:%.*]], [[ARG2:%.*]] -; CHECK-NEXT: [[ADD:%.*]] = add i8 [[X]], 1 -; CHECK-NEXT: [[OUT:%.*]] = urem i8 [[ADD]], [[ARG2]] +; CHECK-NEXT: [[X_FR:%.*]] = freeze i8 [[X]] +; CHECK-NEXT: [[ADD:%.*]] = add i8 [[X_FR]], 1 +; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i8 [[ADD]], [[ARG2]] +; CHECK-NEXT: [[OUT:%.*]] = select i1 [[TMP1]], i8 0, i8 [[ADD]] ; CHECK-NEXT: ret i8 [[OUT]] ; %x = urem i8 %arg, %arg2