[llvm] [IR] Store fast-math flags in Instruction (PR #188937)

via llvm-commits llvm-commits at lists.llvm.org
Wed Apr 1 23:35:55 PDT 2026


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

>From 57e886d2932ad681966656db2bbb568e0c90e888 Mon Sep 17 00:00:00 2001
From: PaperChalice <liujunchang97 at outlook.com>
Date: Fri, 27 Mar 2026 16:28:56 +0800
Subject: [PATCH] [IR] Store fast-math flags in Instruction

---
 llvm/include/llvm/IR/FMF.h                |  2 +-
 llvm/include/llvm/IR/Instruction.h        |  3 +
 llvm/include/llvm/IR/Operator.h           | 74 +++++++++++------------
 llvm/lib/Bitcode/Reader/BitcodeReader.cpp |  1 +
 llvm/lib/Bitcode/Writer/BitcodeWriter.cpp | 25 ++++----
 llvm/lib/IR/Instruction.cpp               | 43 +++++++------
 6 files changed, 80 insertions(+), 68 deletions(-)

diff --git a/llvm/include/llvm/IR/FMF.h b/llvm/include/llvm/IR/FMF.h
index 8f0489442e2b9..ca42a2da84b5b 100644
--- a/llvm/include/llvm/IR/FMF.h
+++ b/llvm/include/llvm/IR/FMF.h
@@ -22,7 +22,7 @@ class raw_ostream;
 /// Convenience struct for specifying and reasoning about fast-math flags.
 class FastMathFlags {
 private:
-  friend class FPMathOperator;
+  friend class Instruction;
 
   unsigned Flags = 0;
 
diff --git a/llvm/include/llvm/IR/Instruction.h b/llvm/include/llvm/IR/Instruction.h
index 11385666e7ff8..191e624b2a151 100644
--- a/llvm/include/llvm/IR/Instruction.h
+++ b/llvm/include/llvm/IR/Instruction.h
@@ -78,6 +78,9 @@ class Instruction : public User,
   /// O(1) local dominance checks between instructions.
   mutable unsigned Order = 0;
 
+protected:
+  unsigned short FMFValue = 0; // fast-math flag values
+
 public:
   /// Optional marker recording the position for debugging information that
   /// takes effect immediately before this instruction. Null unless there is
diff --git a/llvm/include/llvm/IR/Operator.h b/llvm/include/llvm/IR/Operator.h
index 2e0e71cbbf315..28b179155cef0 100644
--- a/llvm/include/llvm/IR/Operator.h
+++ b/llvm/include/llvm/IR/Operator.h
@@ -213,57 +213,52 @@ class FPMathOperator : public Operator {
   }
 
   void setHasAllowReassoc(bool B) {
-    SubclassOptionalData =
-    (SubclassOptionalData & ~FastMathFlags::AllowReassoc) |
-    (B * FastMathFlags::AllowReassoc);
+    auto *I = dyn_cast<Instruction>(this);
+    I->setHasAllowReassoc(B);
   }
 
   void setHasNoNaNs(bool B) {
-    SubclassOptionalData =
-      (SubclassOptionalData & ~FastMathFlags::NoNaNs) |
-      (B * FastMathFlags::NoNaNs);
+    auto *I = dyn_cast<Instruction>(this);
+    I->setHasNoNaNs(B);
   }
 
   void setHasNoInfs(bool B) {
-    SubclassOptionalData =
-      (SubclassOptionalData & ~FastMathFlags::NoInfs) |
-      (B * FastMathFlags::NoInfs);
+    auto *I = dyn_cast<Instruction>(this);
+    I->setHasNoInfs(B);
   }
 
   void setHasNoSignedZeros(bool B) {
-    SubclassOptionalData =
-      (SubclassOptionalData & ~FastMathFlags::NoSignedZeros) |
-      (B * FastMathFlags::NoSignedZeros);
+    auto *I = dyn_cast<Instruction>(this);
+    I->setHasNoSignedZeros(B);
   }
 
   void setHasAllowReciprocal(bool B) {
-    SubclassOptionalData =
-      (SubclassOptionalData & ~FastMathFlags::AllowReciprocal) |
-      (B * FastMathFlags::AllowReciprocal);
+    auto *I = dyn_cast<Instruction>(this);
+    I->setHasAllowReciprocal(B);
   }
 
   void setHasAllowContract(bool B) {
-    SubclassOptionalData =
-        (SubclassOptionalData & ~FastMathFlags::AllowContract) |
-        (B * FastMathFlags::AllowContract);
+    auto *I = dyn_cast<Instruction>(this);
+    I->setHasAllowContract(B);
   }
 
   void setHasApproxFunc(bool B) {
-    SubclassOptionalData =
-        (SubclassOptionalData & ~FastMathFlags::ApproxFunc) |
-        (B * FastMathFlags::ApproxFunc);
+    auto *I = dyn_cast<Instruction>(this);
+    I->setHasApproxFunc(B);
   }
 
   /// Convenience function for setting multiple fast-math flags.
   /// FMF is a mask of the bits to set.
   void setFastMathFlags(FastMathFlags FMF) {
-    SubclassOptionalData |= FMF.Flags;
+    auto *I = dyn_cast<Instruction>(this);
+    I->setFastMathFlags(FMF);
   }
 
   /// Convenience function for copying all fast-math flags.
   /// All values in FMF are transferred to this operator.
   void copyFastMathFlags(FastMathFlags FMF) {
-    SubclassOptionalData = FMF.Flags;
+    auto *I = dyn_cast<Instruction>(this);
+    I->copyFastMathFlags(FMF);
   }
 
   /// Returns true if `Ty` is composed of a single kind of float-poing type
@@ -284,54 +279,57 @@ 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);
+    const auto *I = dyn_cast<Instruction>(this);
+    return I->isFast();
   }
 
   /// Test if this operation may be simplified with reassociative transforms.
   bool hasAllowReassoc() const {
-    return (SubclassOptionalData & FastMathFlags::AllowReassoc) != 0;
+    const auto *I = dyn_cast<Instruction>(this);
+    return I->hasAllowReassoc();
   }
 
   /// Test if this operation's arguments and results are assumed not-NaN.
   bool hasNoNaNs() const {
-    return (SubclassOptionalData & FastMathFlags::NoNaNs) != 0;
+    const auto *I = dyn_cast<Instruction>(this);
+    return I->hasNoNaNs();
   }
 
   /// Test if this operation's arguments and results are assumed not-infinite.
   bool hasNoInfs() const {
-    return (SubclassOptionalData & FastMathFlags::NoInfs) != 0;
+    const auto *I = dyn_cast<Instruction>(this);
+    return I->hasNoInfs();
   }
 
   /// Test if this operation can ignore the sign of zero.
   bool hasNoSignedZeros() const {
-    return (SubclassOptionalData & FastMathFlags::NoSignedZeros) != 0;
+    const auto *I = dyn_cast<Instruction>(this);
+    return I->hasNoSignedZeros();
   }
 
   /// Test if this operation can use reciprocal multiply instead of division.
   bool hasAllowReciprocal() const {
-    return (SubclassOptionalData & FastMathFlags::AllowReciprocal) != 0;
+    const auto *I = dyn_cast<Instruction>(this);
+    return I->hasAllowReciprocal();
   }
 
   /// Test if this operation can be floating-point contracted (FMA).
   bool hasAllowContract() const {
-    return (SubclassOptionalData & FastMathFlags::AllowContract) != 0;
+    const auto *I = dyn_cast<Instruction>(this);
+    return I->hasAllowContract();
   }
 
   /// Test if this operation allows approximations of math library functions or
   /// intrinsics.
   bool hasApproxFunc() const {
-    return (SubclassOptionalData & FastMathFlags::ApproxFunc) != 0;
+    const auto *I = dyn_cast<Instruction>(this);
+    return I->hasApproxFunc();
   }
 
   /// Convenience function for getting all the fast-math flags
   FastMathFlags getFastMathFlags() const {
-    return FastMathFlags(SubclassOptionalData);
+    const auto *I = dyn_cast<Instruction>(this);
+    return I->getFastMathFlags();
   }
 
   /// Get the maximum error permitted by this operation in ULPs. An accuracy of
diff --git a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
index 1b9f13ecec62f..65fbad087b5ba 100644
--- a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
+++ b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
@@ -1427,6 +1427,7 @@ static Comdat::SelectionKind getDecodedComdatSelectionKind(unsigned Val) {
 }
 
 static FastMathFlags getDecodedFastMathFlags(unsigned Val) {
+  Val >>= 8;
   FastMathFlags FMF;
   if (0 != (Val & bitc::UnsafeAlgebra))
     FMF.setFast();
diff --git a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
index 568874b145c8d..2a59d0b767faa 100644
--- a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
+++ b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
@@ -1730,6 +1730,7 @@ void ModuleBitcodeWriter::writeModuleInfo() {
 
 static uint64_t getOptimizationFlags(const Value *V) {
   uint64_t Flags = 0;
+  uint32_t FMF = 0;
 
   if (const auto *OBO = dyn_cast<OverflowingBinaryOperator>(V)) {
     if (OBO->hasNoSignedWrap())
@@ -1744,19 +1745,19 @@ static uint64_t getOptimizationFlags(const Value *V) {
       Flags |= 1 << bitc::PDI_DISJOINT;
   } else if (const auto *FPMO = dyn_cast<FPMathOperator>(V)) {
     if (FPMO->hasAllowReassoc())
-      Flags |= bitc::AllowReassoc;
+      FMF |= bitc::AllowReassoc;
     if (FPMO->hasNoNaNs())
-      Flags |= bitc::NoNaNs;
+      FMF |= bitc::NoNaNs;
     if (FPMO->hasNoInfs())
-      Flags |= bitc::NoInfs;
+      FMF |= bitc::NoInfs;
     if (FPMO->hasNoSignedZeros())
-      Flags |= bitc::NoSignedZeros;
+      FMF |= bitc::NoSignedZeros;
     if (FPMO->hasAllowReciprocal())
-      Flags |= bitc::AllowReciprocal;
+      FMF |= bitc::AllowReciprocal;
     if (FPMO->hasAllowContract())
-      Flags |= bitc::AllowContract;
+      FMF |= bitc::AllowContract;
     if (FPMO->hasApproxFunc())
-      Flags |= bitc::ApproxFunc;
+      FMF |= bitc::ApproxFunc;
   } else if (const auto *NNI = dyn_cast<PossiblyNonNegInst>(V)) {
     if (NNI->hasNonNeg())
       Flags |= 1 << bitc::PNNI_NON_NEG;
@@ -1777,6 +1778,8 @@ static uint64_t getOptimizationFlags(const Value *V) {
       Flags |= 1 << bitc::ICMP_SAME_SIGN;
   }
 
+  Flags |= (FMF << 8);
+
   return Flags;
 }
 
@@ -4026,7 +4029,7 @@ void ModuleBitcodeWriter::writeBlockInfo() {
     Abbv->Add(BitCodeAbbrevOp(bitc::FUNC_CODE_INST_UNOP));
     Abbv->Add(ValAbbrevOp); // LHS
     Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 4)); // opc
-    Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 8)); // flags
+    Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // flags
     if (Stream.EmitBlockInfoAbbrev(bitc::FUNCTION_BLOCK_ID, Abbv) !=
         FUNCTION_INST_UNOP_FLAGS_ABBREV)
       llvm_unreachable("Unexpected abbrev ordering!");
@@ -4047,7 +4050,7 @@ void ModuleBitcodeWriter::writeBlockInfo() {
     Abbv->Add(ValAbbrevOp); // LHS
     Abbv->Add(ValAbbrevOp); // RHS
     Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 4)); // opc
-    Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 8)); // flags
+    Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // flags
     if (Stream.EmitBlockInfoAbbrev(bitc::FUNCTION_BLOCK_ID, Abbv) !=
         FUNCTION_INST_BINOP_FLAGS_ABBREV)
       llvm_unreachable("Unexpected abbrev ordering!");
@@ -4068,7 +4071,7 @@ void ModuleBitcodeWriter::writeBlockInfo() {
     Abbv->Add(ValAbbrevOp); // OpVal
     Abbv->Add(TypeAbbrevOp); // dest ty
     Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 4)); // opc
-    Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 8)); // flags
+    Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // flags
     if (Stream.EmitBlockInfoAbbrev(bitc::FUNCTION_BLOCK_ID, Abbv) !=
         FUNCTION_INST_CAST_FLAGS_ABBREV)
       llvm_unreachable("Unexpected abbrev ordering!");
@@ -4143,7 +4146,7 @@ void ModuleBitcodeWriter::writeBlockInfo() {
     Abbv->Add(ValAbbrevOp);                                // op0
     Abbv->Add(ValAbbrevOp);                                // op1
     Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 6)); // pred
-    Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 8)); // flags
+    Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // flags
     if (Stream.EmitBlockInfoAbbrev(bitc::FUNCTION_BLOCK_ID, Abbv) !=
         FUNCTION_INST_CMP_FLAGS_ABBREV)
       llvm_unreachable("Unexpected abbrev ordering!");
diff --git a/llvm/lib/IR/Instruction.cpp b/llvm/lib/IR/Instruction.cpp
index e324528298532..f3d90b04bac52 100644
--- a/llvm/lib/IR/Instruction.cpp
+++ b/llvm/lib/IR/Instruction.cpp
@@ -612,92 +612,99 @@ void Instruction::setFast(bool B) {
 
 void Instruction::setHasAllowReassoc(bool B) {
   assert(isa<FPMathOperator>(this) && "setting fast-math flag on invalid op");
-  cast<FPMathOperator>(this)->setHasAllowReassoc(B);
+  FMFValue = (FMFValue & ~FastMathFlags::AllowReassoc) |
+             (B * FastMathFlags::AllowReassoc);
 }
 
 void Instruction::setHasNoNaNs(bool B) {
   assert(isa<FPMathOperator>(this) && "setting fast-math flag on invalid op");
-  cast<FPMathOperator>(this)->setHasNoNaNs(B);
+  FMFValue = (FMFValue & ~FastMathFlags::NoNaNs) | (B * FastMathFlags::NoNaNs);
 }
 
 void Instruction::setHasNoInfs(bool B) {
   assert(isa<FPMathOperator>(this) && "setting fast-math flag on invalid op");
-  cast<FPMathOperator>(this)->setHasNoInfs(B);
+  FMFValue = (FMFValue & ~FastMathFlags::NoInfs) | (B * FastMathFlags::NoInfs);
 }
 
 void Instruction::setHasNoSignedZeros(bool B) {
   assert(isa<FPMathOperator>(this) && "setting fast-math flag on invalid op");
-  cast<FPMathOperator>(this)->setHasNoSignedZeros(B);
+  FMFValue = (FMFValue & ~FastMathFlags::NoSignedZeros) |
+             (B * FastMathFlags::NoSignedZeros);
 }
 
 void Instruction::setHasAllowReciprocal(bool B) {
   assert(isa<FPMathOperator>(this) && "setting fast-math flag on invalid op");
-  cast<FPMathOperator>(this)->setHasAllowReciprocal(B);
+  FMFValue = (FMFValue & ~FastMathFlags::AllowReciprocal) |
+             (B * FastMathFlags::AllowReciprocal);
 }
 
 void Instruction::setHasAllowContract(bool B) {
   assert(isa<FPMathOperator>(this) && "setting fast-math flag on invalid op");
-  cast<FPMathOperator>(this)->setHasAllowContract(B);
+  FMFValue = (FMFValue & ~FastMathFlags::AllowContract) |
+             (B * FastMathFlags::AllowContract);
 }
 
 void Instruction::setHasApproxFunc(bool B) {
   assert(isa<FPMathOperator>(this) && "setting fast-math flag on invalid op");
-  cast<FPMathOperator>(this)->setHasApproxFunc(B);
+  FMFValue =
+      (FMFValue & ~FastMathFlags::ApproxFunc) | (B * FastMathFlags::ApproxFunc);
 }
 
 void Instruction::setFastMathFlags(FastMathFlags FMF) {
   assert(isa<FPMathOperator>(this) && "setting fast-math flag on invalid op");
-  cast<FPMathOperator>(this)->setFastMathFlags(FMF);
+  FMFValue |= FMF.Flags;
 }
 
 void Instruction::copyFastMathFlags(FastMathFlags FMF) {
   assert(isa<FPMathOperator>(this) && "copying fast-math flag on invalid op");
-  cast<FPMathOperator>(this)->copyFastMathFlags(FMF);
+  FMFValue = FMF.Flags;
 }
 
 bool Instruction::isFast() const {
   assert(isa<FPMathOperator>(this) && "getting fast-math flag on invalid op");
-  return cast<FPMathOperator>(this)->isFast();
+  return hasAllowReassoc() && hasNoNaNs() && hasNoInfs() &&
+         hasNoSignedZeros() && hasAllowReciprocal() && hasAllowContract() &&
+         hasApproxFunc();
 }
 
 bool Instruction::hasAllowReassoc() const {
   assert(isa<FPMathOperator>(this) && "getting fast-math flag on invalid op");
-  return cast<FPMathOperator>(this)->hasAllowReassoc();
+  return FMFValue & FastMathFlags::AllowReassoc;
 }
 
 bool Instruction::hasNoNaNs() const {
   assert(isa<FPMathOperator>(this) && "getting fast-math flag on invalid op");
-  return cast<FPMathOperator>(this)->hasNoNaNs();
+  return FMFValue & FastMathFlags::NoNaNs;
 }
 
 bool Instruction::hasNoInfs() const {
   assert(isa<FPMathOperator>(this) && "getting fast-math flag on invalid op");
-  return cast<FPMathOperator>(this)->hasNoInfs();
+  return FMFValue & FastMathFlags::NoInfs;
 }
 
 bool Instruction::hasNoSignedZeros() const {
   assert(isa<FPMathOperator>(this) && "getting fast-math flag on invalid op");
-  return cast<FPMathOperator>(this)->hasNoSignedZeros();
+  return FMFValue & FastMathFlags::NoSignedZeros;
 }
 
 bool Instruction::hasAllowReciprocal() const {
   assert(isa<FPMathOperator>(this) && "getting fast-math flag on invalid op");
-  return cast<FPMathOperator>(this)->hasAllowReciprocal();
+  return FMFValue & FastMathFlags::AllowReciprocal;
 }
 
 bool Instruction::hasAllowContract() const {
   assert(isa<FPMathOperator>(this) && "getting fast-math flag on invalid op");
-  return cast<FPMathOperator>(this)->hasAllowContract();
+  return FMFValue & FastMathFlags::AllowContract;
 }
 
 bool Instruction::hasApproxFunc() const {
   assert(isa<FPMathOperator>(this) && "getting fast-math flag on invalid op");
-  return cast<FPMathOperator>(this)->hasApproxFunc();
+  return FMFValue & FastMathFlags::ApproxFunc;
 }
 
 FastMathFlags Instruction::getFastMathFlags() const {
   assert(isa<FPMathOperator>(this) && "getting fast-math flag on invalid op");
-  return cast<FPMathOperator>(this)->getFastMathFlags();
+  return FMFValue;
 }
 
 void Instruction::copyFastMathFlags(const Instruction *I) {



More information about the llvm-commits mailing list