[llvm] [IR] Store fast-math flags in subclasses of Instruction (PR #191190)

via llvm-commits llvm-commits at lists.llvm.org
Sun Apr 12 20:25:32 PDT 2026


https://github.com/paperchalice updated https://github.com/llvm/llvm-project/pull/191190

>From ab1c2a81b984ab41a77b6afe77689432039d57f6 Mon Sep 17 00:00:00 2001
From: PaperChalice <liujunchang97 at outlook.com>
Date: Fri, 10 Apr 2026 19:16:37 +0800
Subject: [PATCH] [IR] Store fast-math flags in subclasses of Instruction

---
 llvm/include/llvm/IR/InstVisitor.h   |  1 +
 llvm/include/llvm/IR/InstrTypes.h    | 83 ++++++++++++++++++++++---
 llvm/include/llvm/IR/Instruction.def | 10 ++--
 llvm/include/llvm/IR/Instruction.h   |  3 +-
 llvm/include/llvm/IR/Instructions.h  | 14 +++--
 llvm/include/llvm/IR/Operator.h      | 90 ++++++++++++++++------------
 llvm/lib/IR/Instruction.cpp          | 11 ++--
 llvm/lib/IR/Instructions.cpp         | 61 +++++++++++++++----
 llvm/lib/IR/Operator.cpp             | 58 ++++++++++++++++++
 9 files changed, 258 insertions(+), 73 deletions(-)

diff --git a/llvm/include/llvm/IR/InstVisitor.h b/llvm/include/llvm/IR/InstVisitor.h
index 4d5dd00b744b9..ff2b999b271a0 100644
--- a/llvm/include/llvm/IR/InstVisitor.h
+++ b/llvm/include/llvm/IR/InstVisitor.h
@@ -264,6 +264,7 @@ class InstVisitor {
   RetTy visitCastInst(CastInst &I)                { DELEGATE(UnaryInstruction);}
   RetTy visitUnaryOperator(UnaryOperator &I)      { DELEGATE(UnaryInstruction);}
   RetTy visitBinaryOperator(BinaryOperator &I)    { DELEGATE(Instruction);}
+  RetTy visitFPBinaryOperator(FPBinaryOperator &I) { DELEGATE(BinaryOperator); }
   RetTy visitCmpInst(CmpInst &I)                  { DELEGATE(Instruction);}
   RetTy visitUnaryInstruction(UnaryInstruction &I){ DELEGATE(Instruction);}
 
diff --git a/llvm/include/llvm/IR/InstrTypes.h b/llvm/include/llvm/IR/InstrTypes.h
index 61dc5ebef1b1d..c8fac25d0e032 100644
--- a/llvm/include/llvm/IR/InstrTypes.h
+++ b/llvm/include/llvm/IR/InstrTypes.h
@@ -51,6 +51,15 @@ namespace Intrinsic {
 typedef unsigned ID;
 }
 
+/// Provide fast-math flags storage, instructions that support fast-math flags
+/// should inherit from this class.
+class FastMathFlagsStorage {
+  friend class FPMathOperator;
+
+protected:
+  unsigned short FMFValue = 0;
+};
+
 //===----------------------------------------------------------------------===//
 //                          UnaryInstruction Class
 //===----------------------------------------------------------------------===//
@@ -98,7 +107,7 @@ DEFINE_TRANSPARENT_OPERAND_ACCESSORS(UnaryInstruction, Value)
 //                                UnaryOperator Class
 //===----------------------------------------------------------------------===//
 
-class UnaryOperator : public UnaryInstruction {
+class UnaryOperator : public UnaryInstruction, public FastMathFlagsStorage {
   void AssertOK();
 
 protected:
@@ -203,16 +212,12 @@ class BinaryOperator : public Instruction {
   /// statically know what type of instruction you're going to create.  These
   /// helpers just save some typing.
 #define HANDLE_BINARY_INST(N, OPC, CLASS)                                      \
-  static BinaryOperator *Create##OPC(Value *V1, Value *V2,                     \
-                                     const Twine &Name = "") {                 \
-    return Create(Instruction::OPC, V1, V2, Name);                             \
-  }
+  static inline BinaryOperator *Create##OPC(Value *V1, Value *V2,              \
+                                            const Twine &Name = "");
 #include "llvm/IR/Instruction.def"
 #define HANDLE_BINARY_INST(N, OPC, CLASS)                                      \
-  static BinaryOperator *Create##OPC(Value *V1, Value *V2, const Twine &Name,  \
-                                     InsertPosition InsertBefore) {            \
-    return Create(Instruction::OPC, V1, V2, Name, InsertBefore);               \
-  }
+  static inline BinaryOperator *Create##OPC(                                   \
+      Value *V1, Value *V2, const Twine &Name, InsertPosition InsertBefore);
 #include "llvm/IR/Instruction.def"
 
   static BinaryOperator *
@@ -435,6 +440,66 @@ BinaryOperator *BinaryOperator::CreateDisjoint(BinaryOps Opc, Value *V1,
   return BO;
 }
 
+/// Binary operators support fast-math flags, users should not use this
+/// class directly, BinaryOperator can automatic create instructions with
+/// correct type.
+class FPBinaryOperator : public BinaryOperator, public FastMathFlagsStorage {
+  friend class Instruction;
+  friend class BinaryOperator;
+  LLVM_ABI FPBinaryOperator *cloneImpl() const;
+  using BinaryOperator::BinaryOperator;
+
+  LLVM_ABI static FPBinaryOperator *
+  Create(BinaryOps Op, Value *S1, Value *S2, const Twine &Name = Twine(),
+         InsertPosition InsertBefore = nullptr);
+
+public:
+  static bool classof(const Instruction *I) {
+    switch (I->getOpcode()) {
+    case Instruction::FAdd:
+    case Instruction::FSub:
+    case Instruction::FMul:
+    case Instruction::FDiv:
+    case Instruction::FRem:
+      return true;
+    default:
+      return false;
+    }
+  }
+
+  static bool classof(const Value *V) {
+    return isa<Instruction>(V) && classof(cast<Instruction>(V));
+  }
+};
+
+#define HANDLE_BINARY_INST(N, OPC, CLASS)                                      \
+  BinaryOperator *BinaryOperator::Create##OPC(Value *V1, Value *V2,            \
+                                              const Twine &Name) {             \
+    if constexpr (Instruction::OPC == Instruction::FAdd ||                     \
+                  Instruction::OPC == Instruction::FSub ||                     \
+                  Instruction::OPC == Instruction::FMul ||                     \
+                  Instruction::OPC == Instruction::FDiv ||                     \
+                  Instruction::OPC == Instruction::FRem)                       \
+      return FPBinaryOperator::Create(Instruction::OPC, V1, V2, Name);         \
+    else                                                                       \
+      return Create(Instruction::OPC, V1, V2, Name);                           \
+  }
+#include "llvm/IR/Instruction.def"
+#define HANDLE_BINARY_INST(N, OPC, CLASS)                                      \
+  BinaryOperator *BinaryOperator::Create##OPC(                                 \
+      Value *V1, Value *V2, const Twine &Name, InsertPosition InsertBefore) {  \
+    if constexpr (Instruction::OPC == Instruction::FAdd ||                     \
+                  Instruction::OPC == Instruction::FSub ||                     \
+                  Instruction::OPC == Instruction::FMul ||                     \
+                  Instruction::OPC == Instruction::FDiv ||                     \
+                  Instruction::OPC == Instruction::FRem)                       \
+      return FPBinaryOperator::Create(Instruction::OPC, V1, V2, Name,          \
+                                      InsertBefore);                           \
+    else                                                                       \
+      return Create(Instruction::OPC, V1, V2, Name, InsertBefore);             \
+  }
+#include "llvm/IR/Instruction.def"
+
 //===----------------------------------------------------------------------===//
 //                               CastInst Class
 //===----------------------------------------------------------------------===//
diff --git a/llvm/include/llvm/IR/Instruction.def b/llvm/include/llvm/IR/Instruction.def
index 89d214868e16b..c1c008d634616 100644
--- a/llvm/include/llvm/IR/Instruction.def
+++ b/llvm/include/llvm/IR/Instruction.def
@@ -146,17 +146,17 @@ HANDLE_UNARY_INST(13, FNeg  , UnaryOperator)
 // Standard binary operators...
  FIRST_BINARY_INST(14)
 HANDLE_BINARY_INST(14, Add  , BinaryOperator)
-HANDLE_BINARY_INST(15, FAdd , BinaryOperator)
+HANDLE_BINARY_INST(15, FAdd , FPBinaryOperator)
 HANDLE_BINARY_INST(16, Sub  , BinaryOperator)
-HANDLE_BINARY_INST(17, FSub , BinaryOperator)
+HANDLE_BINARY_INST(17, FSub , FPBinaryOperator)
 HANDLE_BINARY_INST(18, Mul  , BinaryOperator)
-HANDLE_BINARY_INST(19, FMul , BinaryOperator)
+HANDLE_BINARY_INST(19, FMul , FPBinaryOperator)
 HANDLE_BINARY_INST(20, UDiv , BinaryOperator)
 HANDLE_BINARY_INST(21, SDiv , BinaryOperator)
-HANDLE_BINARY_INST(22, FDiv , BinaryOperator)
+HANDLE_BINARY_INST(22, FDiv , FPBinaryOperator)
 HANDLE_BINARY_INST(23, URem , BinaryOperator)
 HANDLE_BINARY_INST(24, SRem , BinaryOperator)
-HANDLE_BINARY_INST(25, FRem , BinaryOperator)
+HANDLE_BINARY_INST(25, FRem , FPBinaryOperator)
 
 // Logical operators (integer operands)
 HANDLE_BINARY_INST(26, Shl  , BinaryOperator) // Shift left  (logical)
diff --git a/llvm/include/llvm/IR/Instruction.h b/llvm/include/llvm/IR/Instruction.h
index 0b57ad4d0a379..379eca2fd43a6 100644
--- a/llvm/include/llvm/IR/Instruction.h
+++ b/llvm/include/llvm/IR/Instruction.h
@@ -712,7 +712,8 @@ class Instruction : public User,
 
   /// Convenience method to copy supported exact, fast-math, and (optionally)
   /// wrapping flags from V to this instruction.
-  LLVM_ABI void copyIRFlags(const Value *V, bool IncludeWrapFlags = true);
+  LLVM_ABI void copyIRFlags(const Value *V, bool IncludeWrapFlags = true,
+                            bool IncludeFastMathFlags = true);
 
   /// Logical 'and' of any supported wrapping, exact, and fast-math flags of
   /// V and this instruction.
diff --git a/llvm/include/llvm/IR/Instructions.h b/llvm/include/llvm/IR/Instructions.h
index f4fa59ada9d05..2fa49b6fc4e28 100644
--- a/llvm/include/llvm/IR/Instructions.h
+++ b/llvm/include/llvm/IR/Instructions.h
@@ -1418,7 +1418,7 @@ class ICmpInst: public CmpInst {
 /// to the constructor. It only operates on floating point values or packed
 /// vectors of floating point values. The operands must be identical types.
 /// Represents a floating point comparison operator.
-class FCmpInst: public CmpInst {
+class FCmpInst : public CmpInst, public FastMathFlagsStorage {
   void AssertOK() {
     assert(isFPPredicate() && "Invalid FCmp predicate value");
     assert(getOperand(0)->getType() == getOperand(1)->getType() &&
@@ -1456,6 +1456,8 @@ class FCmpInst: public CmpInst {
            Instruction *FlagsSource = nullptr)
       : CmpInst(makeCmpResultType(LHS->getType()), Instruction::FCmp, Pred, LHS,
                 RHS, NameStr, nullptr, FlagsSource) {
+    if (FlagsSource)
+      copyFastMathFlags(FlagsSource);
     AssertOK();
   }
 
@@ -1518,7 +1520,7 @@ class FCmpInst: public CmpInst {
 /// field to indicate whether or not this is a tail call.  The rest of the bits
 /// hold the calling convention of the call.
 ///
-class CallInst : public CallBase {
+class CallInst : public CallBase, public FastMathFlagsStorage {
   CallInst(const CallInst &CI, AllocInfo AllocInfo);
 
   /// Construct a CallInst from a range of arguments
@@ -1697,7 +1699,7 @@ CallInst::CallInst(FunctionType *Ty, Value *Func, ArrayRef<Value *> Args,
 
 /// This class represents the LLVM 'select' instruction.
 ///
-class SelectInst : public Instruction {
+class SelectInst : public Instruction, public FastMathFlagsStorage {
   constexpr static IntrusiveOperandsAllocMarker AllocMarker{3};
 
   SelectInst(Value *C, Value *S1, Value *S2, const Twine &NameStr,
@@ -2648,7 +2650,7 @@ DEFINE_TRANSPARENT_OPERAND_ACCESSORS(InsertValueInst, Value)
 // node, that can not exist in nature, but can be synthesized in a computer
 // scientist's overactive imagination.
 //
-class PHINode : public Instruction {
+class PHINode : public Instruction, public FastMathFlagsStorage {
   constexpr static HungOffOperandsAllocMarker AllocMarker{};
 
   /// The number of operands actually allocated.  NumOperands is
@@ -4878,7 +4880,7 @@ class SExtInst : public CastInst {
 //===----------------------------------------------------------------------===//
 
 /// This class represents a truncation of floating point types.
-class FPTruncInst : public CastInst {
+class FPTruncInst : public CastInst, public FastMathFlagsStorage {
 protected:
   // Note: Instruction needs to be a friend here to call cloneImpl.
   friend class Instruction;
@@ -4909,7 +4911,7 @@ class FPTruncInst : public CastInst {
 //===----------------------------------------------------------------------===//
 
 /// This class represents an extension of floating point types.
-class FPExtInst : public CastInst {
+class FPExtInst : public CastInst, public FastMathFlagsStorage {
 protected:
   // Note: Instruction needs to be a friend here to call cloneImpl.
   friend class Instruction;
diff --git a/llvm/include/llvm/IR/Operator.h b/llvm/include/llvm/IR/Operator.h
index 2e0e71cbbf315..89f6b1f5ea1c6 100644
--- a/llvm/include/llvm/IR/Operator.h
+++ b/llvm/include/llvm/IR/Operator.h
@@ -201,6 +201,9 @@ class FPMathOperator : public Operator {
 private:
   friend class Instruction;
 
+  unsigned short &getFMFValue();
+  unsigned short getFMFValue() const;
+
   /// 'Fast' means all bits are set.
   void setFast(bool B) {
     setHasAllowReassoc(B);
@@ -213,57 +216,59 @@ class FPMathOperator : public Operator {
   }
 
   void setHasAllowReassoc(bool B) {
-    SubclassOptionalData =
-    (SubclassOptionalData & ~FastMathFlags::AllowReassoc) |
-    (B * FastMathFlags::AllowReassoc);
+    unsigned short &FMFValue = getFMFValue();
+    FMFValue = (FMFValue & ~FastMathFlags::AllowReassoc) |
+               (B * FastMathFlags::AllowReassoc);
   }
 
   void setHasNoNaNs(bool B) {
-    SubclassOptionalData =
-      (SubclassOptionalData & ~FastMathFlags::NoNaNs) |
-      (B * FastMathFlags::NoNaNs);
+    unsigned short &FMFValue = getFMFValue();
+    FMFValue =
+        (FMFValue & ~FastMathFlags::NoNaNs) | (B * FastMathFlags::NoNaNs);
   }
 
   void setHasNoInfs(bool B) {
-    SubclassOptionalData =
-      (SubclassOptionalData & ~FastMathFlags::NoInfs) |
-      (B * FastMathFlags::NoInfs);
+    unsigned short &FMFValue = getFMFValue();
+    FMFValue =
+        (FMFValue & ~FastMathFlags::NoInfs) | (B * FastMathFlags::NoInfs);
   }
 
   void setHasNoSignedZeros(bool B) {
-    SubclassOptionalData =
-      (SubclassOptionalData & ~FastMathFlags::NoSignedZeros) |
-      (B * FastMathFlags::NoSignedZeros);
+    unsigned short &FMFValue = getFMFValue();
+    FMFValue = (FMFValue & ~FastMathFlags::NoSignedZeros) |
+               (B * FastMathFlags::NoSignedZeros);
   }
 
   void setHasAllowReciprocal(bool B) {
-    SubclassOptionalData =
-      (SubclassOptionalData & ~FastMathFlags::AllowReciprocal) |
-      (B * FastMathFlags::AllowReciprocal);
+    unsigned short &FMFValue = getFMFValue();
+    FMFValue = (FMFValue & ~FastMathFlags::AllowReciprocal) |
+               (B * FastMathFlags::AllowReciprocal);
   }
 
   void setHasAllowContract(bool B) {
-    SubclassOptionalData =
-        (SubclassOptionalData & ~FastMathFlags::AllowContract) |
-        (B * FastMathFlags::AllowContract);
+    unsigned short &FMFValue = getFMFValue();
+    FMFValue = (FMFValue & ~FastMathFlags::AllowContract) |
+               (B * FastMathFlags::AllowContract);
   }
 
   void setHasApproxFunc(bool B) {
-    SubclassOptionalData =
-        (SubclassOptionalData & ~FastMathFlags::ApproxFunc) |
-        (B * FastMathFlags::ApproxFunc);
+    unsigned short &FMFValue = getFMFValue();
+    FMFValue = (FMFValue & ~FastMathFlags::ApproxFunc) |
+               (B * FastMathFlags::ApproxFunc);
   }
 
   /// Convenience function for setting multiple fast-math flags.
   /// FMF is a mask of the bits to set.
   void setFastMathFlags(FastMathFlags FMF) {
-    SubclassOptionalData |= FMF.Flags;
+    unsigned short &FMFValue = getFMFValue();
+    FMFValue |= FMF.Flags;
   }
 
   /// Convenience function for copying all fast-math flags.
   /// All values in FMF are transferred to this operator.
   void copyFastMathFlags(FastMathFlags FMF) {
-    SubclassOptionalData = FMF.Flags;
+    unsigned short &FMFValue = getFMFValue();
+    FMFValue = FMF.Flags;
   }
 
   /// Returns true if `Ty` is composed of a single kind of float-poing type
@@ -284,54 +289,63 @@ class FPMathOperator : public Operator {
 public:
   /// Test if this operation allows all non-strict floating-point transforms.
   bool isFast() const {
-    return ((SubclassOptionalData & FastMathFlags::AllowReassoc) != 0 &&
-            (SubclassOptionalData & FastMathFlags::NoNaNs) != 0 &&
-            (SubclassOptionalData & FastMathFlags::NoInfs) != 0 &&
-            (SubclassOptionalData & FastMathFlags::NoSignedZeros) != 0 &&
-            (SubclassOptionalData & FastMathFlags::AllowReciprocal) != 0 &&
-            (SubclassOptionalData & FastMathFlags::AllowContract) != 0 &&
-            (SubclassOptionalData & FastMathFlags::ApproxFunc) != 0);
+    unsigned short FMFValue = getFMFValue();
+    return ((FMFValue & FastMathFlags::AllowReassoc) != 0 &&
+            (FMFValue & FastMathFlags::NoNaNs) != 0 &&
+            (FMFValue & FastMathFlags::NoInfs) != 0 &&
+            (FMFValue & FastMathFlags::NoSignedZeros) != 0 &&
+            (FMFValue & FastMathFlags::AllowReciprocal) != 0 &&
+            (FMFValue & FastMathFlags::AllowContract) != 0 &&
+            (FMFValue & FastMathFlags::ApproxFunc) != 0);
   }
 
   /// Test if this operation may be simplified with reassociative transforms.
   bool hasAllowReassoc() const {
-    return (SubclassOptionalData & FastMathFlags::AllowReassoc) != 0;
+    unsigned short FMFValue = getFMFValue();
+    return (FMFValue & FastMathFlags::AllowReassoc) != 0;
   }
 
   /// Test if this operation's arguments and results are assumed not-NaN.
   bool hasNoNaNs() const {
-    return (SubclassOptionalData & FastMathFlags::NoNaNs) != 0;
+    unsigned short FMFValue = getFMFValue();
+    return (FMFValue & FastMathFlags::NoNaNs) != 0;
   }
 
   /// Test if this operation's arguments and results are assumed not-infinite.
   bool hasNoInfs() const {
-    return (SubclassOptionalData & FastMathFlags::NoInfs) != 0;
+    unsigned short FMFValue = getFMFValue();
+    return (FMFValue & FastMathFlags::NoInfs) != 0;
   }
 
   /// Test if this operation can ignore the sign of zero.
   bool hasNoSignedZeros() const {
-    return (SubclassOptionalData & FastMathFlags::NoSignedZeros) != 0;
+    unsigned short FMFValue = getFMFValue();
+    return (FMFValue & FastMathFlags::NoSignedZeros) != 0;
   }
 
   /// Test if this operation can use reciprocal multiply instead of division.
   bool hasAllowReciprocal() const {
-    return (SubclassOptionalData & FastMathFlags::AllowReciprocal) != 0;
+    unsigned short FMFValue = getFMFValue();
+    return (FMFValue & FastMathFlags::AllowReciprocal) != 0;
   }
 
   /// Test if this operation can be floating-point contracted (FMA).
   bool hasAllowContract() const {
-    return (SubclassOptionalData & FastMathFlags::AllowContract) != 0;
+    unsigned short FMFValue = getFMFValue();
+    return (FMFValue & FastMathFlags::AllowContract) != 0;
   }
 
   /// Test if this operation allows approximations of math library functions or
   /// intrinsics.
   bool hasApproxFunc() const {
-    return (SubclassOptionalData & FastMathFlags::ApproxFunc) != 0;
+    unsigned short FMFValue = getFMFValue();
+    return (FMFValue & FastMathFlags::ApproxFunc) != 0;
   }
 
   /// Convenience function for getting all the fast-math flags
   FastMathFlags getFastMathFlags() const {
-    return FastMathFlags(SubclassOptionalData);
+    unsigned short FMFValue = getFMFValue();
+    return FastMathFlags(FMFValue);
   }
 
   /// Get the maximum error permitted by this operation in ULPs. An accuracy of
diff --git a/llvm/lib/IR/Instruction.cpp b/llvm/lib/IR/Instruction.cpp
index 8aa19a436a157..1974634dffbcb 100644
--- a/llvm/lib/IR/Instruction.cpp
+++ b/llvm/lib/IR/Instruction.cpp
@@ -708,7 +708,8 @@ void Instruction::copyFastMathFlags(const Instruction *I) {
   copyFastMathFlags(I->getFastMathFlags());
 }
 
-void Instruction::copyIRFlags(const Value *V, bool IncludeWrapFlags) {
+void Instruction::copyIRFlags(const Value *V, bool IncludeWrapFlags,
+                              bool IncludeFastMathFlags) {
   // Copy the wrapping flags.
   if (IncludeWrapFlags && isa<OverflowingBinaryOperator>(this)) {
     if (auto *OB = dyn_cast<OverflowingBinaryOperator>(V)) {
@@ -734,9 +735,11 @@ void Instruction::copyIRFlags(const Value *V, bool IncludeWrapFlags) {
       DestPD->setIsDisjoint(SrcPD->isDisjoint());
 
   // Copy the fast-math flags.
-  if (auto *FP = dyn_cast<FPMathOperator>(V))
-    if (isa<FPMathOperator>(this))
-      copyFastMathFlags(FP->getFastMathFlags());
+  if (IncludeFastMathFlags) {
+    if (auto *FP = dyn_cast<FPMathOperator>(V))
+      if (isa<FPMathOperator>(this))
+        copyFastMathFlags(FP->getFastMathFlags());
+  }
 
   if (auto *SrcGEP = dyn_cast<GetElementPtrInst>(V))
     if (auto *DestGEP = dyn_cast<GetElementPtrInst>(this))
diff --git a/llvm/lib/IR/Instructions.cpp b/llvm/lib/IR/Instructions.cpp
index 8a220c48acac8..2fd8758698b88 100644
--- a/llvm/lib/IR/Instructions.cpp
+++ b/llvm/lib/IR/Instructions.cpp
@@ -802,6 +802,7 @@ CallInst::CallInst(const CallInst &CI, AllocInfo AllocInfo)
   std::copy(CI.bundle_op_info_begin(), CI.bundle_op_info_end(),
             bundle_op_info_begin());
   SubclassOptionalData = CI.SubclassOptionalData;
+  FMFValue = CI.FMFValue;
 }
 
 CallInst *CallInst::Create(CallInst *CI, ArrayRef<OperandBundleDef> OpB,
@@ -813,6 +814,7 @@ CallInst *CallInst::Create(CallInst *CI, ArrayRef<OperandBundleDef> OpB,
   NewCI->setTailCallKind(CI->getTailCallKind());
   NewCI->setCallingConv(CI->getCallingConv());
   NewCI->SubclassOptionalData = CI->SubclassOptionalData;
+  NewCI->FMFValue = CI->FMFValue;
   NewCI->setAttributes(CI->getAttributes());
   NewCI->setDebugLoc(CI->getDebugLoc());
   return NewCI;
@@ -2717,7 +2719,11 @@ BinaryOperator *BinaryOperator::Create(BinaryOps Op, Value *S1, Value *S2,
                                        InsertPosition InsertBefore) {
   assert(S1->getType() == S2->getType() &&
          "Cannot create binary operator with two operands of differing type!");
-  return new BinaryOperator(Op, S1, S2, S1->getType(), Name, InsertBefore);
+  return FPMathOperator::isSupportedFloatingPointType(S1->getType())
+             ? new FPBinaryOperator(Op, S1, S2, S1->getType(), Name,
+                                    InsertBefore)
+             : new BinaryOperator(Op, S1, S2, S1->getType(), Name,
+                                  InsertBefore);
 }
 
 BinaryOperator *BinaryOperator::CreateNeg(Value *Op, const Twine &Name,
@@ -2750,6 +2756,14 @@ bool BinaryOperator::swapOperands() {
   return false;
 }
 
+FPBinaryOperator *FPBinaryOperator::Create(BinaryOps Op, Value *S1, Value *S2,
+                                           const Twine &Name,
+                                           InsertPosition InsertBefore) {
+  assert(S1->getType() == S2->getType() &&
+         "Cannot create binary operator with two operands of differing type!");
+  return new FPBinaryOperator(Op, S1, S2, S1->getType(), Name, InsertBefore);
+}
+
 //===----------------------------------------------------------------------===//
 //                             FPMathOperator Class
 //===----------------------------------------------------------------------===//
@@ -3532,7 +3546,8 @@ CmpInst::CmpInst(Type *ty, OtherOps op, Predicate predicate, Value *LHS,
   setPredicate(predicate);
   setName(Name);
   if (FlagsSource)
-    copyIRFlags(FlagsSource);
+    copyIRFlags(FlagsSource, /*IncludeWrapFlags=*/true,
+                /*IncludeFastMathFlags=*/false);
 }
 
 CmpInst *CmpInst::Create(OtherOps Op, Predicate predicate, Value *S1, Value *S2,
@@ -4346,15 +4361,27 @@ GetElementPtrInst *GetElementPtrInst::cloneImpl() const {
 }
 
 UnaryOperator *UnaryOperator::cloneImpl() const {
-  return Create(getOpcode(), Op<0>());
+  auto *I = Create(getOpcode(), Op<0>());
+  I->FMFValue = FMFValue;
+  return I;
 }
 
 BinaryOperator *BinaryOperator::cloneImpl() const {
+  if (auto *I = dyn_cast<FPBinaryOperator>(this))
+    return I->cloneImpl();
   return Create(getOpcode(), Op<0>(), Op<1>());
 }
 
+FPBinaryOperator *FPBinaryOperator::cloneImpl() const {
+  FPBinaryOperator *I = Create(getOpcode(), Op<0>(), Op<1>());
+  I->FMFValue = FMFValue;
+  return I;
+}
+
 FCmpInst *FCmpInst::cloneImpl() const {
-  return new FCmpInst(getPredicate(), Op<0>(), Op<1>());
+  auto *I = new FCmpInst(getPredicate(), Op<0>(), Op<1>());
+  I->FMFValue = FMFValue;
+  return I;
 }
 
 ICmpInst *ICmpInst::cloneImpl() const {
@@ -4421,11 +4448,15 @@ SExtInst *SExtInst::cloneImpl() const {
 }
 
 FPTruncInst *FPTruncInst::cloneImpl() const {
-  return new FPTruncInst(getOperand(0), getType());
+  auto *I = new FPTruncInst(getOperand(0), getType());
+  I->FMFValue = FMFValue;
+  return I;
 }
 
 FPExtInst *FPExtInst::cloneImpl() const {
-  return new FPExtInst(getOperand(0), getType());
+  auto *I = new FPExtInst(getOperand(0), getType());
+  I->FMFValue = FMFValue;
+  return I;
 }
 
 UIToFPInst *UIToFPInst::cloneImpl() const {
@@ -4469,14 +4500,20 @@ CallInst *CallInst::cloneImpl() const {
     IntrusiveOperandsAndDescriptorAllocMarker AllocMarker{
         getNumOperands(),
         getNumOperandBundles() * unsigned(sizeof(BundleOpInfo))};
-    return new (AllocMarker) CallInst(*this, AllocMarker);
+    auto *I = new (AllocMarker) CallInst(*this, AllocMarker);
+    I->FMFValue = FMFValue;
+    return I;
   }
   IntrusiveOperandsAllocMarker AllocMarker{getNumOperands()};
-  return new (AllocMarker) CallInst(*this, AllocMarker);
+  auto *I = new (AllocMarker) CallInst(*this, AllocMarker);
+  I->FMFValue = FMFValue;
+  return I;
 }
 
 SelectInst *SelectInst::cloneImpl() const {
-  return SelectInst::Create(getOperand(0), getOperand(1), getOperand(2));
+  auto *I = SelectInst::Create(getOperand(0), getOperand(1), getOperand(2));
+  I->FMFValue = FMFValue;
+  return I;
 }
 
 VAArgInst *VAArgInst::cloneImpl() const {
@@ -4495,7 +4532,11 @@ ShuffleVectorInst *ShuffleVectorInst::cloneImpl() const {
   return new ShuffleVectorInst(getOperand(0), getOperand(1), getShuffleMask());
 }
 
-PHINode *PHINode::cloneImpl() const { return new (AllocMarker) PHINode(*this); }
+PHINode *PHINode::cloneImpl() const {
+  auto *I = new (AllocMarker) PHINode(*this);
+  I->FMFValue = FMFValue;
+  return I;
+}
 
 LandingPadInst *LandingPadInst::cloneImpl() const {
   return new LandingPadInst(*this);
diff --git a/llvm/lib/IR/Operator.cpp b/llvm/lib/IR/Operator.cpp
index bd92a32142ebc..89cb29ba31cdd 100644
--- a/llvm/lib/IR/Operator.cpp
+++ b/llvm/lib/IR/Operator.cpp
@@ -300,3 +300,61 @@ void FastMathFlags::print(raw_ostream &O) const {
       O << " afn";
   }
 }
+
+unsigned short &FPMathOperator::getFMFValue() {
+  auto *V = static_cast<Value *>(this);
+  auto *I = dyn_cast<Instruction>(V);
+
+  if (auto *Op =
+          static_cast<FastMathFlagsStorage *>(dyn_cast<UnaryOperator>(I)))
+    return Op->FMFValue;
+  if (auto *Op =
+          static_cast<FastMathFlagsStorage *>(dyn_cast<FPBinaryOperator>(I)))
+    return Op->FMFValue;
+  if (auto *Op = static_cast<FastMathFlagsStorage *>(dyn_cast<FPTruncInst>(I)))
+    return Op->FMFValue;
+  if (auto *Op = static_cast<FastMathFlagsStorage *>(dyn_cast<FPExtInst>(I)))
+    return Op->FMFValue;
+  if (auto *Op = static_cast<FastMathFlagsStorage *>(dyn_cast<FCmpInst>(I)))
+    return Op->FMFValue;
+  if (auto *Op = static_cast<FastMathFlagsStorage *>(dyn_cast<PHINode>(I)))
+    return Op->FMFValue;
+  if (auto *Op = static_cast<FastMathFlagsStorage *>(dyn_cast<SelectInst>(I)))
+    return Op->FMFValue;
+  if (auto *Op = static_cast<FastMathFlagsStorage *>(dyn_cast<CallInst>(I)))
+    return Op->FMFValue;
+
+  llvm_unreachable("Unknown FPMathOperator!");
+}
+
+unsigned short FPMathOperator::getFMFValue() const {
+  const auto *V = static_cast<const Value *>(this);
+  const auto *I = dyn_cast<Instruction>(V);
+
+  if (auto *Op =
+          static_cast<const FastMathFlagsStorage *>(dyn_cast<UnaryOperator>(I)))
+    return Op->FMFValue;
+  if (const auto *Op = static_cast<const FastMathFlagsStorage *>(
+          dyn_cast<FPBinaryOperator>(I)))
+    return Op->FMFValue;
+  if (const auto *Op =
+          static_cast<const FastMathFlagsStorage *>(dyn_cast<FPTruncInst>(I)))
+    return Op->FMFValue;
+  if (const auto *Op =
+          static_cast<const FastMathFlagsStorage *>(dyn_cast<FPExtInst>(I)))
+    return Op->FMFValue;
+  if (const auto *Op =
+          static_cast<const FastMathFlagsStorage *>(dyn_cast<FCmpInst>(I)))
+    return Op->FMFValue;
+  if (const auto *Op =
+          static_cast<const FastMathFlagsStorage *>(dyn_cast<PHINode>(I)))
+    return Op->FMFValue;
+  if (auto *Op =
+          static_cast<const FastMathFlagsStorage *>(dyn_cast<SelectInst>(I)))
+    return Op->FMFValue;
+  if (const auto *Op =
+          static_cast<const FastMathFlagsStorage *>(dyn_cast<CallInst>(I)))
+    return Op->FMFValue;
+
+  llvm_unreachable("Unknown FPMathOperator!");
+}
\ No newline at end of file



More information about the llvm-commits mailing list