[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