Index: include/llvm/IR/IRBuilder.h =================================================================== --- include/llvm/IR/IRBuilder.h +++ include/llvm/IR/IRBuilder.h @@ -88,6 +88,30 @@ class IRBuilderBase { DebugLoc CurDbgLocation; +public: + /// Specifies the required exception behavior. This is only used when + /// when constrained floating point is enabled. See the LLVM Language + /// Reference Manual for details. + enum ConstrainedExceptKind { + CE_Unspecified, ///< Use as a placeholder to not affect exception + ///< behavior. + CE_Strict, ///< This corresponds to "fpexcept.strict". + CE_Ignore, ///< This corresponds to "fpexcept.ignore". + CE_MayTrap ///< This corresponds to "fpexcept.maytrap". + }; + /// Specifies the rounding mode to be assumed. This is only used when + /// when constrained floating point is enabled. See the LLVM Language + /// Reference Manual for details. + enum ConstrainedRoundingKind { + CR_Unspecified, ///< Use as a placeholder to not affect rounding + ///< behavior. + CR_Dynamic, ///< This corresponds to "fpround.dynamic". + CR_ToNearest, ///< This corresponds to "fpround.tonearest". + CR_Downward, ///< This corresponds to "fpround.downward". + CR_Upward, ///< This corresponds to "fpround.upward". + CR_ToZero ///< This corresponds to "fpround.tozero". + }; + protected: BasicBlock *BB; BasicBlock::iterator InsertPt; @@ -96,12 +120,18 @@ MDNode *DefaultFPMathTag; FastMathFlags FMF; + bool IsFPConstrained; + ConstrainedExceptKind DefaultConstrainedExcept; + ConstrainedRoundingKind DefaultConstrainedRounding; + ArrayRef DefaultOperandBundles; public: IRBuilderBase(LLVMContext &context, MDNode *FPMathTag = nullptr, ArrayRef OpBundles = None) - : Context(context), DefaultFPMathTag(FPMathTag), + : Context(context), DefaultFPMathTag(FPMathTag), IsFPConstrained(false), + DefaultConstrainedExcept(CE_Unspecified), + DefaultConstrainedRounding(CR_Unspecified), DefaultOperandBundles(OpBundles) { ClearInsertionPoint(); } @@ -218,6 +248,35 @@ /// 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 setIsFPConstrained(bool IsCon) { IsFPConstrained = IsCon; } + + /// Disable use of constrained floating point math + void clearIsFPConstrained() { setIsFPConstrained(false); } + + /// Query for the use of constrained floating point math + bool getIsFPConstrained() { return IsFPConstrained; } + + /// Set the exception handling to be used with constrained floating point + void setDefaultConstrainedExcept(ConstrainedExceptKind NewExcept) { + DefaultConstrainedExcept = NewExcept; + } + + /// Set the rounding mode handling to be used with constrained floating point + void setDefaultConstrainedRounding(ConstrainedRoundingKind NewRounding) { + DefaultConstrainedRounding = NewRounding; + } + + /// Get the exception handling used with constrained floating point + ConstrainedExceptKind getDefaultConstrainedExcept() { + return DefaultConstrainedExcept; + } + + /// Get the rounding mode handling used with constrained floating point + ConstrainedRoundingKind getDefaultConstrainedRounding() { + return DefaultConstrainedRounding; + } + //===--------------------------------------------------------------------===// // RAII helpers. //===--------------------------------------------------------------------===// @@ -1045,6 +1104,68 @@ return (LC && RC) ? Insert(Folder.CreateBinOp(Opc, LC, RC), Name) : nullptr; } + Value *getConstrainedRounding(ConstrainedRoundingKind Rounding) { + ConstrainedRoundingKind UseRounding = DefaultConstrainedRounding; + + if (Rounding != CR_Unspecified) + UseRounding = Rounding; + + MDNode *RoundingMD; + switch (UseRounding) { + case CR_Unspecified: + case CR_Dynamic: + RoundingMD = + MDNode::get(Context, MDString::get(Context, "round.dynamic")); + break; + case CR_ToNearest: + RoundingMD = + MDNode::get(Context, MDString::get(Context, "round.tonearest")); + break; + case CR_Downward: + RoundingMD = + MDNode::get(Context, MDString::get(Context, "round.downward")); + break; + case CR_Upward: + RoundingMD = MDNode::get(Context, MDString::get(Context, "round.upward")); + break; + case CR_ToZero: + RoundingMD = MDNode::get(Context, MDString::get(Context, "round.tozero")); + break; + } + + MDString *RoundingMDS = cast(RoundingMD->getOperand(0)); + + return MetadataAsValue::get(Context, RoundingMDS); + } + + Value *getConstrainedExcept(ConstrainedExceptKind Except) { + ConstrainedExceptKind UseExcept = DefaultConstrainedExcept; + + if (Except != CE_Unspecified) + UseExcept = Except; + + MDNode *ExceptMD; + switch (UseExcept) { + case CE_Unspecified: + case CE_Strict: + ExceptMD = + MDNode::get(Context, MDString::get(Context, "fpexcept.strict")); + break; + case CE_Ignore: + ExceptMD = + MDNode::get(Context, MDString::get(Context, "fpexcept.ignore")); + break; + case CE_MayTrap: + ExceptMD = + MDNode::get(Context, MDString::get(Context, "fpexcept.maytrap")); + break; + } + + MDString *ExceptMDS = cast(ExceptMD->getOperand(0)); + + return MetadataAsValue::get(Context, ExceptMDS); + } + public: Value *CreateAdd(Value *LHS, Value *RHS, const Twine &Name = "", bool HasNUW = false, bool HasNSW = false) { @@ -1247,6 +1368,10 @@ Value *CreateFAdd(Value *L, Value *R, const Twine &Name = "", MDNode *FPMD = nullptr) { + if (IsFPConstrained) + return CreateConstrainedFPBinOp(Intrinsic::experimental_constrained_fadd, + L, R, nullptr, Name); + if (Value *V = foldConstant(Instruction::FAdd, L, R, Name)) return V; Instruction *I = setFPAttrs(BinaryOperator::CreateFAdd(L, R), FPMD, FMF); return Insert(I, Name); @@ -1256,6 +1381,10 @@ /// default FMF. Value *CreateFAddFMF(Value *L, Value *R, Instruction *FMFSource, const Twine &Name = "") { + if (IsFPConstrained) + return CreateConstrainedFPBinOp(Intrinsic::experimental_constrained_fadd, + L, R, FMFSource, Name); + if (Value *V = foldConstant(Instruction::FAdd, L, R, Name)) return V; Instruction *I = setFPAttrs(BinaryOperator::CreateFAdd(L, R), nullptr, FMFSource->getFastMathFlags()); @@ -1264,6 +1393,10 @@ Value *CreateFSub(Value *L, Value *R, const Twine &Name = "", MDNode *FPMD = nullptr) { + if (IsFPConstrained) + return CreateConstrainedFPBinOp(Intrinsic::experimental_constrained_fsub, + L, R, nullptr, Name); + if (Value *V = foldConstant(Instruction::FSub, L, R, Name)) return V; Instruction *I = setFPAttrs(BinaryOperator::CreateFSub(L, R), FPMD, FMF); return Insert(I, Name); @@ -1273,6 +1406,10 @@ /// default FMF. Value *CreateFSubFMF(Value *L, Value *R, Instruction *FMFSource, const Twine &Name = "") { + if (IsFPConstrained) + return CreateConstrainedFPBinOp(Intrinsic::experimental_constrained_fsub, + L, R, FMFSource, Name); + if (Value *V = foldConstant(Instruction::FSub, L, R, Name)) return V; Instruction *I = setFPAttrs(BinaryOperator::CreateFSub(L, R), nullptr, FMFSource->getFastMathFlags()); @@ -1281,6 +1418,10 @@ Value *CreateFMul(Value *L, Value *R, const Twine &Name = "", MDNode *FPMD = nullptr) { + if (IsFPConstrained) + return CreateConstrainedFPBinOp(Intrinsic::experimental_constrained_fmul, + L, R, nullptr, Name); + if (Value *V = foldConstant(Instruction::FMul, L, R, Name)) return V; Instruction *I = setFPAttrs(BinaryOperator::CreateFMul(L, R), FPMD, FMF); return Insert(I, Name); @@ -1290,6 +1431,10 @@ /// default FMF. Value *CreateFMulFMF(Value *L, Value *R, Instruction *FMFSource, const Twine &Name = "") { + if (IsFPConstrained) + return CreateConstrainedFPBinOp(Intrinsic::experimental_constrained_fmul, + L, R, FMFSource, Name); + if (Value *V = foldConstant(Instruction::FMul, L, R, Name)) return V; Instruction *I = setFPAttrs(BinaryOperator::CreateFMul(L, R), nullptr, FMFSource->getFastMathFlags()); @@ -1298,6 +1443,10 @@ Value *CreateFDiv(Value *L, Value *R, const Twine &Name = "", MDNode *FPMD = nullptr) { + if (IsFPConstrained) + return CreateConstrainedFPBinOp(Intrinsic::experimental_constrained_fdiv, + L, R, nullptr, Name); + if (Value *V = foldConstant(Instruction::FDiv, L, R, Name)) return V; Instruction *I = setFPAttrs(BinaryOperator::CreateFDiv(L, R), FPMD, FMF); return Insert(I, Name); @@ -1307,6 +1456,10 @@ /// default FMF. Value *CreateFDivFMF(Value *L, Value *R, Instruction *FMFSource, const Twine &Name = "") { + if (IsFPConstrained) + return CreateConstrainedFPBinOp(Intrinsic::experimental_constrained_fdiv, + L, R, FMFSource, Name); + if (Value *V = foldConstant(Instruction::FDiv, L, R, Name)) return V; Instruction *I = setFPAttrs(BinaryOperator::CreateFDiv(L, R), nullptr, FMFSource->getFastMathFlags()); @@ -1315,6 +1468,10 @@ Value *CreateFRem(Value *L, Value *R, const Twine &Name = "", MDNode *FPMD = nullptr) { + if (IsFPConstrained) + return CreateConstrainedFPBinOp(Intrinsic::experimental_constrained_frem, + L, R, nullptr, Name); + if (Value *V = foldConstant(Instruction::FRem, L, R, Name)) return V; Instruction *I = setFPAttrs(BinaryOperator::CreateFRem(L, R), FPMD, FMF); return Insert(I, Name); @@ -1324,6 +1481,10 @@ /// default FMF. Value *CreateFRemFMF(Value *L, Value *R, Instruction *FMFSource, const Twine &Name = "") { + if (IsFPConstrained) + return CreateConstrainedFPBinOp(Intrinsic::experimental_constrained_frem, + L, R, FMFSource, Name); + if (Value *V = foldConstant(Instruction::FRem, L, R, Name)) return V; Instruction *I = setFPAttrs(BinaryOperator::CreateFRem(L, R), nullptr, FMFSource->getFastMathFlags()); @@ -1340,6 +1501,18 @@ return Insert(BinOp, Name); } + CallInst *CreateConstrainedFPBinOp( + Intrinsic::ID ID, Value *L, Value *R, Instruction *FMFSource = nullptr, + const Twine &Name = "", ConstrainedRoundingKind Rounding = CR_Unspecified, + ConstrainedExceptKind Except = CE_Unspecified) { + + Value *RoundingV = getConstrainedRounding(Rounding); + Value *ExceptV = getConstrainedExcept(Except); + + return CreateIntrinsic(ID, {L->getType()}, {L, R, RoundingV, ExceptV}, + FMFSource, Name); + } + Value *CreateNeg(Value *V, const Twine &Name = "", bool HasNUW = false, bool HasNSW = false) { if (auto *VC = dyn_cast(V)) Index: unittests/IR/IRBuilderTest.cpp =================================================================== --- unittests/IR/IRBuilderTest.cpp +++ unittests/IR/IRBuilderTest.cpp @@ -122,6 +122,70 @@ EXPECT_FALSE(II->hasNoNaNs()); } +TEST_F(IRBuilderTest, ConstrainedFP) { + IRBuilder<> Builder(BB); + Value *V; + CallInst *Call; + IntrinsicInst *II; + + V = Builder.CreateLoad(GV); + + // See if we get constrained intrinsics instead of non-constrained + // instructions. + Builder.setIsFPConstrained(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. + 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(IRBuilderBase::CE_Ignore); + Builder.setDefaultConstrainedRounding(IRBuilderBase::CR_Upward); + 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.CreateConstrainedFPBinOp( + Intrinsic::experimental_constrained_fadd, V, V, nullptr, "", + IRBuilderBase::CR_Dynamic, IRBuilderBase::CE_Strict); + CII = cast(Call); + EXPECT_EQ(CII->getIntrinsicID(), Intrinsic::experimental_constrained_fadd); + 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());