[llvm] [GISel] Add KnownFPClass Analysis to GISelValueTrackingPass (PR #134611)

Matt Arsenault via llvm-commits llvm-commits at lists.llvm.org
Tue May 13 03:03:33 PDT 2025


================
@@ -637,6 +653,1102 @@ void GISelValueTracking::computeKnownBitsImpl(Register R, KnownBits &Known,
   ComputeKnownBitsCache[R] = Known;
 }
 
+static bool outputDenormalIsIEEEOrPosZero(const MachineFunction &MF, LLT Ty) {
+  Ty = Ty.getScalarType();
+  DenormalMode Mode = MF.getDenormalMode(getFltSemanticForLLT(Ty));
+  return Mode.Output == DenormalMode::IEEE ||
+         Mode.Output == DenormalMode::PositiveZero;
+}
+
+std::pair<Register, FPClassTest> GISelValueTracking::fcmpToClassTest(
+    FCmpInst::Predicate Pred, const MachineFunction &MF, Register LHS,
+    const APFloat *ConstRHS, bool LookThroughSrc) {
+
+  auto [Src, ClassIfTrue, ClassIfFalse] =
+      fcmpImpliesClass(Pred, MF, LHS, *ConstRHS, LookThroughSrc);
+  if (Src && ClassIfTrue == ~ClassIfFalse)
+    return {Src, ClassIfTrue};
+
+  return {Register(), fcAllFlags};
+}
+
+std::tuple<Register, FPClassTest, FPClassTest>
+GISelValueTracking::fcmpImpliesClass(CmpInst::Predicate Pred,
+                                     const MachineFunction &MF, Register LHS,
+                                     FPClassTest RHSClass,
+                                     bool LookThroughSrc) {
+  auto LookThrough = [&](Register LHS, Register &Src) {
+    return LookThroughSrc && mi_match(LHS, MRI, m_GFabs(m_Reg(Src)));
+  };
+
+  auto ModeQuery = [&](Register LHS) {
+    LLT Ty = MRI.getType(LHS).getScalarType();
+    return MF.getDenormalMode(getFltSemanticForLLT(Ty));
+  };
+
+  return llvm::fcmpImpliesClass(Pred, ModeQuery, LHS, RHSClass, LookThrough);
+}
+
+std::tuple<Register, FPClassTest, FPClassTest>
+GISelValueTracking::fcmpImpliesClass(CmpInst::Predicate Pred,
+                                     const MachineFunction &MF, Register LHS,
+                                     const APFloat &ConstRHS,
+                                     bool LookThroughSrc) {
+  auto LookThrough = [&](Register LHS, Register &Src) {
+    return LookThroughSrc && mi_match(LHS, MRI, m_GFabs(m_Reg(Src)));
+  };
+
+  auto ModeQuery = [&](Register LHS) {
+    LLT Ty = MRI.getType(LHS).getScalarType();
+    return MF.getDenormalMode(getFltSemanticForLLT(Ty));
+  };
+
+  return llvm::fcmpImpliesClass(Pred, ModeQuery, LHS, ConstRHS, LookThrough);
+}
+
+std::tuple<Register, FPClassTest, FPClassTest>
+GISelValueTracking::fcmpImpliesClass(CmpInst::Predicate Pred,
+                                     const MachineFunction &MF, Register LHS,
+                                     Register RHS, bool LookThroughSrc) {
+
+  const ConstantFP *ConstRHS;
+  if (!mi_match(RHS, MRI, m_GFCst(ConstRHS)))
+    return {Register(), fcAllFlags, fcAllFlags};
+
+  auto LookThrough = [&](Register LHS, Register &Src) {
+    return LookThroughSrc && mi_match(LHS, MRI, m_GFabs(m_Reg(Src)));
+  };
+
+  auto ModeQuery = [&](Register LHS) {
+    LLT Ty = MRI.getType(LHS).getScalarType();
+    return MF.getDenormalMode(getFltSemanticForLLT(Ty));
+  };
+
+  // TODO: Just call computeKnownFPClass for RHS to handle non-constants.
+  return llvm::fcmpImpliesClass(Pred, ModeQuery, LHS, ConstRHS->getValueAPF(),
+                                LookThrough);
+}
+
+void GISelValueTracking::computeKnownFPClass(Register R, KnownFPClass &Known,
+                                             FPClassTest InterestedClasses,
+                                             unsigned Depth) {
+  LLT Ty = MRI.getType(R);
+  APInt DemandedElts =
+      Ty.isFixedVector() ? APInt::getAllOnes(Ty.getNumElements()) : APInt(1, 1);
+  computeKnownFPClass(R, DemandedElts, InterestedClasses, Known, Depth);
+}
+
+void GISelValueTracking::computeKnownFPClassForFPTrunc(
+    const MachineInstr &MI, const APInt &DemandedElts,
+    FPClassTest InterestedClasses, KnownFPClass &Known, unsigned Depth) {
+  if ((InterestedClasses & (KnownFPClass::OrderedLessThanZeroMask | fcNan)) ==
+      fcNone)
+    return;
+
+  Register Val = MI.getOperand(1).getReg();
+  KnownFPClass KnownSrc;
+  computeKnownFPClass(Val, DemandedElts, InterestedClasses, KnownSrc,
+                      Depth + 1);
+
+  // Sign should be preserved
+  // TODO: Handle cannot be ordered greater than zero
+  if (KnownSrc.cannotBeOrderedLessThanZero())
+    Known.knownNot(KnownFPClass::OrderedLessThanZeroMask);
+
+  Known.propagateNaN(KnownSrc, true);
+
+  // Infinity needs a range check.
+}
+
+void GISelValueTracking::computeKnownFPClass(Register R,
+                                             const APInt &DemandedElts,
+                                             FPClassTest InterestedClasses,
+                                             KnownFPClass &Known,
+                                             unsigned Depth) {
+  assert(Known.isUnknown() && "should not be called with known information");
+
+  if (!DemandedElts) {
+    // No demanded elts, better to assume we don't know anything.
+    Known.resetAll();
+    return;
+  }
+
+  assert(Depth <= MaxAnalysisRecursionDepth && "Limit Search Depth");
+
+  MachineInstr &MI = *MRI.getVRegDef(R);
+  unsigned Opcode = MI.getOpcode();
+  LLT DstTy = MRI.getType(R);
+
+  if (!DstTy.isValid()) {
+    Known.resetAll();
+    return;
+  }
+
+  if (auto Cst = GFConstant::getConstant(R, MRI)) {
+    switch (Cst->getKind()) {
+    case GFConstant::GFConstantKind::Scalar: {
+      auto APF = Cst->getScalarValue();
+      Known.KnownFPClasses = APF.classify();
+      Known.SignBit = APF.isNegative();
+      break;
+    }
+    case GFConstant::GFConstantKind::FixedVector: {
+      Known.KnownFPClasses = fcNone;
+      bool SignBitAllZero = true;
+      bool SignBitAllOne = true;
+
+      for (auto C : *Cst) {
+        Known.KnownFPClasses |= C.classify();
+        if (C.isNegative())
+          SignBitAllZero = false;
+        else
+          SignBitAllOne = false;
+      }
+
+      if (SignBitAllOne != SignBitAllZero)
+        Known.SignBit = SignBitAllOne;
+
+      break;
+    }
+    case GFConstant::GFConstantKind::ScalableVector: {
+      Known.resetAll();
+      break;
+    }
+    }
+
+    return;
+  }
+
+  FPClassTest KnownNotFromFlags = fcNone;
+  if (MI.getFlag(MachineInstr::MIFlag::FmNoNans))
+    KnownNotFromFlags |= fcNan;
+  if (MI.getFlag(MachineInstr::MIFlag::FmNoInfs))
+    KnownNotFromFlags |= fcInf;
+
+  // We no longer need to find out about these bits from inputs if we can
+  // assume this from flags/attributes.
+  InterestedClasses &= ~KnownNotFromFlags;
+
+  auto ClearClassesFromFlags =
+      make_scope_exit([=, &Known] { Known.knownNot(KnownNotFromFlags); });
+
+  // All recursive calls that increase depth must come after this.
+  if (Depth == MaxAnalysisRecursionDepth)
+    return;
+
+  // auto CacheEntry = ComputeKnownFPClassCache.find(R);
+  // if (CacheEntry != ComputeKnownFPClassCache.end()) {
+  //   Known = CacheEntry->second;
+  //   LLVM_DEBUG(dbgs() << "Cache hit at ");
+  //   // LLVM_DEBUG(dumpResult(MI, Known, Depth));
+  //   // assert(Known.getBitWidth() == BitWidth && "Cache entry size doesn't
+  //   match"); return;
+  // }
----------------
arsenm wrote:

Commented out debug printing 

https://github.com/llvm/llvm-project/pull/134611


More information about the llvm-commits mailing list