diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp --- a/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp @@ -1529,6 +1529,31 @@ return Builder.CreateIntCast(Result, Ty, true); } +/// If we have: +/// x - ((x / y) * y) +/// We can transform it into: +/// x % y +static Instruction * +produceRemFromSubtractionOfRoundeddownValue(BinaryOperator &I) { + assert(I.getOpcode() == Instruction::Sub && "Must start from 'sub'."); + + Value *X = I.getOperand(0); + Value *XroundedDownToMultipleOfY = I.getOperand(1); + + Value *Y; + Instruction *Div; + // Look for ((x / y) * y) + if (!match(XroundedDownToMultipleOfY, + m_c_Mul(m_CombineAnd(m_IDiv(m_Specific(X), m_Value(Y)), + m_Instruction(Div)), + m_Deferred(Y)))) + return nullptr; + + return Div->getOpcode() == Instruction::SDiv + ? BinaryOperator::CreateSRem(X, Y, I.getName()) + : BinaryOperator::CreateURem(X, Y, I.getName()); +} + Instruction *InstCombiner::visitSub(BinaryOperator &I) { if (Value *V = SimplifySubInst(I.getOperand(0), I.getOperand(1), I.hasNoSignedWrap(), I.hasNoUnsignedWrap(), @@ -1791,6 +1816,9 @@ } } + if (Instruction *Ext = produceRemFromSubtractionOfRoundeddownValue(I)) + return Ext; + // Optimize pointer differences into the same array into a size. Consider: // &A[10] - &A[0]: we should compile this to "10". Value *LHSOp, *RHSOp; diff --git a/llvm/test/Transforms/InstCombine/srem-via-sdiv-mul-sub.ll b/llvm/test/Transforms/InstCombine/srem-via-sdiv-mul-sub.ll --- a/llvm/test/Transforms/InstCombine/srem-via-sdiv-mul-sub.ll +++ b/llvm/test/Transforms/InstCombine/srem-via-sdiv-mul-sub.ll @@ -18,8 +18,7 @@ ; CHECK-LABEL: @t0_basic( ; CHECK-NEXT: [[DIV:%.*]] = sdiv i8 [[X:%.*]], [[Y:%.*]] ; CHECK-NEXT: call void @use8(i8 [[DIV]]) -; CHECK-NEXT: [[ROUNDXDOWNTOMULTIPLEOFY:%.*]] = mul i8 [[DIV]], [[Y]] -; CHECK-NEXT: [[REM:%.*]] = sub i8 [[X]], [[ROUNDXDOWNTOMULTIPLEOFY]] +; CHECK-NEXT: [[REM:%.*]] = srem i8 [[X]], [[Y]] ; CHECK-NEXT: ret i8 [[REM]] ; %div = sdiv i8 %x, %y @@ -33,8 +32,7 @@ ; CHECK-LABEL: @t1_vector( ; CHECK-NEXT: [[DIV:%.*]] = sdiv <2 x i8> [[X:%.*]], [[Y:%.*]] ; CHECK-NEXT: call void @use2xi8(<2 x i8> [[DIV]]) -; CHECK-NEXT: [[ROUNDXDOWNTOMULTIPLEOFY:%.*]] = mul <2 x i8> [[DIV]], [[Y]] -; CHECK-NEXT: [[REM:%.*]] = sub <2 x i8> [[X]], [[ROUNDXDOWNTOMULTIPLEOFY]] +; CHECK-NEXT: [[REM:%.*]] = srem <2 x i8> [[X]], [[Y]] ; CHECK-NEXT: ret <2 x i8> [[REM]] ; %div = sdiv <2 x i8> %x, %y @@ -52,7 +50,7 @@ ; CHECK-NEXT: call void @use8(i8 [[DIV]]) ; CHECK-NEXT: [[ROUNDXDOWNTOMULTIPLEOFY:%.*]] = mul i8 [[DIV]], [[Y]] ; CHECK-NEXT: call void @use8(i8 [[ROUNDXDOWNTOMULTIPLEOFY]]) -; CHECK-NEXT: [[REM:%.*]] = sub i8 [[X]], [[ROUNDXDOWNTOMULTIPLEOFY]] +; CHECK-NEXT: [[REM:%.*]] = srem i8 [[X]], [[Y]] ; CHECK-NEXT: ret i8 [[REM]] ; %div = sdiv i8 %x, %y @@ -72,8 +70,7 @@ ; CHECK-NEXT: [[Y:%.*]] = call i8 @gen8() ; CHECK-NEXT: [[DIV:%.*]] = sdiv i8 [[X:%.*]], [[Y]] ; CHECK-NEXT: call void @use8(i8 [[DIV]]) -; CHECK-NEXT: [[ROUNDXDOWNTOMULTIPLEOFY:%.*]] = mul i8 [[Y]], [[DIV]] -; CHECK-NEXT: [[REM:%.*]] = sub i8 [[X]], [[ROUNDXDOWNTOMULTIPLEOFY]] +; CHECK-NEXT: [[REM:%.*]] = srem i8 [[X]], [[Y]] ; CHECK-NEXT: ret i8 [[REM]] ; %y = call i8 @gen8() diff --git a/llvm/test/Transforms/InstCombine/urem-via-udiv-mul-sub.ll b/llvm/test/Transforms/InstCombine/urem-via-udiv-mul-sub.ll --- a/llvm/test/Transforms/InstCombine/urem-via-udiv-mul-sub.ll +++ b/llvm/test/Transforms/InstCombine/urem-via-udiv-mul-sub.ll @@ -18,8 +18,7 @@ ; CHECK-LABEL: @t0_basic( ; CHECK-NEXT: [[DIV:%.*]] = udiv i8 [[X:%.*]], [[Y:%.*]] ; CHECK-NEXT: call void @use8(i8 [[DIV]]) -; CHECK-NEXT: [[ROUNDXDOWNTOMULTIPLEOFY:%.*]] = mul i8 [[DIV]], [[Y]] -; CHECK-NEXT: [[REM:%.*]] = sub i8 [[X]], [[ROUNDXDOWNTOMULTIPLEOFY]] +; CHECK-NEXT: [[REM:%.*]] = urem i8 [[X]], [[Y]] ; CHECK-NEXT: ret i8 [[REM]] ; %div = udiv i8 %x, %y @@ -33,8 +32,7 @@ ; CHECK-LABEL: @t1_vector( ; CHECK-NEXT: [[DIV:%.*]] = udiv <2 x i8> [[X:%.*]], [[Y:%.*]] ; CHECK-NEXT: call void @use2xi8(<2 x i8> [[DIV]]) -; CHECK-NEXT: [[ROUNDXDOWNTOMULTIPLEOFY:%.*]] = mul <2 x i8> [[DIV]], [[Y]] -; CHECK-NEXT: [[REM:%.*]] = sub <2 x i8> [[X]], [[ROUNDXDOWNTOMULTIPLEOFY]] +; CHECK-NEXT: [[REM:%.*]] = urem <2 x i8> [[X]], [[Y]] ; CHECK-NEXT: ret <2 x i8> [[REM]] ; %div = udiv <2 x i8> %x, %y @@ -52,7 +50,7 @@ ; CHECK-NEXT: call void @use8(i8 [[DIV]]) ; CHECK-NEXT: [[ROUNDXDOWNTOMULTIPLEOFY:%.*]] = mul i8 [[DIV]], [[Y]] ; CHECK-NEXT: call void @use8(i8 [[ROUNDXDOWNTOMULTIPLEOFY]]) -; CHECK-NEXT: [[REM:%.*]] = sub i8 [[X]], [[ROUNDXDOWNTOMULTIPLEOFY]] +; CHECK-NEXT: [[REM:%.*]] = urem i8 [[X]], [[Y]] ; CHECK-NEXT: ret i8 [[REM]] ; %div = udiv i8 %x, %y @@ -72,8 +70,7 @@ ; CHECK-NEXT: [[Y:%.*]] = call i8 @gen8() ; CHECK-NEXT: [[DIV:%.*]] = udiv i8 [[X:%.*]], [[Y]] ; CHECK-NEXT: call void @use8(i8 [[DIV]]) -; CHECK-NEXT: [[ROUNDXDOWNTOMULTIPLEOFY:%.*]] = mul i8 [[Y]], [[DIV]] -; CHECK-NEXT: [[REM:%.*]] = sub i8 [[X]], [[ROUNDXDOWNTOMULTIPLEOFY]] +; CHECK-NEXT: [[REM:%.*]] = urem i8 [[X]], [[Y]] ; CHECK-NEXT: ret i8 [[REM]] ; %y = call i8 @gen8()