Index: llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp =================================================================== --- llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp +++ llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp @@ -1729,6 +1729,16 @@ return CastInst::CreateFPCast(ExactResult, Ty); } } + } else if (auto *UO = dyn_cast(FPT.getOperand(0)); + UO && UO->hasOneUse()) { + switch (UO->getOpcode()) { + case Instruction::FNeg: { + Value *TruncSrc = Builder.CreateFPTrunc(UO->getOperand(0), Ty); + return UnaryOperator::CreateFNegFMF(TruncSrc, UO); + } + default: + break; + } } // (fptrunc (fneg x)) -> (fneg (fptrunc x)) Index: llvm/test/Transforms/InstCombine/double-float-shrink-2.ll =================================================================== --- llvm/test/Transforms/InstCombine/double-float-shrink-2.ll +++ llvm/test/Transforms/InstCombine/double-float-shrink-2.ll @@ -737,4 +737,51 @@ ret float %F } +define float @test_shrink_intrin_fneg_double_src(double %D) { +; CHECK-LABEL: @test_shrink_intrin_fneg_double_src( +; CHECK-NEXT: [[TMP1:%.*]] = fptrunc double [[D:%.*]] to float +; CHECK-NEXT: [[F:%.*]] = fneg float [[TMP1]] +; CHECK-NEXT: ret float [[F]] +; + %E = fneg double %D + %F = fptrunc double %E to float + ret float %F +} + +define <2 x float> @test_shrink_intrin_fneg_v2f64_src(<2 x double> %D) { +; CHECK-LABEL: @test_shrink_intrin_fneg_v2f64_src( +; CHECK-NEXT: [[TMP1:%.*]] = fptrunc <2 x double> [[D:%.*]] to <2 x float> +; CHECK-NEXT: [[F:%.*]] = fneg <2 x float> [[TMP1]] +; CHECK-NEXT: ret <2 x float> [[F]] +; + %E = fneg <2 x double> %D + %F = fptrunc <2 x double> %E to <2 x float> + ret <2 x float> %F +} + +; Make sure fast math flags are preserved +define float @test_shrink_intrin_fneg_nnan_double_src(double %D) { +; CHECK-LABEL: @test_shrink_intrin_fneg_nnan_double_src( +; CHECK-NEXT: [[TMP1:%.*]] = fptrunc double [[D:%.*]] to float +; CHECK-NEXT: [[F:%.*]] = fneg nnan float [[TMP1]] +; CHECK-NEXT: ret float [[F]] +; + %E = fneg nnan double %D + %F = fptrunc double %E to float + ret float %F +} + +define float @test_shrink_intrin_fneg_double_src_multi_use(double %D, ptr %ptr) { +; CHECK-LABEL: @test_shrink_intrin_fneg_double_src_multi_use( +; CHECK-NEXT: [[E:%.*]] = fneg double [[D:%.*]] +; CHECK-NEXT: store double [[E]], ptr [[PTR:%.*]], align 8 +; CHECK-NEXT: [[F:%.*]] = fptrunc double [[E]] to float +; CHECK-NEXT: ret float [[F]] +; + %E = fneg double %D + store double %E, ptr %ptr + %F = fptrunc double %E to float + ret float %F +} + ; DBG-VALID: CheckModuleDebugify: PASS