Index: lib/Transforms/InstCombine/InstCombineMulDivRem.cpp =================================================================== --- lib/Transforms/InstCombine/InstCombineMulDivRem.cpp +++ lib/Transforms/InstCombine/InstCombineMulDivRem.cpp @@ -1330,6 +1330,17 @@ return &I; } + // ((X % Z) + (Y % Z)) % Z -> (X + Y) % Z + Value *X, *Y, *Z; + if (match(Op1, m_Value(Z)) && + match(Op0, m_Add(m_SRem(m_Value(X), m_Specific(Z)), + m_SRem(m_Value(Y), m_Specific(Z))))) { + if (WillNotOverflowSignedAdd(X, Y, (Instruction *)&I)) { + return ReplaceInstUsesWith( + I, Builder->CreateSRem(Builder->CreateAdd(X, Y), Z)); + } + } + // If the sign bits of both operands are zero (i.e. we can prove they are // unsigned inputs), turn this into a urem. if (I.getType()->isIntegerTy()) { Index: test/Transforms/InstCombine/rem.ll =================================================================== --- test/Transforms/InstCombine/rem.ll +++ test/Transforms/InstCombine/rem.ll @@ -213,3 +213,40 @@ %R = urem <2 x i64> %V, ret <2 x i64> %R } + +define i32 @test21(i32 %x, i32 %y, i32 %n) { +; CHECK-LABEL: @test21( +; CHECK-NEXT: %1 = add i32 %x, %y +; CHECK-NEXT: %2 = srem i32 %1, %n +; CHECK-NEXT: ret i32 %2 + %mod = srem i32 %x, %n + %mod1 = srem i32 %y, %n + %add = add i32 %mod, %mod1 + %mod2 = srem i32 %add, %n + ret i32 %mod2 +} + +define i2 @test22(i2 %c) { +; CHECK-LABEL: @test22( +; CHECK-NEXT: %lhs = srem i2 -1, %c +; CHECK-NEXT: %rhs = srem i2 -2, %c +; CHECK-NEXT: %add = add i2 %lhs, %rhs +; CHECK-NEXT: %mod = srem i2 %add, %c +; CHECK-NEXT: ret i2 %mod + %lhs = srem i2 3, %c + %rhs = srem i2 2, %c + %add = add i2 %lhs, %rhs + %mod = srem i2 %add, %c + ret i2 %mod +} + +define i4 @test23(i4 %c) { +; CHECK-LABEL: @test23( +; CHECK-NEXT: %1 = srem i4 5, %c +; CHECK-NEXT: ret i4 %1 + %lhs = srem i4 3, %c + %rhs = srem i4 2, %c + %add = add i4 %lhs, %rhs + %mod = srem i4 %add, %c + ret i4 %mod +}