Index: include/llvm/IR/IRBuilder.h =================================================================== --- include/llvm/IR/IRBuilder.h +++ include/llvm/IR/IRBuilder.h @@ -97,13 +97,18 @@ MDNode *DefaultFPMathTag; FastMathFlags FMF; + bool IsFPConstrained; + MDNode *DefaultConstrainedExcept; + MDNode *DefaultConstrainedRounding; + ArrayRef DefaultOperandBundles; public: IRBuilderBase(LLVMContext &context, MDNode *FPMathTag = nullptr, ArrayRef OpBundles = None) : Context(context), DefaultFPMathTag(FPMathTag), - DefaultOperandBundles(OpBundles) { + IsFPConstrained(false), DefaultConstrainedExcept(nullptr), + DefaultConstrainedRounding(nullptr), DefaultOperandBundles(OpBundles) { ClearInsertionPoint(); } @@ -219,6 +224,40 @@ /// Set the fast-math flags to be used with generated fp-math operators void setFastMathFlags(FastMathFlags NewFMF) { FMF = NewFMF; } + /// Enable/Disable use of constrained floating point math + void setIsConstrainedFP(bool IsCon) { IsFPConstrained = IsCon; } + + /// Disable use of constrained floating point math + void clearIsConstrainedFP() { setIsConstrainedFP(false); } + + /// Set the exception handling to be used with constrained floating point + void setDefaultConstrainedExcept(MDNode *NewExcept) { + DefaultConstrainedExcept = NewExcept; + } + + /// Set the rounding mode handling to be used with constrained floating point + void setDefaultConstrainedRounding(MDNode *NewRounding) { + DefaultConstrainedRounding = NewRounding; + } + + /// Get the exception handling used with constrained floating point + MDNode *getDefaultConstrainedExcept() { + if (!DefaultConstrainedExcept) { + DefaultConstrainedExcept = + MDNode::get(Context, MDString::get(Context, "fpexcept.strict")); + } + return DefaultConstrainedExcept; + } + + /// Get the rounding mode handling used with constrained floating point + MDNode *getDefaultConstrainedRounding() { + if (!DefaultConstrainedRounding) { + DefaultConstrainedRounding = + MDNode::get(Context, MDString::get(Context, "round.dynamic")); + } + return DefaultConstrainedRounding; + } + //===--------------------------------------------------------------------===// // RAII helpers. //===--------------------------------------------------------------------===// @@ -970,6 +1009,28 @@ return (LC && RC) ? Insert(Folder.CreateBinOp(Opc, LC, RC), Name) : nullptr; } + Value *getConstrainedRounding(MDNode *RoundingMD) { + MDString *Rounding; + + if (!RoundingMD) + RoundingMD = getDefaultConstrainedRounding(); + + Rounding = cast(RoundingMD->getOperand(0)); + + return MetadataAsValue::get(Context, Rounding); + } + + Value *getConstrainedExcept(MDNode *ExceptMD) { + MDString *Except; + + if (!ExceptMD) + ExceptMD = getDefaultConstrainedExcept(); + + Except = cast(ExceptMD->getOperand(0)); + + return MetadataAsValue::get(Context, Except); + } + public: Value *CreateAdd(Value *LHS, Value *RHS, const Twine &Name = "", bool HasNUW = false, bool HasNSW = false) { @@ -1172,89 +1233,203 @@ Value *CreateFAdd(Value *L, Value *R, const Twine &Name = "", MDNode *FPMD = nullptr) { - if (Value *V = foldConstant(Instruction::FAdd, L, R, Name)) return V; - Instruction *I = setFPAttrs(BinaryOperator::CreateFAdd(L, R), FPMD, FMF); - return Insert(I, Name); + if (IsFPConstrained) + return CreateConstrainedFAdd(L, R, nullptr, Name, nullptr, nullptr); + else { + if (Value *V = foldConstant(Instruction::FAdd, L, R, Name)) return V; + Instruction *I = setFPAttrs(BinaryOperator::CreateFAdd(L, R), FPMD, FMF); + return Insert(I, Name); + } } /// Copy fast-math-flags from an instruction rather than using the builder's /// default FMF. Value *CreateFAddFMF(Value *L, Value *R, Instruction *FMFSource, const Twine &Name = "") { - if (Value *V = foldConstant(Instruction::FAdd, L, R, Name)) return V; - Instruction *I = setFPAttrs(BinaryOperator::CreateFAdd(L, R), nullptr, - FMFSource->getFastMathFlags()); - return Insert(I, Name); + if (IsFPConstrained) + return CreateConstrainedFAdd(L, R, FMFSource, Name, nullptr, nullptr); + else { + if (Value *V = foldConstant(Instruction::FAdd, L, R, Name)) return V; + Instruction *I = setFPAttrs(BinaryOperator::CreateFAdd(L, R), nullptr, + FMFSource->getFastMathFlags()); + return Insert(I, Name); + } } + CallInst *CreateConstrainedFAdd(Value *L, Value *R, + Instruction *FMFSource = nullptr, const Twine &Name = "", + MDNode *RoundingMD = nullptr, + MDNode *ExceptMD = nullptr) { + + Value *Rounding = getConstrainedRounding(RoundingMD); + Value *Except = getConstrainedExcept(ExceptMD); + + return CreateIntrinsic(Intrinsic::experimental_constrained_fadd, + { L->getType() }, + { L, R, Rounding, Except }, + FMFSource, Name); + } + Value *CreateFSub(Value *L, Value *R, const Twine &Name = "", MDNode *FPMD = nullptr) { - if (Value *V = foldConstant(Instruction::FSub, L, R, Name)) return V; - Instruction *I = setFPAttrs(BinaryOperator::CreateFSub(L, R), FPMD, FMF); - return Insert(I, Name); + if (IsFPConstrained) + return CreateConstrainedFSub(L, R, nullptr, Name, nullptr, nullptr); + else { + if (Value *V = foldConstant(Instruction::FSub, L, R, Name)) return V; + Instruction *I = setFPAttrs(BinaryOperator::CreateFSub(L, R), FPMD, FMF); + return Insert(I, Name); + } } /// Copy fast-math-flags from an instruction rather than using the builder's /// default FMF. Value *CreateFSubFMF(Value *L, Value *R, Instruction *FMFSource, const Twine &Name = "") { - if (Value *V = foldConstant(Instruction::FSub, L, R, Name)) return V; - Instruction *I = setFPAttrs(BinaryOperator::CreateFSub(L, R), nullptr, - FMFSource->getFastMathFlags()); - return Insert(I, Name); + if (IsFPConstrained) + return CreateConstrainedFSub(L, R, FMFSource, Name, nullptr, nullptr); + else { + if (Value *V = foldConstant(Instruction::FSub, L, R, Name)) return V; + Instruction *I = setFPAttrs(BinaryOperator::CreateFSub(L, R), nullptr, + FMFSource->getFastMathFlags()); + return Insert(I, Name); + } } + CallInst *CreateConstrainedFSub(Value *L, Value *R, + Instruction *FMFSource = nullptr, + const Twine &Name = "", + MDNode *RoundingMD = nullptr, + MDNode *ExceptMD = nullptr) { + + Value *Rounding = getConstrainedRounding(RoundingMD); + Value *Except = getConstrainedExcept(ExceptMD); + + return CreateIntrinsic(Intrinsic::experimental_constrained_fsub, + { L->getType() }, + { L, R, Rounding, Except }, + FMFSource, Name); + } + Value *CreateFMul(Value *L, Value *R, const Twine &Name = "", MDNode *FPMD = nullptr) { - if (Value *V = foldConstant(Instruction::FMul, L, R, Name)) return V; - Instruction *I = setFPAttrs(BinaryOperator::CreateFMul(L, R), FPMD, FMF); - return Insert(I, Name); + if (IsFPConstrained) + return CreateConstrainedFMul(L, R, nullptr, Name, nullptr, nullptr); + else { + if (Value *V = foldConstant(Instruction::FMul, L, R, Name)) return V; + Instruction *I = setFPAttrs(BinaryOperator::CreateFMul(L, R), FPMD, FMF); + return Insert(I, Name); + } } /// Copy fast-math-flags from an instruction rather than using the builder's /// default FMF. Value *CreateFMulFMF(Value *L, Value *R, Instruction *FMFSource, const Twine &Name = "") { - if (Value *V = foldConstant(Instruction::FMul, L, R, Name)) return V; - Instruction *I = setFPAttrs(BinaryOperator::CreateFMul(L, R), nullptr, - FMFSource->getFastMathFlags()); - return Insert(I, Name); + if (IsFPConstrained) + return CreateConstrainedFMul(L, R, FMFSource, Name, nullptr, nullptr); + else { + if (Value *V = foldConstant(Instruction::FMul, L, R, Name)) return V; + Instruction *I = setFPAttrs(BinaryOperator::CreateFMul(L, R), nullptr, + FMFSource->getFastMathFlags()); + return Insert(I, Name); + } } + CallInst *CreateConstrainedFMul(Value *L, Value *R, + Instruction *FMFSource = nullptr, + const Twine &Name = "", + MDNode *RoundingMD = nullptr, + MDNode *ExceptMD = nullptr) { + + Value *Rounding = getConstrainedRounding(RoundingMD); + Value *Except = getConstrainedExcept(ExceptMD); + + return CreateIntrinsic(Intrinsic::experimental_constrained_fmul, + { L->getType() }, + { L, R, Rounding, Except }, + FMFSource, Name); + } + Value *CreateFDiv(Value *L, Value *R, const Twine &Name = "", MDNode *FPMD = nullptr) { - if (Value *V = foldConstant(Instruction::FDiv, L, R, Name)) return V; - Instruction *I = setFPAttrs(BinaryOperator::CreateFDiv(L, R), FPMD, FMF); - return Insert(I, Name); + if (IsFPConstrained) + return CreateConstrainedFDiv(L, R, nullptr, Name, nullptr, nullptr); + else { + if (Value *V = foldConstant(Instruction::FDiv, L, R, Name)) return V; + Instruction *I = setFPAttrs(BinaryOperator::CreateFDiv(L, R), FPMD, FMF); + return Insert(I, Name); + } } /// Copy fast-math-flags from an instruction rather than using the builder's /// default FMF. Value *CreateFDivFMF(Value *L, Value *R, Instruction *FMFSource, const Twine &Name = "") { - if (Value *V = foldConstant(Instruction::FDiv, L, R, Name)) return V; - Instruction *I = setFPAttrs(BinaryOperator::CreateFDiv(L, R), nullptr, - FMFSource->getFastMathFlags()); - return Insert(I, Name); + if (IsFPConstrained) + return CreateConstrainedFDiv(L, R, FMFSource, Name, nullptr, nullptr); + else { + if (Value *V = foldConstant(Instruction::FDiv, L, R, Name)) return V; + Instruction *I = setFPAttrs(BinaryOperator::CreateFDiv(L, R), nullptr, + FMFSource->getFastMathFlags()); + return Insert(I, Name); + } } + CallInst *CreateConstrainedFDiv(Value *L, Value *R, + Instruction *FMFSource = nullptr, + const Twine &Name = "", + MDNode *RoundingMD = nullptr, + MDNode *ExceptMD = nullptr) { + + Value *Rounding = getConstrainedRounding(RoundingMD); + Value *Except = getConstrainedExcept(ExceptMD); + + return CreateIntrinsic(Intrinsic::experimental_constrained_fdiv, + { L->getType() }, + { L, R, Rounding, Except }, + FMFSource, Name); + } + Value *CreateFRem(Value *L, Value *R, const Twine &Name = "", MDNode *FPMD = nullptr) { - if (Value *V = foldConstant(Instruction::FRem, L, R, Name)) return V; - Instruction *I = setFPAttrs(BinaryOperator::CreateFRem(L, R), FPMD, FMF); - return Insert(I, Name); + if (IsFPConstrained) + return CreateConstrainedFRem(L, R, nullptr, Name, nullptr, nullptr); + else { + if (Value *V = foldConstant(Instruction::FRem, L, R, Name)) return V; + Instruction *I = setFPAttrs(BinaryOperator::CreateFRem(L, R), FPMD, FMF); + return Insert(I, Name); + } } /// Copy fast-math-flags from an instruction rather than using the builder's /// default FMF. Value *CreateFRemFMF(Value *L, Value *R, Instruction *FMFSource, const Twine &Name = "") { - if (Value *V = foldConstant(Instruction::FRem, L, R, Name)) return V; - Instruction *I = setFPAttrs(BinaryOperator::CreateFRem(L, R), nullptr, - FMFSource->getFastMathFlags()); - return Insert(I, Name); + if (IsFPConstrained) + return CreateConstrainedFRem(L, R, FMFSource, Name, nullptr, nullptr); + else { + if (Value *V = foldConstant(Instruction::FRem, L, R, Name)) return V; + Instruction *I = setFPAttrs(BinaryOperator::CreateFRem(L, R), nullptr, + FMFSource->getFastMathFlags()); + return Insert(I, Name); + } } + CallInst *CreateConstrainedFRem(Value *L, Value *R, + Instruction *FMFSource = nullptr, + const Twine &Name = "", + MDNode *RoundingMD = nullptr, + MDNode *ExceptMD = nullptr) { + + Value *Rounding = getConstrainedRounding(RoundingMD); + Value *Except = getConstrainedExcept(ExceptMD); + + return CreateIntrinsic(Intrinsic::experimental_constrained_frem, + { L->getType() }, + { L, R, Rounding, Except }, + FMFSource, Name); + } + Value *CreateBinOp(Instruction::BinaryOps Opc, Value *LHS, Value *RHS, const Twine &Name = "", MDNode *FPMathTag = nullptr) { Index: unittests/IR/IRBuilderTest.cpp =================================================================== --- unittests/IR/IRBuilderTest.cpp +++ unittests/IR/IRBuilderTest.cpp @@ -123,6 +123,100 @@ EXPECT_FALSE(II->hasNoNaNs()); } +TEST_F(IRBuilderTest, ConstrainedFP) { + IRBuilder<> Builder(BB); + Value *V; + CallInst *Call; + IntrinsicInst *II; + + V = Builder.CreateLoad(GV); + + Call = Builder.CreateConstrainedFAdd(V, V); + II = cast(Call); + EXPECT_EQ(II->getIntrinsicID(), Intrinsic::experimental_constrained_fadd); + + Call = Builder.CreateConstrainedFSub(V, V); + II = cast(Call); + EXPECT_EQ(II->getIntrinsicID(), Intrinsic::experimental_constrained_fsub); + + Call = Builder.CreateConstrainedFMul(V, V); + II = cast(Call); + EXPECT_EQ(II->getIntrinsicID(), Intrinsic::experimental_constrained_fmul); + + Call = Builder.CreateConstrainedFDiv(V, V); + II = cast(Call); + EXPECT_EQ(II->getIntrinsicID(), Intrinsic::experimental_constrained_fdiv); + + Call = Builder.CreateConstrainedFRem(V, V); + II = cast(Call); + EXPECT_EQ(II->getIntrinsicID(), Intrinsic::experimental_constrained_frem); + + // Now see if we get constrained intrinsics instead of non-constrained + // instructions. + Builder.setIsConstrainedFP(true); + + V = Builder.CreateFAdd(V, V); + ASSERT_TRUE(isa(V)); + II = cast(V); + EXPECT_EQ(II->getIntrinsicID(), Intrinsic::experimental_constrained_fadd); + + V = Builder.CreateFSub(V, V); + ASSERT_TRUE(isa(V)); + II = cast(V); + EXPECT_EQ(II->getIntrinsicID(), Intrinsic::experimental_constrained_fsub); + + V = Builder.CreateFMul(V, V); + ASSERT_TRUE(isa(V)); + II = cast(V); + EXPECT_EQ(II->getIntrinsicID(), Intrinsic::experimental_constrained_fmul); + + V = Builder.CreateFDiv(V, V); + ASSERT_TRUE(isa(V)); + II = cast(V); + EXPECT_EQ(II->getIntrinsicID(), Intrinsic::experimental_constrained_fdiv); + + V = Builder.CreateFRem(V, V); + ASSERT_TRUE(isa(V)); + II = cast(V); + EXPECT_EQ(II->getIntrinsicID(), Intrinsic::experimental_constrained_frem); + + // Verify the codepaths for setting and overriding the default metadata. + MDNode *ExceptStr = MDNode::get(Builder.getContext(), + MDString::get(Builder.getContext(), + "fpexcept.strict")); + MDNode *ExceptIgn = MDNode::get(Builder.getContext(), + MDString::get(Builder.getContext(), + "fpexcept.ignore")); + MDNode *RoundDyn = MDNode::get(Builder.getContext(), + MDString::get(Builder.getContext(), + "round.dynamic")); + MDNode *RoundUp = MDNode::get(Builder.getContext(), + MDString::get(Builder.getContext(), + "round.upward")); + + V = Builder.CreateFAdd(V, V); + ASSERT_TRUE(isa(V)); + auto *CII = cast(V); + ASSERT_TRUE(CII->getExceptionBehavior() == ConstrainedFPIntrinsic::ebStrict); + ASSERT_TRUE(CII->getRoundingMode() == ConstrainedFPIntrinsic::rmDynamic); + + Builder.setDefaultConstrainedExcept(ExceptIgn); + Builder.setDefaultConstrainedRounding(RoundUp); + V = Builder.CreateFAdd(V, V); + CII = cast(V); + ASSERT_TRUE(CII->getExceptionBehavior() == ConstrainedFPIntrinsic::ebIgnore); + ASSERT_TRUE(CII->getRoundingMode() == ConstrainedFPIntrinsic::rmUpward); + + // Now override the defaults. + Call = Builder.CreateConstrainedFAdd(V, V, nullptr, "", RoundDyn, ExceptStr); + CII = cast(Call); + ASSERT_TRUE(CII->getExceptionBehavior() == ConstrainedFPIntrinsic::ebStrict); + ASSERT_TRUE(CII->getRoundingMode() == ConstrainedFPIntrinsic::rmDynamic); + + Builder.CreateRetVoid(); + EXPECT_FALSE(verifyModule(*M)); +} + TEST_F(IRBuilderTest, Lifetime) { IRBuilder<> Builder(BB); AllocaInst *Var1 = Builder.CreateAlloca(Builder.getInt8Ty());