[llvm] [GISel] Add KnownFPClass Analysis to GISelValueTrackingPass (PR #134611)
via llvm-commits
llvm-commits at lists.llvm.org
Mon Apr 7 04:07:23 PDT 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-llvm-selectiondag
Author: Tim Gymnich (tgymnich)
<details>
<summary>Changes</summary>
add KnownFPClass analysis to GISelValueTrackingPass
---
Patch is 107.08 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/134611.diff
10 Files Affected:
- (modified) llvm/include/llvm/CodeGen/GlobalISel/GISelValueTracking.h (+89)
- (modified) llvm/include/llvm/CodeGen/GlobalISel/MIPatternMatch.h (+229)
- (modified) llvm/include/llvm/CodeGen/GlobalISel/Utils.h (+35)
- (modified) llvm/include/llvm/CodeGen/TargetLowering.h (+8)
- (modified) llvm/lib/Analysis/ValueTracking.cpp (+1)
- (modified) llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp (+1464-4)
- (modified) llvm/lib/CodeGen/GlobalISel/Utils.cpp (+23)
- (modified) llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp (+7)
- (modified) llvm/unittests/CodeGen/GlobalISel/CMakeLists.txt (+1)
- (added) llvm/unittests/CodeGen/GlobalISel/KnownFPClassTest.cpp (+1062)
``````````diff
diff --git a/llvm/include/llvm/CodeGen/GlobalISel/GISelValueTracking.h b/llvm/include/llvm/CodeGen/GlobalISel/GISelValueTracking.h
index aa99bf321d2b1..1ae3b173d95ce 100644
--- a/llvm/include/llvm/CodeGen/GlobalISel/GISelValueTracking.h
+++ b/llvm/include/llvm/CodeGen/GlobalISel/GISelValueTracking.h
@@ -14,12 +14,15 @@
#ifndef LLVM_CODEGEN_GLOBALISEL_GISELVALUETRACKING_H
#define LLVM_CODEGEN_GLOBALISEL_GISELVALUETRACKING_H
+#include "llvm/ADT/APFloat.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/CodeGen/GlobalISel/GISelChangeObserver.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/Register.h"
+#include "llvm/IR/InstrTypes.h"
#include "llvm/InitializePasses.h"
#include "llvm/Support/KnownBits.h"
+#include "llvm/Support/KnownFPClass.h"
namespace llvm {
@@ -41,6 +44,64 @@ class GISelValueTracking : public GISelChangeObserver {
unsigned computeNumSignBitsMin(Register Src0, Register Src1,
const APInt &DemandedElts, unsigned Depth = 0);
+ /// Returns a pair of values, which if passed to llvm.is.fpclass, returns the
+ /// same result as an fcmp with the given operands.
+ ///
+ /// If \p LookThroughSrc is true, consider the input value when computing the
+ /// mask.
+ ///
+ /// If \p LookThroughSrc is false, ignore the source value (i.e. the first
+ /// pair element will always be LHS.
+ std::pair<Register, FPClassTest> fcmpToClassTest(CmpInst::Predicate Pred,
+ const MachineFunction &MF,
+ Register LHS, Value *RHS,
+ bool LookThroughSrc = true);
+ std::pair<Register, FPClassTest> fcmpToClassTest(CmpInst::Predicate Pred,
+ const MachineFunction &MF,
+ Register LHS,
+ const APFloat *ConstRHS,
+ bool LookThroughSrc = true);
+
+ /// Compute the possible floating-point classes that \p LHS could be based on
+ /// fcmp \Pred \p LHS, \p RHS.
+ ///
+ /// \returns { TestedValue, ClassesIfTrue, ClassesIfFalse }
+ ///
+ /// If the compare returns an exact class test, ClassesIfTrue ==
+ /// ~ClassesIfFalse
+ ///
+ /// This is a less exact version of fcmpToClassTest (e.g. fcmpToClassTest will
+ /// only succeed for a test of x > 0 implies positive, but not x > 1).
+ ///
+ /// If \p LookThroughSrc is true, consider the input value when computing the
+ /// mask. This may look through sign bit operations.
+ ///
+ /// If \p LookThroughSrc is false, ignore the source value (i.e. the first
+ /// pair element will always be LHS.
+ ///
+ std::tuple<Register, FPClassTest, FPClassTest>
+ fcmpImpliesClass(CmpInst::Predicate Pred, const MachineFunction &MF,
+ Register LHS, Register RHS, bool LookThroughSrc = true);
+ std::tuple<Register, FPClassTest, FPClassTest>
+ fcmpImpliesClass(CmpInst::Predicate Pred, const MachineFunction &MF,
+ Register LHS, FPClassTest RHS, bool LookThroughSrc = true);
+ std::tuple<Register, FPClassTest, FPClassTest>
+ fcmpImpliesClass(CmpInst::Predicate Pred, const MachineFunction &MF,
+ Register LHS, const APFloat &RHS,
+ bool LookThroughSrc = true);
+
+ void computeKnownFPClass(Register R, KnownFPClass &Known,
+ FPClassTest InterestedClasses, unsigned Depth);
+
+ void computeKnownFPClassForFPTrunc(const MachineInstr &MI,
+ const APInt &DemandedElts,
+ FPClassTest InterestedClasses,
+ KnownFPClass &Known, unsigned Depth);
+
+ void computeKnownFPClass(Register R, const APInt &DemandedElts,
+ FPClassTest InterestedClasses, KnownFPClass &Known,
+ unsigned Depth);
+
public:
GISelValueTracking(MachineFunction &MF, unsigned MaxDepth = 6);
virtual ~GISelValueTracking() = default;
@@ -86,6 +147,34 @@ class GISelValueTracking : public GISelChangeObserver {
/// \return The known alignment for the pointer-like value \p R.
Align computeKnownAlignment(Register R, unsigned Depth = 0);
+ /// Determine which floating-point classes are valid for \p V, and return them
+ /// in KnownFPClass bit sets.
+ ///
+ /// This function is defined on values with floating-point type, values
+ /// vectors of floating-point type, and arrays of floating-point type.
+
+ /// \p InterestedClasses is a compile time optimization hint for which
+ /// floating point classes should be queried. Queries not specified in \p
+ /// InterestedClasses should be reliable if they are determined during the
+ /// query.
+ KnownFPClass computeKnownFPClass(Register R, const APInt &DemandedElts,
+ FPClassTest InterestedClasses,
+ unsigned Depth);
+
+ KnownFPClass computeKnownFPClass(Register R,
+ FPClassTest InterestedClasses = fcAllFlags,
+ unsigned Depth = 0);
+
+ /// Wrapper to account for known fast math flags at the use instruction.
+ KnownFPClass computeKnownFPClass(Register R, const APInt &DemandedElts,
+ uint32_t Flags,
+ FPClassTest InterestedClasses,
+ unsigned Depth);
+
+ KnownFPClass computeKnownFPClass(Register R, uint32_t Flags,
+ FPClassTest InterestedClasses,
+ unsigned Depth);
+
// Observer API. No-op for non-caching implementation.
void erasingInstr(MachineInstr &MI) override {}
void createdInstr(MachineInstr &MI) override {}
diff --git a/llvm/include/llvm/CodeGen/GlobalISel/MIPatternMatch.h b/llvm/include/llvm/CodeGen/GlobalISel/MIPatternMatch.h
index 72483fbea5805..ccd898f0bfc39 100644
--- a/llvm/include/llvm/CodeGen/GlobalISel/MIPatternMatch.h
+++ b/llvm/include/llvm/CodeGen/GlobalISel/MIPatternMatch.h
@@ -14,9 +14,13 @@
#define LLVM_CODEGEN_GLOBALISEL_MIPATTERNMATCH_H
#include "llvm/ADT/APInt.h"
+#include "llvm/ADT/FloatingPointMode.h"
+#include "llvm/CodeGen/GlobalISel/GenericMachineInstrs.h"
#include "llvm/CodeGen/GlobalISel/Utils.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
+#include "llvm/CodeGen/TargetOpcodes.h"
#include "llvm/IR/InstrTypes.h"
+#include <optional>
namespace llvm {
namespace MIPatternMatch {
@@ -84,6 +88,12 @@ inline std::optional<int64_t> matchConstant(Register Reg,
return getIConstantVRegSExtVal(Reg, MRI);
}
+template <>
+inline std::optional<uint64_t> matchConstant(Register Reg,
+ const MachineRegisterInfo &MRI) {
+ return getIConstantVRegZExtVal(Reg, MRI);
+}
+
template <typename ConstT> struct ConstantMatch {
ConstT &CR;
ConstantMatch(ConstT &C) : CR(C) {}
@@ -103,6 +113,10 @@ inline ConstantMatch<int64_t> m_ICst(int64_t &Cst) {
return ConstantMatch<int64_t>(Cst);
}
+inline ConstantMatch<uint64_t> m_ICst(uint64_t &Cst) {
+ return ConstantMatch<uint64_t>(Cst);
+}
+
template <typename ConstT>
inline std::optional<ConstT> matchConstantSplat(Register,
const MachineRegisterInfo &);
@@ -119,6 +133,12 @@ matchConstantSplat(Register Reg, const MachineRegisterInfo &MRI) {
return getIConstantSplatSExtVal(Reg, MRI);
}
+template <>
+inline std::optional<uint64_t>
+matchConstantSplat(Register Reg, const MachineRegisterInfo &MRI) {
+ return getIConstantSplatZExtVal(Reg, MRI);
+}
+
template <typename ConstT> struct ICstOrSplatMatch {
ConstT &CR;
ICstOrSplatMatch(ConstT &C) : CR(C) {}
@@ -145,6 +165,10 @@ inline ICstOrSplatMatch<int64_t> m_ICstOrSplat(int64_t &Cst) {
return ICstOrSplatMatch<int64_t>(Cst);
}
+inline ICstOrSplatMatch<uint64_t> m_ICstOrSplat(uint64_t &Cst) {
+ return ICstOrSplatMatch<uint64_t>(Cst);
+}
+
struct GCstAndRegMatch {
std::optional<ValueAndVReg> &ValReg;
GCstAndRegMatch(std::optional<ValueAndVReg> &ValReg) : ValReg(ValReg) {}
@@ -393,6 +417,7 @@ inline bind_ty<const MachineInstr *> m_MInstr(const MachineInstr *&MI) {
inline bind_ty<LLT> m_Type(LLT &Ty) { return Ty; }
inline bind_ty<CmpInst::Predicate> m_Pred(CmpInst::Predicate &P) { return P; }
inline operand_type_match m_Pred() { return operand_type_match(); }
+inline bind_ty<FPClassTest> m_FPClassTest(FPClassTest &T) { return T; }
template <typename BindTy> struct deferred_helper {
static bool match(const MachineRegisterInfo &MRI, BindTy &VR, BindTy &V) {
@@ -762,6 +787,32 @@ struct CompareOp_match {
}
};
+template <typename LHS_P, typename Test_P, unsigned Opcode>
+struct ClassifyOp_match {
+ LHS_P L;
+ Test_P T;
+
+ ClassifyOp_match(const LHS_P &LHS, const Test_P &Tst) : L(LHS), T(Tst) {}
+
+ template <typename OpTy>
+ bool match(const MachineRegisterInfo &MRI, OpTy &&Op) {
+ MachineInstr *TmpMI;
+ if (!mi_match(Op, MRI, m_MInstr(TmpMI)) || TmpMI->getOpcode() != Opcode)
+ return false;
+
+ Register LHS = TmpMI->getOperand(1).getReg();
+ if (!L.match(MRI, LHS))
+ return false;
+
+ FPClassTest TmpClass =
+ static_cast<FPClassTest>(TmpMI->getOperand(2).getImm());
+ if (T.match(MRI, TmpClass))
+ return true;
+
+ return false;
+ }
+};
+
template <typename Pred, typename LHS, typename RHS>
inline CompareOp_match<Pred, LHS, RHS, TargetOpcode::G_ICMP>
m_GICmp(const Pred &P, const LHS &L, const RHS &R) {
@@ -804,6 +855,14 @@ m_c_GFCmp(const Pred &P, const LHS &L, const RHS &R) {
return CompareOp_match<Pred, LHS, RHS, TargetOpcode::G_FCMP, true>(P, L, R);
}
+/// Matches a register not-ed by a G_XOR.
+/// G_XOR %not_reg, -1
+template <typename LHS, typename Test>
+inline ClassifyOp_match<LHS, Test, TargetOpcode::G_IS_FPCLASS>
+m_GIsFPClass(const LHS &L, const Test &T) {
+ return ClassifyOp_match<LHS, Test, TargetOpcode::G_IS_FPCLASS>(L, T);
+}
+
// Helper for checking if a Reg is of specific type.
struct CheckType {
LLT Ty;
@@ -868,6 +927,176 @@ m_Not(const SrcTy &&Src) {
return m_GXor(Src, m_AllOnesInt());
}
+/// Matching combinators
+template <typename LTy, typename RTy> struct match_combine_or {
+ LTy L;
+ RTy R;
+
+ match_combine_or(const LTy &Left, const RTy &Right) : L(Left), R(Right) {}
+
+ template <typename OpTy>
+ bool match(const MachineRegisterInfo &MRI, OpTy &&Op) {
+ if (L.match(MRI, Op))
+ return true;
+ if (R.match(MRI, Op))
+ return true;
+ return false;
+ }
+};
+
+template <typename LTy, typename RTy> struct match_combine_and {
+ LTy L;
+ RTy R;
+
+ match_combine_and(const LTy &Left, const RTy &Right) : L(Left), R(Right) {}
+
+ template <typename OpTy>
+ bool match(const MachineRegisterInfo &MRI, OpTy &&Op) {
+ if (L.match(MRI, Op))
+ if (R.match(MRI, Op))
+ return true;
+ return false;
+ }
+};
+
+/// Combine two pattern matchers matching L || R
+template <typename LTy, typename RTy>
+inline match_combine_or<LTy, RTy> m_CombineOr(const LTy &L, const RTy &R) {
+ return match_combine_or<LTy, RTy>(L, R);
+}
+
+/// Combine two pattern matchers matching L && R
+template <typename LTy, typename RTy>
+inline match_combine_and<LTy, RTy> m_CombineAnd(const LTy &L, const RTy &R) {
+ return match_combine_and<LTy, RTy>(L, R);
+}
+
+template <typename Opnd_t> struct Argument_match {
+ unsigned OpI;
+ Opnd_t Val;
+
+ Argument_match(unsigned OpIdx, const Opnd_t &V) : OpI(OpIdx), Val(V) {}
+
+ template <typename OpTy>
+ bool match(const MachineRegisterInfo &MRI, OpTy &&Op) {
+ MachineInstr *TmpMI;
+ if (mi_match(Op, MRI, m_MInstr(TmpMI)))
+ return Val.match(
+ MRI, TmpMI->getOperand(TmpMI->getNumDefs() + 1 + OpI).getReg());
+ return false;
+ }
+};
+
+/// Match an argument.
+template <unsigned OpI, typename Opnd_t>
+inline Argument_match<Opnd_t> m_Argument(const Opnd_t &Op) {
+ return Argument_match<Opnd_t>(OpI, Op);
+}
+
+/// Intrinsic matchers.
+struct IntrinsicID_match {
+ unsigned ID;
+
+ IntrinsicID_match(Intrinsic::ID IntrID) : ID(IntrID) {}
+
+ template <typename OpTy>
+ bool match(const MachineRegisterInfo &MRI, OpTy &&Op) {
+ MachineInstr *TmpMI;
+ if (mi_match(Op, MRI, m_MInstr(TmpMI)))
+ if (auto *Intr = dyn_cast<GIntrinsic>(TmpMI))
+ return Intr->getIntrinsicID() == ID;
+ return false;
+ }
+};
+
+/// Intrinsic matches are combinations of ID matchers, and argument
+/// matchers. Higher arity matcher are defined recursively in terms of and-ing
+/// them with lower arity matchers. Here's some convenient typedefs for up to
+/// several arguments, and more can be added as needed
+template <typename T0 = void, typename T1 = void, typename T2 = void,
+ typename T3 = void, typename T4 = void, typename T5 = void,
+ typename T6 = void, typename T7 = void, typename T8 = void,
+ typename T9 = void, typename T10 = void>
+struct m_Intrinsic_Ty;
+template <typename T0> struct m_Intrinsic_Ty<T0> {
+ using Ty = match_combine_and<IntrinsicID_match, Argument_match<T0>>;
+};
+template <typename T0, typename T1> struct m_Intrinsic_Ty<T0, T1> {
+ using Ty =
+ match_combine_and<typename m_Intrinsic_Ty<T0>::Ty, Argument_match<T1>>;
+};
+template <typename T0, typename T1, typename T2>
+struct m_Intrinsic_Ty<T0, T1, T2> {
+ using Ty = match_combine_and<typename m_Intrinsic_Ty<T0, T1>::Ty,
+ Argument_match<T2>>;
+};
+template <typename T0, typename T1, typename T2, typename T3>
+struct m_Intrinsic_Ty<T0, T1, T2, T3> {
+ using Ty = match_combine_and<typename m_Intrinsic_Ty<T0, T1, T2>::Ty,
+ Argument_match<T3>>;
+};
+
+template <typename T0, typename T1, typename T2, typename T3, typename T4>
+struct m_Intrinsic_Ty<T0, T1, T2, T3, T4> {
+ using Ty = match_combine_and<typename m_Intrinsic_Ty<T0, T1, T2, T3>::Ty,
+ Argument_match<T4>>;
+};
+
+template <typename T0, typename T1, typename T2, typename T3, typename T4,
+ typename T5>
+struct m_Intrinsic_Ty<T0, T1, T2, T3, T4, T5> {
+ using Ty = match_combine_and<typename m_Intrinsic_Ty<T0, T1, T2, T3, T4>::Ty,
+ Argument_match<T5>>;
+};
+
+/// Match intrinsic calls like this:
+/// m_Intrinsic<Intrinsic::fabs>(m_Value(X))
+template <Intrinsic::ID IntrID> inline IntrinsicID_match m_GIntrinsic() {
+ return IntrinsicID_match(IntrID);
+}
+
+template <Intrinsic::ID IntrID, typename T0>
+inline typename m_Intrinsic_Ty<T0>::Ty m_GIntrinsic(const T0 &Op0) {
+ return m_CombineAnd(m_GIntrinsic<IntrID>(), m_Argument<0>(Op0));
+}
+
+template <Intrinsic::ID IntrID, typename T0, typename T1>
+inline typename m_Intrinsic_Ty<T0, T1>::Ty m_GIntrinsic(const T0 &Op0,
+ const T1 &Op1) {
+ return m_CombineAnd(m_GIntrinsic<IntrID>(Op0), m_Argument<1>(Op1));
+}
+
+template <Intrinsic::ID IntrID, typename T0, typename T1, typename T2>
+inline typename m_Intrinsic_Ty<T0, T1, T2>::Ty
+m_GIntrinsic(const T0 &Op0, const T1 &Op1, const T2 &Op2) {
+ return m_CombineAnd(m_GIntrinsic<IntrID>(Op0, Op1), m_Argument<2>(Op2));
+}
+
+template <Intrinsic::ID IntrID, typename T0, typename T1, typename T2,
+ typename T3>
+inline typename m_Intrinsic_Ty<T0, T1, T2, T3>::Ty
+m_GIntrinsic(const T0 &Op0, const T1 &Op1, const T2 &Op2, const T3 &Op3) {
+ return m_CombineAnd(m_GIntrinsic<IntrID>(Op0, Op1, Op2), m_Argument<3>(Op3));
+}
+
+template <Intrinsic::ID IntrID, typename T0, typename T1, typename T2,
+ typename T3, typename T4>
+inline typename m_Intrinsic_Ty<T0, T1, T2, T3, T4>::Ty
+m_GIntrinsic(const T0 &Op0, const T1 &Op1, const T2 &Op2, const T3 &Op3,
+ const T4 &Op4) {
+ return m_CombineAnd(m_GIntrinsic<IntrID>(Op0, Op1, Op2, Op3),
+ m_Argument<4>(Op4));
+}
+
+template <Intrinsic::ID IntrID, typename T0, typename T1, typename T2,
+ typename T3, typename T4, typename T5>
+inline typename m_Intrinsic_Ty<T0, T1, T2, T3, T4, T5>::Ty
+m_GIntrinsic(const T0 &Op0, const T1 &Op1, const T2 &Op2, const T3 &Op3,
+ const T4 &Op4, const T5 &Op5) {
+ return m_CombineAnd(m_GIntrinsic<IntrID>(Op0, Op1, Op2, Op3, Op4),
+ m_Argument<5>(Op5));
+}
+
} // namespace MIPatternMatch
} // namespace llvm
diff --git a/llvm/include/llvm/CodeGen/GlobalISel/Utils.h b/llvm/include/llvm/CodeGen/GlobalISel/Utils.h
index 44141844f42f4..f6101d5d589d2 100644
--- a/llvm/include/llvm/CodeGen/GlobalISel/Utils.h
+++ b/llvm/include/llvm/CodeGen/GlobalISel/Utils.h
@@ -183,6 +183,10 @@ std::optional<APInt> getIConstantVRegVal(Register VReg,
std::optional<int64_t> getIConstantVRegSExtVal(Register VReg,
const MachineRegisterInfo &MRI);
+/// If \p VReg is defined by a G_CONSTANT fits in uint64_t returns it.
+std::optional<uint64_t> getIConstantVRegZExtVal(Register VReg,
+ const MachineRegisterInfo &MRI);
+
/// \p VReg is defined by a G_CONSTANT, return the corresponding value.
const APInt &getIConstantFromReg(Register VReg, const MachineRegisterInfo &MRI);
@@ -438,6 +442,17 @@ std::optional<int64_t> getIConstantSplatSExtVal(const Register Reg,
std::optional<int64_t> getIConstantSplatSExtVal(const MachineInstr &MI,
const MachineRegisterInfo &MRI);
+/// \returns the scalar sign extended integral splat value of \p Reg if
+/// possible.
+std::optional<uint64_t>
+getIConstantSplatZExtVal(const Register Reg, const MachineRegisterInfo &MRI);
+
+/// \returns the scalar sign extended integral splat value defined by \p MI if
+/// possible.
+std::optional<uint64_t>
+getIConstantSplatZExtVal(const MachineInstr &MI,
+ const MachineRegisterInfo &MRI);
+
/// Returns a floating point scalar constant of a build vector splat if it
/// exists. When \p AllowUndef == true some elements can be undef but not all.
std::optional<FPValueAndVReg> getFConstantSplat(Register VReg,
@@ -654,6 +669,9 @@ class GIConstant {
/// }
/// provides low-level access.
class GFConstant {
+ using VecTy = SmallVector<APFloat>;
+ using const_iterator = VecTy::const_iterator;
+
public:
enum class GFConstantKind { Scalar, FixedVector, ScalableVector };
@@ -671,6 +689,23 @@ class GFConstant {
/// Returns the kind of of this constant, e.g, Scalar.
GFConstantKind getKind() const { return Kind; }
+ const_iterator begin() const {
+ assert(Kind != GFConstantKind::ScalableVector &&
+ "Expected fixed vector or scalar constant");
+ return Values.begin();
+ }
+
+ const_iterator end() const {
+ assert(Kind != GFConstantKind::ScalableVector &&
+ "Expected fixed vector or scalar constant");
+ return Values.end();
+ }
+
+ size_t size() const {
+ assert(Kind == GFConstantKind::FixedVector && "Expected fixed vector");
+ return Values.size();
+ }
+
/// Returns the value, if this constant is a scalar.
APFloat getScalarValue() const;
diff --git a/llvm/include/llvm/CodeGen/TargetLowering.h b/llvm/include/llvm/CodeGen/TargetLowering.h
index 16066226f1896..f339344704f34 100644
--- a/llvm/include/llvm/CodeGen/TargetLowering.h
+++ b/llvm/include/llvm/CodeGen/TargetLowering.h
@@ -51,6 +51,7 @@
#include "llvm/Support/AtomicOrdering.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/KnownFPClass.h"
#include <algorithm>
#include <cassert>
#include <climits>
@@ -4165,6 +4166,13 @@ class TargetLowering : public TargetLoweringBase {
const MachineRegisterInfo &MRI,
unsigned Depth = 0) const;
+ virtual void computeKnownFPClassForTargetInstr(GISelValueTracking &Analysis,
+ Register R,
+ KnownFPClass &Known,
+ const APInt &DemandedElts,
+ const MachineRegisterInfo &MRI,
+ unsigned Depth = 0) const;
+
/// Determine the known alig...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/134611
More information about the llvm-commits
mailing list