kpn updated this revision to Diff 176432.
kpn added a comment.

I've changed the patch so that calls to CreateFAdd() et al will give you 
constrained intrinsics if they are enabled. This required adding functions to 
enable/disable constrained-as-default plus calls to deal with the rounding mode 
and exception handling for contrained intrinsics.

I've left the independent create constrained functions to make it dead easy to 
move them out of the header and avoid inlining bloat.

I'm not dealing with any fast math flags or metadata currently. I'm not sure 
they make sense in a constrained context, or at least I haven't seen anyone 
argue they must be in place for an initial implementation.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D53157/new/

https://reviews.llvm.org/D53157

Files:
  include/llvm/IR/IRBuilder.h
  unittests/IR/IRBuilderTest.cpp

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<IntrinsicInst>(Call);
+  EXPECT_EQ(II->getIntrinsicID(), Intrinsic::experimental_constrained_fadd);
+
+  Call = Builder.CreateConstrainedFSub(V, V);
+  II = cast<IntrinsicInst>(Call);
+  EXPECT_EQ(II->getIntrinsicID(), Intrinsic::experimental_constrained_fsub);
+
+  Call = Builder.CreateConstrainedFMul(V, V);
+  II = cast<IntrinsicInst>(Call);
+  EXPECT_EQ(II->getIntrinsicID(), Intrinsic::experimental_constrained_fmul);
+
+  Call = Builder.CreateConstrainedFDiv(V, V);
+  II = cast<IntrinsicInst>(Call);
+  EXPECT_EQ(II->getIntrinsicID(), Intrinsic::experimental_constrained_fdiv);
+
+  Call = Builder.CreateConstrainedFRem(V, V);
+  II = cast<IntrinsicInst>(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<IntrinsicInst>(V));
+  II = cast<IntrinsicInst>(V);
+  EXPECT_EQ(II->getIntrinsicID(), Intrinsic::experimental_constrained_fadd);
+
+  V = Builder.CreateFSub(V, V);
+  ASSERT_TRUE(isa<IntrinsicInst>(V));
+  II = cast<IntrinsicInst>(V);
+  EXPECT_EQ(II->getIntrinsicID(), Intrinsic::experimental_constrained_fsub);
+
+  V = Builder.CreateFMul(V, V);
+  ASSERT_TRUE(isa<IntrinsicInst>(V));
+  II = cast<IntrinsicInst>(V);
+  EXPECT_EQ(II->getIntrinsicID(), Intrinsic::experimental_constrained_fmul);
+  
+  V = Builder.CreateFDiv(V, V);
+  ASSERT_TRUE(isa<IntrinsicInst>(V));
+  II = cast<IntrinsicInst>(V);
+  EXPECT_EQ(II->getIntrinsicID(), Intrinsic::experimental_constrained_fdiv);
+  
+  V = Builder.CreateFRem(V, V);
+  ASSERT_TRUE(isa<IntrinsicInst>(V));
+  II = cast<IntrinsicInst>(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<ConstrainedFPIntrinsic>(V));
+  auto *CII = cast<ConstrainedFPIntrinsic>(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<ConstrainedFPIntrinsic>(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<ConstrainedFPIntrinsic>(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());
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<OperandBundleDef> DefaultOperandBundles;
 
 public:
   IRBuilderBase(LLVMContext &context, MDNode *FPMathTag = nullptr,
                 ArrayRef<OperandBundleDef> 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<MDString>(RoundingMD->getOperand(0));
+
+    return MetadataAsValue::get(Context, Rounding);
+  }
+
+  Value *getConstrainedExcept(MDNode *ExceptMD) {
+    MDString *Except;
+
+    if (!ExceptMD)
+      ExceptMD = getDefaultConstrainedExcept();
+
+    Except = cast<MDString>(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) {
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to