diff --git a/llvm/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp b/llvm/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp --- a/llvm/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp +++ b/llvm/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp @@ -768,9 +768,23 @@ return true; } +static bool processURem(BinaryOperator *Instr, LazyValueInfo *LVI) { + assert(Instr->getOpcode() == Instruction::URem); + // X % Y -> X for X < Y + if (LVI->getConstantRange(Instr->getOperand(0), Instr) + .getUnsignedMax() + .ult(LVI->getConstantRange(Instr->getOperand(1), Instr) + .getUnsignedMin())) { + Instr->replaceAllUsesWith(Instr->getOperand(0)); + Instr->eraseFromParent(); + return true; + } + return false; +} + /// Try to shrink a udiv/urem's width down to the smallest power of two that's /// sufficient to contain its operands. -static bool processUDivOrURem(BinaryOperator *Instr, LazyValueInfo *LVI) { +static bool narrowUDivOrURem(BinaryOperator *Instr, LazyValueInfo *LVI) { assert(Instr->getOpcode() == Instruction::UDiv || Instr->getOpcode() == Instruction::URem); if (Instr->getType()->isVectorTy()) @@ -812,6 +826,18 @@ return true; } +static bool processUDivOrURem(BinaryOperator *Instr, LazyValueInfo *LVI) { + assert(Instr->getOpcode() == Instruction::UDiv || + Instr->getOpcode() == Instruction::URem); + if (Instr->getType()->isVectorTy()) + return false; + + if (Instr->getOpcode() == Instruction::URem && processURem(Instr, LVI)) + return true; + + return narrowUDivOrURem(Instr, LVI); +} + static bool processSRem(BinaryOperator *SDI, LazyValueInfo *LVI) { assert(SDI->getOpcode() == Instruction::SRem); if (SDI->getType()->isVectorTy()) diff --git a/llvm/test/Transforms/CorrelatedValuePropagation/urem.ll b/llvm/test/Transforms/CorrelatedValuePropagation/urem.ll --- a/llvm/test/Transforms/CorrelatedValuePropagation/urem.ll +++ b/llvm/test/Transforms/CorrelatedValuePropagation/urem.ll @@ -152,6 +152,22 @@ ret void } +declare void @llvm.assume(i1) + +define i16 @test7(i16 %x, i16 %y) { +; CHECK-LABEL: @test7( +; CHECK: ret i16 %x +; + %above_range = icmp uge i16 %y, 13 + call void @llvm.assume(i1 %above_range) + + %below_range = icmp ult i16 %x, 13 + call void @llvm.assume(i1 %below_range) + + %r = urem i16 %x, %y + ret i16 %r +} + define void @non_power_of_2(i24 %n) { ; CHECK-LABEL: @non_power_of_2( ; CHECK-NEXT: [[DIV:%.*]] = urem i24 [[N:%.*]], 42