Index: llvm/trunk/lib/Transforms/InstCombine/InstCombineSelect.cpp =================================================================== --- llvm/trunk/lib/Transforms/InstCombine/InstCombineSelect.cpp +++ llvm/trunk/lib/Transforms/InstCombine/InstCombineSelect.cpp @@ -333,6 +333,18 @@ TI->getType()); } + // Cond ? -X : -Y --> -(Cond ? X : Y) + Value *X, *Y; + if (match(TI, m_FNeg(m_Value(X))) && match(FI, m_FNeg(m_Value(Y))) && + (TI->hasOneUse() || FI->hasOneUse())) { + Value *NewSel = Builder.CreateSelect(Cond, X, Y, SI.getName() + ".v", &SI); + // TODO: Remove the hack for the binop form when the unary op is optimized + // properly with all IR passes. + if (TI->getOpcode() != Instruction::FNeg) + return BinaryOperator::CreateFNegFMF(NewSel, cast(TI)); + return UnaryOperator::CreateFNeg(NewSel); + } + // Only handle binary operators (including two-operand getelementptr) with // one-use here. As with the cast case above, it may be possible to relax the // one-use constraint, but that needs be examined carefully since it may not Index: llvm/trunk/test/Transforms/InstCombine/fneg.ll =================================================================== --- llvm/trunk/test/Transforms/InstCombine/fneg.ll +++ llvm/trunk/test/Transforms/InstCombine/fneg.ll @@ -161,9 +161,8 @@ define <2 x double> @fneg_fneg_sel(<2 x double> %x, <2 x double> %y, i1 %cond) { ; CHECK-LABEL: @fneg_fneg_sel( -; CHECK-NEXT: [[N1:%.*]] = fneg <2 x double> [[X:%.*]] -; CHECK-NEXT: [[N2:%.*]] = fneg <2 x double> [[Y:%.*]] -; CHECK-NEXT: [[SEL:%.*]] = select i1 [[COND:%.*]], <2 x double> [[N1]], <2 x double> [[N2]] +; CHECK-NEXT: [[SEL_V:%.*]] = select i1 [[COND:%.*]], <2 x double> [[X:%.*]], <2 x double> [[Y:%.*]] +; CHECK-NEXT: [[SEL:%.*]] = fneg <2 x double> [[SEL_V]] ; CHECK-NEXT: ret <2 x double> [[SEL]] ; %n1 = fneg <2 x double> %x @@ -178,8 +177,8 @@ ; CHECK-LABEL: @fneg_fneg_sel_extra_use1( ; CHECK-NEXT: [[N1:%.*]] = fneg float [[X:%.*]] ; CHECK-NEXT: call void @use(float [[N1]]) -; CHECK-NEXT: [[N2:%.*]] = fneg float [[Y:%.*]] -; CHECK-NEXT: [[SEL:%.*]] = select i1 [[COND:%.*]], float [[N1]], float [[N2]] +; CHECK-NEXT: [[SEL_V:%.*]] = select i1 [[COND:%.*]], float [[X]], float [[Y:%.*]] +; CHECK-NEXT: [[SEL:%.*]] = fneg float [[SEL_V]] ; CHECK-NEXT: ret float [[SEL]] ; %n1 = fneg float %x @@ -191,10 +190,10 @@ define float @fneg_fneg_sel_extra_use2(float %x, float %y, i1 %cond) { ; CHECK-LABEL: @fneg_fneg_sel_extra_use2( -; CHECK-NEXT: [[N1:%.*]] = fneg float [[X:%.*]] ; CHECK-NEXT: [[N2:%.*]] = fneg float [[Y:%.*]] ; CHECK-NEXT: call void @use(float [[N2]]) -; CHECK-NEXT: [[SEL:%.*]] = select i1 [[COND:%.*]], float [[N1]], float [[N2]] +; CHECK-NEXT: [[SEL_V:%.*]] = select i1 [[COND:%.*]], float [[X:%.*]], float [[Y]] +; CHECK-NEXT: [[SEL:%.*]] = fneg float [[SEL_V]] ; CHECK-NEXT: ret float [[SEL]] ; %n1 = fneg float %x @@ -210,8 +209,8 @@ ; CHECK-LABEL: @fsub_fsub_sel_extra_use1( ; CHECK-NEXT: [[N1:%.*]] = fsub float -0.000000e+00, [[X:%.*]] ; CHECK-NEXT: call void @use(float [[N1]]) -; CHECK-NEXT: [[N2:%.*]] = fsub float -0.000000e+00, [[Y:%.*]] -; CHECK-NEXT: [[SEL:%.*]] = select i1 [[COND:%.*]], float [[N1]], float [[N2]] +; CHECK-NEXT: [[SEL_V:%.*]] = select i1 [[COND:%.*]], float [[X]], float [[Y:%.*]] +; CHECK-NEXT: [[SEL:%.*]] = fsub float -0.000000e+00, [[SEL_V]] ; CHECK-NEXT: ret float [[SEL]] ; %n1 = fsub float -0.0, %x