Index: llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp =================================================================== --- llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp +++ llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp @@ -1485,6 +1485,14 @@ } } + // If the divisor is a select-of-constants, try to constant fold all rem ops: + // C % (select Cond, TrueC, FalseC) --> select Cond, (C % TrueC), (C % FalseC) + if (match(Op0, m_ImmConstant()) && + match(Op1, m_Select(m_Value(), m_ImmConstant(), m_ImmConstant()))) { + if (Instruction *R = FoldOpIntoSelect(I, cast(Op1))) + return R; + } + return nullptr; } Index: llvm/test/Transforms/InstCombine/rem.ll =================================================================== --- llvm/test/Transforms/InstCombine/rem.ll +++ llvm/test/Transforms/InstCombine/rem.ll @@ -777,8 +777,7 @@ define i32 @srem_constant_dividend_select_of_constants_divisor(i1 %b) { ; CHECK-LABEL: @srem_constant_dividend_select_of_constants_divisor( -; CHECK-NEXT: [[S:%.*]] = select i1 [[B:%.*]], i32 12, i32 -3 -; CHECK-NEXT: [[R:%.*]] = srem i32 42, [[S]] +; CHECK-NEXT: [[R:%.*]] = select i1 [[B:%.*]], i32 6, i32 0 ; CHECK-NEXT: ret i32 [[R]] ; %s = select i1 %b, i32 12, i32 -3 @@ -786,6 +785,8 @@ ret i32 %r } +; TODO: srem should still be replaced by select. + define i32 @srem_constant_dividend_select_of_constants_divisor_use(i1 %b) { ; CHECK-LABEL: @srem_constant_dividend_select_of_constants_divisor_use( ; CHECK-NEXT: [[S:%.*]] = select i1 [[B:%.*]], i32 12, i32 -3 @@ -799,6 +800,8 @@ ret i32 %r } +; negative test - not safe to speculate rem with variable divisor + define i32 @srem_constant_dividend_select_divisor1(i1 %b, i32 %x) { ; CHECK-LABEL: @srem_constant_dividend_select_divisor1( ; CHECK-NEXT: [[S:%.*]] = select i1 [[B:%.*]], i32 [[X:%.*]], i32 -3 @@ -810,6 +813,8 @@ ret i32 %r } +; negative test - not safe to speculate rem with variable divisor + define i32 @srem_constant_dividend_select_divisor2(i1 %b, i32 %x) { ; CHECK-LABEL: @srem_constant_dividend_select_divisor2( ; CHECK-NEXT: [[S:%.*]] = select i1 [[B:%.*]], i32 12, i32 [[X:%.*]] @@ -823,8 +828,7 @@ define <2 x i8> @srem_constant_dividend_select_of_constants_divisor_vec(i1 %b) { ; CHECK-LABEL: @srem_constant_dividend_select_of_constants_divisor_vec( -; CHECK-NEXT: [[S:%.*]] = select i1 [[B:%.*]], <2 x i8> , <2 x i8> -; CHECK-NEXT: [[R:%.*]] = srem <2 x i8> , [[S]] +; CHECK-NEXT: [[R:%.*]] = select i1 [[B:%.*]], <2 x i8> , <2 x i8> ; CHECK-NEXT: ret <2 x i8> [[R]] ; %s = select i1 %b, <2 x i8> , <2 x i8> @@ -832,6 +836,8 @@ ret <2 x i8> %r } +; Rem-by-0 element is immediate UB, so select is simplified. + define <2 x i8> @srem_constant_dividend_select_of_constants_divisor_vec_ub1(i1 %b) { ; CHECK-LABEL: @srem_constant_dividend_select_of_constants_divisor_vec_ub1( ; CHECK-NEXT: ret <2 x i8> @@ -841,10 +847,11 @@ ret <2 x i8> %r } +; SMIN % -1 element is poison. + define <2 x i8> @srem_constant_dividend_select_of_constants_divisor_vec_ub2(i1 %b) { ; CHECK-LABEL: @srem_constant_dividend_select_of_constants_divisor_vec_ub2( -; CHECK-NEXT: [[S:%.*]] = select i1 [[B:%.*]], <2 x i8> , <2 x i8> -; CHECK-NEXT: [[R:%.*]] = srem <2 x i8> , [[S]] +; CHECK-NEXT: [[R:%.*]] = select i1 [[B:%.*]], <2 x i8> , <2 x i8> ; CHECK-NEXT: ret <2 x i8> [[R]] ; %s = select i1 %b, <2 x i8> , <2 x i8> @@ -852,6 +859,8 @@ ret <2 x i8> %r } +; negative test - must have constant dividend + define i32 @srem_select_of_constants_divisor(i1 %b, i32 %x) { ; CHECK-LABEL: @srem_select_of_constants_divisor( ; CHECK-NEXT: [[S:%.*]] = select i1 [[B:%.*]], i32 12, i32 -3 @@ -865,8 +874,7 @@ define i32 @urem_constant_dividend_select_of_constants_divisor(i1 %b) { ; CHECK-LABEL: @urem_constant_dividend_select_of_constants_divisor( -; CHECK-NEXT: [[S:%.*]] = select i1 [[B:%.*]], i32 12, i32 -3 -; CHECK-NEXT: [[R:%.*]] = urem i32 42, [[S]] +; CHECK-NEXT: [[R:%.*]] = select i1 [[B:%.*]], i32 6, i32 42 ; CHECK-NEXT: ret i32 [[R]] ; %s = select i1 %b, i32 12, i32 -3 @@ -874,6 +882,8 @@ ret i32 %r } +; TODO: urem should still be replaced by select. + define i32 @urem_constant_dividend_select_of_constants_divisor_use(i1 %b) { ; CHECK-LABEL: @urem_constant_dividend_select_of_constants_divisor_use( ; CHECK-NEXT: [[S:%.*]] = select i1 [[B:%.*]], i32 12, i32 -3 @@ -887,6 +897,8 @@ ret i32 %r } +; negative test - not safe to speculate rem with variable divisor + define i32 @urem_constant_dividend_select_divisor1(i1 %b, i32 %x) { ; CHECK-LABEL: @urem_constant_dividend_select_divisor1( ; CHECK-NEXT: [[S:%.*]] = select i1 [[B:%.*]], i32 [[X:%.*]], i32 -3 @@ -898,6 +910,8 @@ ret i32 %r } +; negative test - not safe to speculate rem with variable divisor + define i32 @urem_constant_dividend_select_divisor2(i1 %b, i32 %x) { ; CHECK-LABEL: @urem_constant_dividend_select_divisor2( ; CHECK-NEXT: [[S:%.*]] = select i1 [[B:%.*]], i32 12, i32 [[X:%.*]] @@ -911,8 +925,7 @@ define <2 x i8> @urem_constant_dividend_select_of_constants_divisor_vec(i1 %b) { ; CHECK-LABEL: @urem_constant_dividend_select_of_constants_divisor_vec( -; CHECK-NEXT: [[S:%.*]] = select i1 [[B:%.*]], <2 x i8> , <2 x i8> -; CHECK-NEXT: [[R:%.*]] = urem <2 x i8> , [[S]] +; CHECK-NEXT: [[R:%.*]] = select i1 [[B:%.*]], <2 x i8> , <2 x i8> ; CHECK-NEXT: ret <2 x i8> [[R]] ; %s = select i1 %b, <2 x i8> , <2 x i8> @@ -920,6 +933,8 @@ ret <2 x i8> %r } +; Rem-by-0 element is immediate UB, so select is simplified. + define <2 x i8> @urem_constant_dividend_select_of_constants_divisor_vec_ub1(i1 %b) { ; CHECK-LABEL: @urem_constant_dividend_select_of_constants_divisor_vec_ub1( ; CHECK-NEXT: ret <2 x i8> @@ -929,10 +944,11 @@ ret <2 x i8> %r } +; There's no unsigned equivalent to "SMIN % -1", so this is just the usual constant folding. + define <2 x i8> @urem_constant_dividend_select_of_constants_divisor_vec_ub2(i1 %b) { ; CHECK-LABEL: @urem_constant_dividend_select_of_constants_divisor_vec_ub2( -; CHECK-NEXT: [[S:%.*]] = select i1 [[B:%.*]], <2 x i8> , <2 x i8> -; CHECK-NEXT: [[R:%.*]] = urem <2 x i8> , [[S]] +; CHECK-NEXT: [[R:%.*]] = select i1 [[B:%.*]], <2 x i8> , <2 x i8> ; CHECK-NEXT: ret <2 x i8> [[R]] ; %s = select i1 %b, <2 x i8> , <2 x i8> @@ -940,6 +956,8 @@ ret <2 x i8> %r } +; negative test - must have constant dividend + define i32 @urem_select_of_constants_divisor(i1 %b, i32 %x) { ; CHECK-LABEL: @urem_select_of_constants_divisor( ; CHECK-NEXT: [[S:%.*]] = select i1 [[B:%.*]], i32 12, i32 -3