Index: llvm/include/llvm/IR/PatternMatch.h =================================================================== --- llvm/include/llvm/IR/PatternMatch.h +++ llvm/include/llvm/IR/PatternMatch.h @@ -667,18 +667,26 @@ FNeg_match(const Op_t &Op) : X(Op) {} template bool match(OpTy *V) { auto *FPMO = dyn_cast(V); - if (!FPMO || FPMO->getOpcode() != Instruction::FSub) - return false; - if (FPMO->hasNoSignedZeros()) { - // With 'nsz', any zero goes. - if (!cstfp_pred_ty().match(FPMO->getOperand(0))) - return false; - } else { - // Without 'nsz', we need fsub -0.0, X exactly. - if (!cstfp_pred_ty().match(FPMO->getOperand(0))) - return false; + if (!FPMO) return false; + + if (FPMO->getOpcode() == Instruction::FNeg) + return X.match(FPMO->getOperand(0)); + + if (FPMO->getOpcode() == Instruction::FSub) { + if (FPMO->hasNoSignedZeros()) { + // With 'nsz', any zero goes. + if (!cstfp_pred_ty().match(FPMO->getOperand(0))) + return false; + } else { + // Without 'nsz', we need fsub -0.0, X exactly. + if (!cstfp_pred_ty().match(FPMO->getOperand(0))) + return false; + } + + return X.match(FPMO->getOperand(1)); } - return X.match(FPMO->getOperand(1)); + + return false; } }; Index: llvm/unittests/IR/PatternMatch.cpp =================================================================== --- llvm/unittests/IR/PatternMatch.cpp +++ llvm/unittests/IR/PatternMatch.cpp @@ -589,6 +589,35 @@ EXPECT_TRUE(match(VectorZeroUndef, m_AnyZeroFP())); } +TEST_F(PatternMatchTest, FloatingPointFNeg) { + Type *FltTy = IRB.getFloatTy(); + Value *O = ConstantFP::get(FltTy, 1.0); + Value *Z = ConstantFP::get(FltTy, 0.0); + Value *NZ = ConstantFP::get(FltTy, -0.0); + Value *V = IRB.CreateFNeg(O); + Value *V1 = IRB.CreateFSub(NZ, O); + Value *V2 = IRB.CreateFSub(Z, O); + Value *V3 = IRB.CreateFAdd(NZ, O); + Value *Match; + + // Test FNeg(1.0) + EXPECT_TRUE(match(V, m_FNeg(m_Value(Match)))); + EXPECT_EQ(O, Match); + + // Test FSub(-0.0, 1.0) + EXPECT_TRUE(match(V1, m_FNeg(m_Value(Match)))); + EXPECT_EQ(O, Match); + + // Test FSub(0.0, 1.0) + EXPECT_FALSE(match(V2, m_FNeg(m_Value(Match)))); + cast(V2)->setHasNoSignedZeros(true); + EXPECT_TRUE(match(V2, m_FNeg(m_Value(Match)))); + EXPECT_EQ(O, Match); + + // Test FAdd(-0.0, 1.0) + EXPECT_FALSE(match(V3, m_FNeg(m_Value(Match)))); +} + template struct MutableConstTest : PatternMatchTest { }; typedef ::testing::Types,