Index: llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp =================================================================== --- llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp +++ llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp @@ -3404,7 +3404,7 @@ } } - if (isa(SI)) { + if (FPMathOperator *SelectFPOp = dyn_cast(&SI)) { // TODO: Try to forward-propagate FMF from select arms to the select. // Canonicalize select of FP values where NaN and -0.0 are not valid as @@ -3419,6 +3419,32 @@ return replaceInstUsesWith( SI, Builder.CreateBinaryIntrinsic(Intrinsic::minnum, X, Y, &SI)); } + + Value *LdexpVal0, *LdexpVal1, *LdexpExp0, *LdexpExp1; + + // select c, (ldexp v, e0), (ldexp v, e1) -> ldexp v, (select c, e0, e1) + // select c, (ldexp v0, e), (ldexp v1, e) -> ldexp (select c, v0, v1), e + // + // select c, (ldexp v0, e0), (ldexp v1, e1) -> + // ldexp (select c, v0, v1), (select c, e0, e1) + if (match(TrueVal, m_OneUse(m_Intrinsic( + m_Value(LdexpVal0), m_Value(LdexpExp0)))) && + match(FalseVal, m_OneUse(m_Intrinsic( + m_Value(LdexpVal1), m_Value(LdexpExp1)))) && + LdexpExp0->getType() == LdexpExp1->getType()) { + FastMathFlags FMF = cast(TrueVal)->getFastMathFlags(); + FMF &= cast(FalseVal)->getFastMathFlags(); + FMF |= SelectFPOp->getFastMathFlags(); + IRBuilder<>::FastMathFlagGuard FMFG(Builder); + + Value *SelectVal = Builder.CreateSelect(CondVal, LdexpVal0, LdexpVal1); + Value *SelectExp = Builder.CreateSelect(CondVal, LdexpExp0, LdexpExp1); + + Builder.setFastMathFlags(FMF); + CallInst *NewLdexp = Builder.CreateIntrinsic( + TrueVal->getType(), Intrinsic::ldexp, {SelectVal, SelectExp}); + return replaceInstUsesWith(SI, NewLdexp); + } } // Fold selecting to fabs. Index: llvm/test/Transforms/InstCombine/ldexp.ll =================================================================== --- llvm/test/Transforms/InstCombine/ldexp.ll +++ llvm/test/Transforms/InstCombine/ldexp.ll @@ -9,9 +9,8 @@ define float @select_ldexp_f32_sameval_differentexp(i1 %cond, float %val, i32 %exp0, i32 %exp1) { ; CHECK-LABEL: define float @select_ldexp_f32_sameval_differentexp ; CHECK-SAME: (i1 [[COND:%.*]], float [[VAL:%.*]], i32 [[EXP0:%.*]], i32 [[EXP1:%.*]]) { -; CHECK-NEXT: [[LDEXP0:%.*]] = call float @llvm.ldexp.f32.i32(float [[VAL]], i32 [[EXP0]]) -; CHECK-NEXT: [[LDEXP1:%.*]] = call float @llvm.ldexp.f32.i32(float [[VAL]], i32 [[EXP1]]) -; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], float [[LDEXP0]], float [[LDEXP1]] +; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[COND]], i32 [[EXP0]], i32 [[EXP1]] +; CHECK-NEXT: [[SELECT:%.*]] = call float @llvm.ldexp.f32.i32(float [[VAL]], i32 [[TMP1]]) ; CHECK-NEXT: ret float [[SELECT]] ; %ldexp0 = call float @llvm.ldexp.f32.i32(float %val, i32 %exp0) @@ -23,9 +22,8 @@ define float @select_ldexp_f32_sameval_differentexp_selectflags(i1 %cond, float %val, i32 %exp0, i32 %exp1) { ; CHECK-LABEL: define float @select_ldexp_f32_sameval_differentexp_selectflags ; CHECK-SAME: (i1 [[COND:%.*]], float [[VAL:%.*]], i32 [[EXP0:%.*]], i32 [[EXP1:%.*]]) { -; CHECK-NEXT: [[LDEXP0:%.*]] = call float @llvm.ldexp.f32.i32(float [[VAL]], i32 [[EXP0]]) -; CHECK-NEXT: [[LDEXP1:%.*]] = call float @llvm.ldexp.f32.i32(float [[VAL]], i32 [[EXP1]]) -; CHECK-NEXT: [[SELECT:%.*]] = select nnan i1 [[COND]], float [[LDEXP0]], float [[LDEXP1]] +; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[COND]], i32 [[EXP0]], i32 [[EXP1]] +; CHECK-NEXT: [[SELECT:%.*]] = call nnan float @llvm.ldexp.f32.i32(float [[VAL]], i32 [[TMP1]]) ; CHECK-NEXT: ret float [[SELECT]] ; %ldexp0 = call float @llvm.ldexp.f32.i32(float %val, i32 %exp0) @@ -37,9 +35,8 @@ define float @select_ldexp_f32_sameval_differentexp_ldexp_intersect_flags(i1 %cond, float %val, i32 %exp0, i32 %exp1) { ; CHECK-LABEL: define float @select_ldexp_f32_sameval_differentexp_ldexp_intersect_flags ; CHECK-SAME: (i1 [[COND:%.*]], float [[VAL:%.*]], i32 [[EXP0:%.*]], i32 [[EXP1:%.*]]) { -; CHECK-NEXT: [[LDEXP0:%.*]] = call nnan nsz float @llvm.ldexp.f32.i32(float [[VAL]], i32 [[EXP0]]) -; CHECK-NEXT: [[LDEXP1:%.*]] = call nnan float @llvm.ldexp.f32.i32(float [[VAL]], i32 [[EXP1]]) -; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], float [[LDEXP0]], float [[LDEXP1]] +; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[COND]], i32 [[EXP0]], i32 [[EXP1]] +; CHECK-NEXT: [[SELECT:%.*]] = call nnan float @llvm.ldexp.f32.i32(float [[VAL]], i32 [[TMP1]]) ; CHECK-NEXT: ret float [[SELECT]] ; %ldexp0 = call nnan nsz float @llvm.ldexp.f32.i32(float %val, i32 %exp0) @@ -51,9 +48,8 @@ define float @select_ldexp_f32_sameval_differentexp_ldexp_intersect_flags_union_select(i1 %cond, float %val, i32 %exp0, i32 %exp1) { ; CHECK-LABEL: define float @select_ldexp_f32_sameval_differentexp_ldexp_intersect_flags_union_select ; CHECK-SAME: (i1 [[COND:%.*]], float [[VAL:%.*]], i32 [[EXP0:%.*]], i32 [[EXP1:%.*]]) { -; CHECK-NEXT: [[LDEXP0:%.*]] = call nnan nsz float @llvm.ldexp.f32.i32(float [[VAL]], i32 [[EXP0]]) -; CHECK-NEXT: [[LDEXP1:%.*]] = call nnan float @llvm.ldexp.f32.i32(float [[VAL]], i32 [[EXP1]]) -; CHECK-NEXT: [[SELECT:%.*]] = select ninf i1 [[COND]], float [[LDEXP0]], float [[LDEXP1]] +; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[COND]], i32 [[EXP0]], i32 [[EXP1]] +; CHECK-NEXT: [[SELECT:%.*]] = call nnan ninf float @llvm.ldexp.f32.i32(float [[VAL]], i32 [[TMP1]]) ; CHECK-NEXT: ret float [[SELECT]] ; %ldexp0 = call nnan nsz float @llvm.ldexp.f32.i32(float %val, i32 %exp0) @@ -98,9 +94,8 @@ define float @select_ldexp_f32_differentval_sameexp(i1 %cond, float %val0, float %val1, i32 %exp) { ; CHECK-LABEL: define float @select_ldexp_f32_differentval_sameexp ; CHECK-SAME: (i1 [[COND:%.*]], float [[VAL0:%.*]], float [[VAL1:%.*]], i32 [[EXP:%.*]]) { -; CHECK-NEXT: [[LDEXP0:%.*]] = call float @llvm.ldexp.f32.i32(float [[VAL0]], i32 [[EXP]]) -; CHECK-NEXT: [[LDEXP1:%.*]] = call float @llvm.ldexp.f32.i32(float [[VAL1]], i32 [[EXP]]) -; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], float [[LDEXP0]], float [[LDEXP1]] +; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[COND]], float [[VAL0]], float [[VAL1]] +; CHECK-NEXT: [[SELECT:%.*]] = call float @llvm.ldexp.f32.i32(float [[TMP1]], i32 [[EXP]]) ; CHECK-NEXT: ret float [[SELECT]] ; %ldexp0 = call float @llvm.ldexp.f32.i32(float %val0, i32 %exp) @@ -112,9 +107,8 @@ define float @select_ldexp_f32_differentval_sameexp_selectflags(i1 %cond, float %val0, float %val1, i32 %exp) { ; CHECK-LABEL: define float @select_ldexp_f32_differentval_sameexp_selectflags ; CHECK-SAME: (i1 [[COND:%.*]], float [[VAL0:%.*]], float [[VAL1:%.*]], i32 [[EXP:%.*]]) { -; CHECK-NEXT: [[LDEXP0:%.*]] = call float @llvm.ldexp.f32.i32(float [[VAL0]], i32 [[EXP]]) -; CHECK-NEXT: [[LDEXP1:%.*]] = call float @llvm.ldexp.f32.i32(float [[VAL1]], i32 [[EXP]]) -; CHECK-NEXT: [[SELECT:%.*]] = select nnan i1 [[COND]], float [[LDEXP0]], float [[LDEXP1]] +; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[COND]], float [[VAL0]], float [[VAL1]] +; CHECK-NEXT: [[SELECT:%.*]] = call nnan float @llvm.ldexp.f32.i32(float [[TMP1]], i32 [[EXP]]) ; CHECK-NEXT: ret float [[SELECT]] ; %ldexp0 = call float @llvm.ldexp.f32.i32(float %val0, i32 %exp) @@ -126,9 +120,8 @@ define float @select_ldexp_f32_differentval_sameexp_ldexp_intersect_flags(i1 %cond, float %val0, float %val1, i32 %exp) { ; CHECK-LABEL: define float @select_ldexp_f32_differentval_sameexp_ldexp_intersect_flags ; CHECK-SAME: (i1 [[COND:%.*]], float [[VAL0:%.*]], float [[VAL1:%.*]], i32 [[EXP:%.*]]) { -; CHECK-NEXT: [[LDEXP0:%.*]] = call nnan nsz float @llvm.ldexp.f32.i32(float [[VAL0]], i32 [[EXP]]) -; CHECK-NEXT: [[LDEXP1:%.*]] = call nnan float @llvm.ldexp.f32.i32(float [[VAL1]], i32 [[EXP]]) -; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], float [[LDEXP0]], float [[LDEXP1]] +; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[COND]], float [[VAL0]], float [[VAL1]] +; CHECK-NEXT: [[SELECT:%.*]] = call nnan float @llvm.ldexp.f32.i32(float [[TMP1]], i32 [[EXP]]) ; CHECK-NEXT: ret float [[SELECT]] ; %ldexp0 = call nnan nsz float @llvm.ldexp.f32.i32(float %val0, i32 %exp) @@ -140,9 +133,8 @@ define float @select_ldexp_f32_differentval_sameexp_ldexp_intersect_flags_unino_select(i1 %cond, float %val0, float %val1, i32 %exp) { ; CHECK-LABEL: define float @select_ldexp_f32_differentval_sameexp_ldexp_intersect_flags_unino_select ; CHECK-SAME: (i1 [[COND:%.*]], float [[VAL0:%.*]], float [[VAL1:%.*]], i32 [[EXP:%.*]]) { -; CHECK-NEXT: [[LDEXP0:%.*]] = call nnan nsz float @llvm.ldexp.f32.i32(float [[VAL0]], i32 [[EXP]]) -; CHECK-NEXT: [[LDEXP1:%.*]] = call nnan float @llvm.ldexp.f32.i32(float [[VAL1]], i32 [[EXP]]) -; CHECK-NEXT: [[SELECT:%.*]] = select ninf i1 [[COND]], float [[LDEXP0]], float [[LDEXP1]] +; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[COND]], float [[VAL0]], float [[VAL1]] +; CHECK-NEXT: [[SELECT:%.*]] = call nnan ninf float @llvm.ldexp.f32.i32(float [[TMP1]], i32 [[EXP]]) ; CHECK-NEXT: ret float [[SELECT]] ; %ldexp0 = call nnan nsz float @llvm.ldexp.f32.i32(float %val0, i32 %exp) @@ -186,9 +178,9 @@ define float @select_ldexp_f32_differentval_differentexp(i1 %cond, float %val0, float %val1, i32 %exp0, i32 %exp1) { ; CHECK-LABEL: define float @select_ldexp_f32_differentval_differentexp ; CHECK-SAME: (i1 [[COND:%.*]], float [[VAL0:%.*]], float [[VAL1:%.*]], i32 [[EXP0:%.*]], i32 [[EXP1:%.*]]) { -; CHECK-NEXT: [[LDEXP0:%.*]] = call float @llvm.ldexp.f32.i32(float [[VAL0]], i32 [[EXP0]]) -; CHECK-NEXT: [[LDEXP1:%.*]] = call float @llvm.ldexp.f32.i32(float [[VAL1]], i32 [[EXP1]]) -; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], float [[LDEXP0]], float [[LDEXP1]] +; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[COND]], float [[VAL0]], float [[VAL1]] +; CHECK-NEXT: [[TMP2:%.*]] = select i1 [[COND]], i32 [[EXP0]], i32 [[EXP1]] +; CHECK-NEXT: [[SELECT:%.*]] = call float @llvm.ldexp.f32.i32(float [[TMP1]], i32 [[TMP2]]) ; CHECK-NEXT: ret float [[SELECT]] ; %ldexp0 = call float @llvm.ldexp.f32.i32(float %val0, i32 %exp0) @@ -200,9 +192,8 @@ define <2 x float> @select_ldexp_v2f32_sameval_differentexp(<2 x i1> %cond, <2 x float> %val, <2 x i32> %exp0, <2 x i32> %exp1) { ; CHECK-LABEL: define <2 x float> @select_ldexp_v2f32_sameval_differentexp ; CHECK-SAME: (<2 x i1> [[COND:%.*]], <2 x float> [[VAL:%.*]], <2 x i32> [[EXP0:%.*]], <2 x i32> [[EXP1:%.*]]) { -; CHECK-NEXT: [[LDEXP0:%.*]] = call <2 x float> @llvm.ldexp.v2f32.v2i32(<2 x float> [[VAL]], <2 x i32> [[EXP0]]) -; CHECK-NEXT: [[LDEXP1:%.*]] = call <2 x float> @llvm.ldexp.v2f32.v2i32(<2 x float> [[VAL]], <2 x i32> [[EXP1]]) -; CHECK-NEXT: [[SELECT:%.*]] = select <2 x i1> [[COND]], <2 x float> [[LDEXP0]], <2 x float> [[LDEXP1]] +; CHECK-NEXT: [[TMP1:%.*]] = select <2 x i1> [[COND]], <2 x i32> [[EXP0]], <2 x i32> [[EXP1]] +; CHECK-NEXT: [[SELECT:%.*]] = call <2 x float> @llvm.ldexp.v2f32.v2i32(<2 x float> [[VAL]], <2 x i32> [[TMP1]]) ; CHECK-NEXT: ret <2 x float> [[SELECT]] ; %ldexp0 = call <2 x float> @llvm.ldexp.v2f32.v2i32(<2 x float> %val, <2 x i32> %exp0) @@ -214,9 +205,8 @@ define <2 x float> @select_ldexp_v2f32_differentval_sameexp(<2 x i1> %cond, <2 x float> %val0, <2 x float> %val1, <2 x i32> %exp) { ; CHECK-LABEL: define <2 x float> @select_ldexp_v2f32_differentval_sameexp ; CHECK-SAME: (<2 x i1> [[COND:%.*]], <2 x float> [[VAL0:%.*]], <2 x float> [[VAL1:%.*]], <2 x i32> [[EXP:%.*]]) { -; CHECK-NEXT: [[LDEXP0:%.*]] = call <2 x float> @llvm.ldexp.v2f32.v2i32(<2 x float> [[VAL0]], <2 x i32> [[EXP]]) -; CHECK-NEXT: [[LDEXP1:%.*]] = call <2 x float> @llvm.ldexp.v2f32.v2i32(<2 x float> [[VAL1]], <2 x i32> [[EXP]]) -; CHECK-NEXT: [[SELECT:%.*]] = select <2 x i1> [[COND]], <2 x float> [[LDEXP0]], <2 x float> [[LDEXP1]] +; CHECK-NEXT: [[TMP1:%.*]] = select <2 x i1> [[COND]], <2 x float> [[VAL0]], <2 x float> [[VAL1]] +; CHECK-NEXT: [[SELECT:%.*]] = call <2 x float> @llvm.ldexp.v2f32.v2i32(<2 x float> [[TMP1]], <2 x i32> [[EXP]]) ; CHECK-NEXT: ret <2 x float> [[SELECT]] ; %ldexp0 = call <2 x float> @llvm.ldexp.v2f32.v2i32(<2 x float> %val0, <2 x i32> %exp) @@ -228,9 +218,9 @@ define <2 x float> @select_ldexp_v2f32_differentval_differentexp(<2 x i1> %cond, <2 x float> %val0, <2 x float> %val1, <2 x i32> %exp0, <2 x i32> %exp1) { ; CHECK-LABEL: define <2 x float> @select_ldexp_v2f32_differentval_differentexp ; CHECK-SAME: (<2 x i1> [[COND:%.*]], <2 x float> [[VAL0:%.*]], <2 x float> [[VAL1:%.*]], <2 x i32> [[EXP0:%.*]], <2 x i32> [[EXP1:%.*]]) { -; CHECK-NEXT: [[LDEXP0:%.*]] = call <2 x float> @llvm.ldexp.v2f32.v2i32(<2 x float> [[VAL0]], <2 x i32> [[EXP0]]) -; CHECK-NEXT: [[LDEXP1:%.*]] = call <2 x float> @llvm.ldexp.v2f32.v2i32(<2 x float> [[VAL1]], <2 x i32> [[EXP1]]) -; CHECK-NEXT: [[SELECT:%.*]] = select <2 x i1> [[COND]], <2 x float> [[LDEXP0]], <2 x float> [[LDEXP1]] +; CHECK-NEXT: [[TMP1:%.*]] = select <2 x i1> [[COND]], <2 x float> [[VAL0]], <2 x float> [[VAL1]] +; CHECK-NEXT: [[TMP2:%.*]] = select <2 x i1> [[COND]], <2 x i32> [[EXP0]], <2 x i32> [[EXP1]] +; CHECK-NEXT: [[SELECT:%.*]] = call <2 x float> @llvm.ldexp.v2f32.v2i32(<2 x float> [[TMP1]], <2 x i32> [[TMP2]]) ; CHECK-NEXT: ret <2 x float> [[SELECT]] ; %ldexp0 = call <2 x float> @llvm.ldexp.v2f32.v2i32(<2 x float> %val0, <2 x i32> %exp0) @@ -242,9 +232,7 @@ define float @select_ldexp_f32_same(i1 %cond, float %val, i32 %exp) { ; CHECK-LABEL: define float @select_ldexp_f32_same ; CHECK-SAME: (i1 [[COND:%.*]], float [[VAL:%.*]], i32 [[EXP:%.*]]) { -; CHECK-NEXT: [[LDEXP0:%.*]] = call float @llvm.ldexp.f32.i32(float [[VAL]], i32 [[EXP]]) -; CHECK-NEXT: [[LDEXP1:%.*]] = call float @llvm.ldexp.f32.i32(float [[VAL]], i32 [[EXP]]) -; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], float [[LDEXP0]], float [[LDEXP1]] +; CHECK-NEXT: [[SELECT:%.*]] = call float @llvm.ldexp.f32.i32(float [[VAL]], i32 [[EXP]]) ; CHECK-NEXT: ret float [[SELECT]] ; %ldexp0 = call float @llvm.ldexp.f32.i32(float %val, i32 %exp)