Index: llvm/include/llvm/Analysis/TargetFolder.h =================================================================== --- llvm/include/llvm/Analysis/TargetFolder.h +++ llvm/include/llvm/Analysis/TargetFolder.h @@ -124,6 +124,10 @@ return Fold(ConstantExpr::getNot(C)); } + Constant *CreateUnOp(Instruction::UnaryOps Opc, Constant *C) const { + return Fold(ConstantExpr::get(Opc, C)); + } + //===--------------------------------------------------------------------===// // Memory Instructions //===--------------------------------------------------------------------===// Index: llvm/include/llvm/IR/ConstantFolder.h =================================================================== --- llvm/include/llvm/IR/ConstantFolder.h +++ llvm/include/llvm/IR/ConstantFolder.h @@ -134,6 +134,10 @@ return ConstantExpr::getNot(C); } + Constant *CreateUnOp(Instruction::UnaryOps Opc, Constant *V) const { + return ConstantExpr::get(Opc, V); + } + //===--------------------------------------------------------------------===// // Memory Instructions //===--------------------------------------------------------------------===// Index: llvm/include/llvm/IR/IRBuilder.h =================================================================== --- llvm/include/llvm/IR/IRBuilder.h +++ llvm/include/llvm/IR/IRBuilder.h @@ -1038,6 +1038,12 @@ return I; } + Value *foldConstant(Instruction::UnaryOps Opc, Value *V, + const Twine &Name) const { + auto *C = dyn_cast(V); + return C ? Insert(Folder.CreateUnOp(Opc, C), Name) : nullptr; + } + Value *foldConstant(Instruction::BinaryOps Opc, Value *L, Value *R, const Twine &Name) const { auto *LC = dyn_cast(L); @@ -1360,18 +1366,37 @@ Value *CreateFNeg(Value *V, const Twine &Name = "", MDNode *FPMathTag = nullptr) { - if (auto *VC = dyn_cast(V)) - return Insert(Folder.CreateFNeg(VC), Name); + if (Value *VC = foldConstant(Instruction::FNeg, V, Name)) return VC; return Insert(setFPAttrs(BinaryOperator::CreateFNeg(V), FPMathTag, FMF), Name); } + /// Copy fast-math-flags from an instruction rather than using the builder's + /// default FMF. + Value *CreateFNegFMF(Value *V, Instruction *FMFSource, + const Twine &Name = "") { + if (Value *VC = foldConstant(Instruction::FNeg, V, Name)) return VC; + return Insert(setFPAttrs(UnaryOperator::CreateFNeg(V), nullptr, + FMFSource->getFastMathFlags()), + Name); + } + Value *CreateNot(Value *V, const Twine &Name = "") { if (auto *VC = dyn_cast(V)) return Insert(Folder.CreateNot(VC), Name); return Insert(BinaryOperator::CreateNot(V), Name); } + Value *CreateUnOp(Instruction::UnaryOps Opc, + Value *V, const Twine &Name = "", + MDNode *FPMathTag = nullptr) { + if (Value *VC = foldConstant(Opc, V, Name)) return VC; + Instruction *UnOp = UnaryOperator::Create(Opc, V); + if (isa(UnOp)) + UnOp = setFPAttrs(UnOp, FPMathTag, FMF); + return Insert(UnOp, Name); + } + //===--------------------------------------------------------------------===// // Instruction creation methods: Memory Instructions //===--------------------------------------------------------------------===// Index: llvm/include/llvm/IR/NoFolder.h =================================================================== --- llvm/include/llvm/IR/NoFolder.h +++ llvm/include/llvm/IR/NoFolder.h @@ -203,6 +203,10 @@ return BinaryOperator::CreateNot(C); } + Instruction *CreateUnOp(Instruction::UnaryOps Opc, Constant *V) const { + return UnaryOperator::Create(Opc, V); + } + //===--------------------------------------------------------------------===// // Memory Instructions //===--------------------------------------------------------------------===// Index: llvm/unittests/IR/PatternMatch.cpp =================================================================== --- llvm/unittests/IR/PatternMatch.cpp +++ llvm/unittests/IR/PatternMatch.cpp @@ -616,6 +616,28 @@ // Test FAdd(-0.0, 1.0) EXPECT_FALSE(match(V3, m_FNeg(m_Value(Match)))); + + // Test FNeg(X) with inherited FMF + Instruction *I = cast(V); + I->setHasNoSignedZeros(true); + I->setHasNoNaNs(true); + Value *Alloca = IRB.CreateAlloca(FltTy); + Value *LoadInst = IRB.CreateLoad(FltTy, Alloca); + Value *VFMF = IRB.CreateFNegFMF(LoadInst, I); + Instruction *IFMF = cast(VFMF); + EXPECT_TRUE(IFMF->hasNoSignedZeros()); + EXPECT_TRUE(IFMF->hasNoNaNs()); + EXPECT_FALSE(IFMF->hasAllowReassoc()); + + // Test CreateUnOp(Opcode, C) + Value *CUP = IRB.CreateUnOp(Instruction::FNeg, One); + EXPECT_TRUE(match(CUP, m_FNeg(m_Value(Match)))); + EXPECT_EQ(One, Match); + + // Test CreateUnOp(Opcode, X) + Value *CUP2 = IRB.CreateUnOp(Instruction::FNeg, LoadInst); + EXPECT_TRUE(match(CUP2, m_FNeg(m_Value(Match)))); + EXPECT_EQ(LoadInst, Match); } template struct MutableConstTest : PatternMatchTest { };