diff options
-rw-r--r-- | llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp | 18 | ||||
-rw-r--r-- | llvm/test/Transforms/InstCombine/fptrunc.ll | 26 |
2 files changed, 33 insertions, 11 deletions
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp index 53bcaeb98b4..8d8b2f9f871 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp @@ -1636,6 +1636,24 @@ Instruction *InstCombiner::visitFPTrunc(FPTruncInst &FPT) { return BinaryOperator::CreateFNegFMF(InnerTrunc, Op); return UnaryOperator::CreateFNegFMF(InnerTrunc, Op); } + + // If we are truncating a select that has an extended operand, we can + // narrow the other operand and do the select as a narrow op. + Value *Cond, *X, *Y; + if (match(Op, m_Select(m_Value(Cond), m_FPExt(m_Value(X)), m_Value(Y))) && + X->getType() == Ty) { + // fptrunc (select Cond, (fpext X), Y --> select Cond, X, (fptrunc Y) + Value *NarrowY = Builder.CreateFPTrunc(Y, Ty); + Value *Sel = Builder.CreateSelect(Cond, X, NarrowY, "narrow.sel", Op); + return replaceInstUsesWith(FPT, Sel); + } + if (match(Op, m_Select(m_Value(Cond), m_Value(Y), m_FPExt(m_Value(X)))) && + X->getType() == Ty) { + // fptrunc (select Cond, Y, (fpext X) --> select Cond, (fptrunc Y), X + Value *NarrowY = Builder.CreateFPTrunc(Y, Ty); + Value *Sel = Builder.CreateSelect(Cond, NarrowY, X, "narrow.sel", Op); + return replaceInstUsesWith(FPT, Sel); + } } if (auto *II = dyn_cast<IntrinsicInst>(FPT.getOperand(0))) { diff --git a/llvm/test/Transforms/InstCombine/fptrunc.ll b/llvm/test/Transforms/InstCombine/fptrunc.ll index e1b2b1b9c53..e8038f4b846 100644 --- a/llvm/test/Transforms/InstCombine/fptrunc.ll +++ b/llvm/test/Transforms/InstCombine/fptrunc.ll @@ -51,10 +51,9 @@ define <2 x half> @fmul_constant_op1(<2 x float> %x) { define float @fptrunc_select_true_val(float %x, double %y, i1 %cond) { ; CHECK-LABEL: @fptrunc_select_true_val( -; CHECK-NEXT: [[E:%.*]] = fpext float [[X:%.*]] to double -; CHECK-NEXT: [[SEL:%.*]] = select fast i1 [[COND:%.*]], double [[Y:%.*]], double [[E]] -; CHECK-NEXT: [[R:%.*]] = fptrunc double [[SEL]] to float -; CHECK-NEXT: ret float [[R]] +; CHECK-NEXT: [[TMP1:%.*]] = fptrunc double [[Y:%.*]] to float +; CHECK-NEXT: [[NARROW_SEL:%.*]] = select fast i1 [[COND:%.*]], float [[TMP1]], float [[X:%.*]] +; CHECK-NEXT: ret float [[NARROW_SEL]] ; %e = fpext float %x to double %sel = select fast i1 %cond, double %y, double %e @@ -64,10 +63,9 @@ define float @fptrunc_select_true_val(float %x, double %y, i1 %cond) { define <2 x float> @fptrunc_select_false_val(<2 x float> %x, <2 x double> %y, <2 x i1> %cond) { ; CHECK-LABEL: @fptrunc_select_false_val( -; CHECK-NEXT: [[E:%.*]] = fpext <2 x float> [[X:%.*]] to <2 x double> -; CHECK-NEXT: [[SEL:%.*]] = select nnan <2 x i1> [[COND:%.*]], <2 x double> [[E]], <2 x double> [[Y:%.*]] -; CHECK-NEXT: [[R:%.*]] = fptrunc <2 x double> [[SEL]] to <2 x float> -; CHECK-NEXT: ret <2 x float> [[R]] +; CHECK-NEXT: [[TMP1:%.*]] = fptrunc <2 x double> [[Y:%.*]] to <2 x float> +; CHECK-NEXT: [[NARROW_SEL:%.*]] = select nnan <2 x i1> [[COND:%.*]], <2 x float> [[X:%.*]], <2 x float> [[TMP1]] +; CHECK-NEXT: ret <2 x float> [[NARROW_SEL]] ; %e = fpext <2 x float> %x to <2 x double> %sel = select nnan <2 x i1> %cond, <2 x double> %e, <2 x double> %y @@ -81,9 +79,9 @@ define half @fptrunc_select_true_val_extra_use(half %x, float %y, i1 %cond) { ; CHECK-LABEL: @fptrunc_select_true_val_extra_use( ; CHECK-NEXT: [[E:%.*]] = fpext half [[X:%.*]] to float ; CHECK-NEXT: call void @use(float [[E]]) -; CHECK-NEXT: [[SEL:%.*]] = select ninf i1 [[COND:%.*]], float [[Y:%.*]], float [[E]] -; CHECK-NEXT: [[R:%.*]] = fptrunc float [[SEL]] to half -; CHECK-NEXT: ret half [[R]] +; CHECK-NEXT: [[TMP1:%.*]] = fptrunc float [[Y:%.*]] to half +; CHECK-NEXT: [[NARROW_SEL:%.*]] = select ninf i1 [[COND:%.*]], half [[TMP1]], half [[X]] +; CHECK-NEXT: ret half [[NARROW_SEL]] ; %e = fpext half %x to float call void @use(float %e) @@ -92,6 +90,8 @@ define half @fptrunc_select_true_val_extra_use(half %x, float %y, i1 %cond) { ret half %r } +; Negative test - this would require an extra instruction. + define half @fptrunc_select_true_val_extra_use_2(half %x, float %y, i1 %cond) { ; CHECK-LABEL: @fptrunc_select_true_val_extra_use_2( ; CHECK-NEXT: [[E:%.*]] = fpext half [[X:%.*]] to float @@ -107,6 +107,8 @@ define half @fptrunc_select_true_val_extra_use_2(half %x, float %y, i1 %cond) { ret half %r } +; Negative test - the extend must be from the same source type as the result of the trunc. + define float @fptrunc_select_true_val_type_mismatch(half %x, double %y, i1 %cond) { ; CHECK-LABEL: @fptrunc_select_true_val_type_mismatch( ; CHECK-NEXT: [[E:%.*]] = fpext half [[X:%.*]] to double @@ -120,6 +122,8 @@ define float @fptrunc_select_true_val_type_mismatch(half %x, double %y, i1 %cond ret float %r } +; Negative test - but given enough FMF, should this be folded? + define float @fptrunc_select_true_val_type_mismatch_fast(half %x, double %y, i1 %cond) { ; CHECK-LABEL: @fptrunc_select_true_val_type_mismatch_fast( ; CHECK-NEXT: [[E:%.*]] = fpext half [[X:%.*]] to double |