diff --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp --- a/llvm/lib/Analysis/InstructionSimplify.cpp +++ b/llvm/lib/Analysis/InstructionSimplify.cpp @@ -1228,6 +1228,24 @@ match(Op0, m_NUWShl(m_Specific(Op1), m_Value()))))) return Constant::getNullValue(Op0->getType()); + // (X << S1) % (X << S2) + // (S1 >= S2) ? -> 0 : -> (X << S1) + Value *ShiftX; + ConstantInt *S1, *S2; + if (match(Op0, m_Shl(m_Value(ShiftX), m_ConstantInt(S1))) && + match(Op1, m_Shl(m_Deferred(ShiftX), m_ConstantInt(S2)))) { + auto Shl0 = cast(Op0); + if (S1 >= S2 && + ((Opcode == Instruction::SRem && Q.IIQ.hasNoSignedWrap(Shl0)) || + (Opcode == Instruction::URem && Q.IIQ.hasNoUnsignedWrap(Shl0)))) + return Constant::getNullValue(Shl0->getType()); + + auto Shl1 = cast(Op1); + if ((Opcode == Instruction::SRem && Q.IIQ.hasNoSignedWrap(Shl1)) || + (Opcode == Instruction::URem && Q.IIQ.hasNoUnsignedWrap(Shl1))) + return Op0; + } + // If the operation is with the result of a select instruction, check whether // operating on either branch of the select always yields the same value. if (isa(Op0) || isa(Op1)) diff --git a/llvm/test/Transforms/InstSimplify/rem.ll b/llvm/test/Transforms/InstSimplify/rem.ll --- a/llvm/test/Transforms/InstSimplify/rem.ll +++ b/llvm/test/Transforms/InstSimplify/rem.ll @@ -488,3 +488,129 @@ %mod = urem i8 %mul, %y ret i8 %mod } + +define i8 @urem_shl(i8 %x){ +; CHECK-LABEL: @urem_shl( +; CHECK-NEXT: ret i8 0 +; + %x1 = shl i8 %x, 1 + %x2 = shl nuw i8 %x, 2 + %1 = urem i8 %x2, %x1 + ret i8 %1 +} + +define i8 @urem_shl_2(i8 %x){ +; CHECK-LABEL: @urem_shl_2( +; CHECK-NEXT: [[X1:%.*]] = shl i8 [[X:%.*]], 1 +; CHECK-NEXT: ret i8 [[X1]] +; + %x1 = shl i8 %x, 1 + %x2 = shl nuw i8 %x, 2 + %1 = urem i8 %x1, %x2 + ret i8 %1 +} + +define i8 @srem_shl(i8 %x){ +; CHECK-LABEL: @srem_shl( +; CHECK-NEXT: ret i8 0 +; + %x1 = shl i8 %x, 1 + %x2 = shl nsw i8 %x, 2 + %1 = srem i8 %x2, %x1 + ret i8 %1 +} + +define i8 @srem_shl_2(i8 %x){ +; CHECK-LABEL: @srem_shl_2( +; CHECK-NEXT: [[X1:%.*]] = shl i8 [[X:%.*]], 1 +; CHECK-NEXT: ret i8 [[X1]] +; + %x1 = shl i8 %x, 1 + %x2 = shl nsw i8 %x, 2 + %1 = srem i8 %x1, %x2 + ret i8 %1 +} + +; Cannot simplify to ret 0 when larger shift is missing nuw with urem +define i8 @neg_urem_shl_no_nuw(i8 %x){ +; CHECK-LABEL: @neg_urem_shl_no_nuw( +; CHECK-NEXT: [[X1:%.*]] = shl i8 [[X:%.*]], 1 +; CHECK-NEXT: [[X2:%.*]] = shl i8 [[X]], 2 +; CHECK-NEXT: [[TMP1:%.*]] = urem i8 [[X2]], [[X1]] +; CHECK-NEXT: ret i8 [[TMP1]] +; + %x1 = shl i8 %x, 1 + %x2 = shl i8 %x, 2 + %1 = urem i8 %x2, %x1 + ret i8 %1 +} + +; Cannot simplify to ret %x1 when larger shift is missing nuw with urem +define i8 @neg_urem_shl_no_nuw_2(i8 %x){ +; CHECK-LABEL: @neg_urem_shl_no_nuw_2( +; CHECK-NEXT: [[X1:%.*]] = shl i8 [[X:%.*]], 1 +; CHECK-NEXT: [[X2:%.*]] = shl i8 [[X]], 2 +; CHECK-NEXT: [[TMP1:%.*]] = urem i8 [[X1]], [[X2]] +; CHECK-NEXT: ret i8 [[TMP1]] +; + %x1 = shl i8 %x, 1 + %x2 = shl i8 %x, 2 + %1 = urem i8 %x1, %x2 + ret i8 %1 +} + +; Cannot simplify to ret 0 when larger shift is missing nuw with urem; ignore nsw +define i8 @neg_urem_shl_no_nuw_3(i8 %x){ +; CHECK-LABEL: @neg_urem_shl_no_nuw_3( +; CHECK-NEXT: [[X1:%.*]] = shl i8 [[X:%.*]], 1 +; CHECK-NEXT: [[X2:%.*]] = shl nsw i8 [[X]], 2 +; CHECK-NEXT: [[TMP1:%.*]] = urem i8 [[X2]], [[X1]] +; CHECK-NEXT: ret i8 [[TMP1]] +; + %x1 = shl i8 %x, 1 + %x2 = shl nsw i8 %x, 2 + %1 = urem i8 %x2, %x1 + ret i8 %1 +} + +; Cannot simplify to ret 0 when larger shift is missing nsw with srem +define i8 @neg_srem_shl_no_nsw(i8 %x){ +; CHECK-LABEL: @neg_srem_shl_no_nsw( +; CHECK-NEXT: [[X1:%.*]] = shl i8 [[X:%.*]], 1 +; CHECK-NEXT: [[X2:%.*]] = shl i8 [[X]], 2 +; CHECK-NEXT: [[TMP1:%.*]] = srem i8 [[X2]], [[X1]] +; CHECK-NEXT: ret i8 [[TMP1]] +; + %x1 = shl i8 %x, 1 + %x2 = shl i8 %x, 2 + %1 = srem i8 %x2, %x1 + ret i8 %1 +} + +; Cannot simplify to ret %x1 when larger shift is missing nsw with srem +define i8 @neg_srem_shl_no_nsw_2(i8 %x){ +; CHECK-LABEL: @neg_srem_shl_no_nsw_2( +; CHECK-NEXT: [[X1:%.*]] = shl i8 [[X:%.*]], 1 +; CHECK-NEXT: [[X2:%.*]] = shl i8 [[X]], 2 +; CHECK-NEXT: [[TMP1:%.*]] = srem i8 [[X1]], [[X2]] +; CHECK-NEXT: ret i8 [[TMP1]] +; + %x1 = shl i8 %x, 1 + %x2 = shl i8 %x, 2 + %1 = srem i8 %x1, %x2 + ret i8 %1 +} + +; Cannot simplify to ret 0 when larger shift is missing nsw with srem; ignore nuw +define i8 @neg_srem_shl_no_nsw_3(i8 %x){ +; CHECK-LABEL: @neg_srem_shl_no_nsw_3( +; CHECK-NEXT: [[X1:%.*]] = shl i8 [[X:%.*]], 1 +; CHECK-NEXT: [[X2:%.*]] = shl nuw i8 [[X]], 2 +; CHECK-NEXT: [[TMP1:%.*]] = srem i8 [[X2]], [[X1]] +; CHECK-NEXT: ret i8 [[TMP1]] +; + %x1 = shl i8 %x, 1 + %x2 = shl nuw i8 %x, 2 + %1 = srem i8 %x2, %x1 + ret i8 %1 +}