Index: lib/Transforms/InstCombine/InstCombineMulDivRem.cpp =================================================================== --- lib/Transforms/InstCombine/InstCombineMulDivRem.cpp +++ lib/Transforms/InstCombine/InstCombineMulDivRem.cpp @@ -891,6 +891,7 @@ /// @brief Common integer divide transforms Instruction *InstCombiner::commonIDivTransforms(BinaryOperator &I) { Value *Op0 = I.getOperand(0), *Op1 = I.getOperand(1); + bool IsSigned = I.getOpcode() == Instruction::SDiv; // The RHS is known non-zero. if (Value *V = simplifyValueKnownNonZero(I.getOperand(1), *this, I)) { @@ -908,7 +909,6 @@ if (match(Op1, m_APInt(C2))) { Value *X; const APInt *C1; - bool IsSigned = I.getOpcode() == Instruction::SDiv; // (X / C1) / C2 -> X / (C1*C2) if ((IsSigned && match(LHS, m_SDiv(m_Value(X), m_APInt(C1)))) || @@ -1000,12 +1000,18 @@ // (X - (X rem Y)) / Y -> X / Y; usually originates as ((X / Y) * Y) / Y Value *X = nullptr, *Z = nullptr; - if (match(Op0, m_Sub(m_Value(X), m_Value(Z)))) { // (X - Z) / Y; Y = Op1 - bool isSigned = I.getOpcode() == Instruction::SDiv; - if ((isSigned && match(Z, m_SRem(m_Specific(X), m_Specific(Op1)))) || - (!isSigned && match(Z, m_URem(m_Specific(X), m_Specific(Op1))))) + if (match(Op0, m_Sub(m_Value(X), m_Value(Z)))) // (X - Z) / Y; Y = Op1 + if ((IsSigned && match(Z, m_SRem(m_Specific(X), m_Specific(Op1)))) || + (!IsSigned && match(Z, m_URem(m_Specific(X), m_Specific(Op1))))) return BinaryOperator::Create(I.getOpcode(), X, Op1); - } + + // (X << Y) / X -> 1 << Y + Value *Y = nullptr; + Constant *C = ConstantInt::get(Op1->getType(), 1); + if (IsSigned && match(Op0, m_NSWShl(m_Specific(Op1), m_Value(Y)))) + return BinaryOperator::CreateNSWShl(C, Y); + if (!IsSigned && match(Op0, m_NUWShl(m_Specific(Op1), m_Value(Y)))) + return BinaryOperator::CreateNUWShl(C, Y); return nullptr; } Index: test/Transforms/InstCombine/div-shift.ll =================================================================== --- test/Transforms/InstCombine/div-shift.ll +++ test/Transforms/InstCombine/div-shift.ll @@ -98,3 +98,107 @@ %y = udiv i32 %z, %divisor ret i32 %y } + +; (X << C1) / X -> 1 << C1 optimizations + +define i32 @t7(i32 %x) { +; CHECK-LABEL: @t7( +; CHECK: ret i32 4 +; + %shl = shl nsw i32 %x, 2 + %r = sdiv i32 %shl, %x + ret i32 %r +} + +; make sure the previous opt doesn't take place for wrapped shifts + +define i32 @t8(i32 %x) { +; CHECK-LABEL: @t8( +; CHECK: %shl = shl i32 %x, 2 +; CHECK-NEXT: %r = sdiv i32 %shl, %x +; CHECK-NEXT: ret i32 %r +; + %shl = shl i32 %x, 2 + %r = sdiv i32 %shl, %x + ret i32 %r +} + +define <2 x i32> @t9(<2 x i32> %x) { +; CHECK-LABEL: @t9( +; CHECK: ret <2 x i32> +; + %shl = shl nsw <2 x i32> %x, + %r = sdiv <2 x i32> %shl, %x + ret <2 x i32> %r +} + +define i32 @t10(i32 %x, i32 %y) { +; CHECK-LABEL: @t10( +; CHECK: %r = shl nsw i32 1, %y +; CHECK-NEXT: ret i32 %r +; + %shl = shl nsw i32 %x, %y + %r = sdiv i32 %shl, %x + ret i32 %r +} + +define <2 x i32> @t11(<2 x i32> %x, <2 x i32> %y) { +; CHECK-LABEL: @t11( +; CHECK: %r = shl nsw <2 x i32> , %y +; CHECK-NEXT: ret <2 x i32> %r +; + %shl = shl nsw <2 x i32> %x, %y + %r = sdiv <2 x i32> %shl, %x + ret <2 x i32> %r +} + +define i32 @t12(i32 %x) { +; CHECK-LABEL: @t12( +; CHECK: ret i32 4 +; + %shl = shl nuw i32 %x, 2 + %r = udiv i32 %shl, %x + ret i32 %r +} + +; make sure the previous opt doesn't take place for wrapped shifts + +define i32 @t13(i32 %x) { +; CHECK-LABEL: @t13( +; CHECK: %shl = shl i32 %x, 2 +; CHECK-NEXT: %r = udiv i32 %shl, %x +; CHECK-NEXT: ret i32 %r +; + %shl = shl i32 %x, 2 + %r = udiv i32 %shl, %x + ret i32 %r +} + +define <2 x i32> @t14(<2 x i32> %x) { +; CHECK-LABEL: @t14( +; CHECK: ret <2 x i32> +; + %shl = shl nuw <2 x i32> %x, + %r = udiv <2 x i32> %shl, %x + ret <2 x i32> %r +} + +define i32 @t15(i32 %x, i32 %y) { +; CHECK-LABEL: @t15( +; CHECK: %r = shl nuw i32 1, %y +; CHECK-NEXT: ret i32 %r +; + %shl = shl nuw i32 %x, %y + %r = udiv i32 %shl, %x + ret i32 %r +} + +define <2 x i32> @t16(<2 x i32> %x, <2 x i32> %y) { +; CHECK-LABEL: @t16( +; CHECK: %r = shl nuw <2 x i32> , %y +; CHECK-NEXT: ret <2 x i32> %r +; + %shl = shl nuw <2 x i32> %x, %y + %r = udiv <2 x i32> %shl, %x + ret <2 x i32> %r +}