Repository: llvm/llvm-project
File: llvm/lib/Transforms/IPO/FunctionAttrs.cpp (C++)

Code before:
  return true;
}

static bool addNoFPClassAttrsTopDown(Function &F) {
  assert(!F.isDeclaration() && "Cannot deduce nofpclass without a definition!");
  unsigned NumArgs = F.arg_size();
  SmallVector<FPClassTest, 8> ArgsNoFPClass(NumArgs, fcAllFlags);
  FPClassTest RetNoFPClass = fcAllFlags;

  bool Changed = false;
  for (User *U : F.users()) {
    auto *CB = dyn_cast<CallBase>(U);
    if (!CB || CB->getCalledFunction() != &F)
      return false;

    RetNoFPClass &= CB->getRetNoFPClass();
    for (unsigned I = 0; I != NumArgs; ++I)
      ArgsNoFPClass[I] &= CB->getParamNoFPClass(I);
  }

  LLVMContext &Ctx = F.getContext();

  if (RetNoFPClass != fcNone) {
    FPClassTest OldAttr = F.getAttributes().getRetNoFPClass();
    if (OldAttr != RetNoFPClass) {
      F.addRetAttr(Attribute::getWithNoFPClass(Ctx, RetNoFPClass | OldAttr));
      Changed = true;
    }
  }

  for (unsigned I = 0; I != NumArgs; ++I) {
    FPClassTest ArgNoFPClass = ArgsNoFPClass[I];
    if (ArgNoFPClass == fcNone)
      continue;
    FPClassTest OldAttr = F.getParamNoFPClass(I);
    if (OldAttr == ArgNoFPClass)
      continue;

    F.addParamAttr(I, Attribute::getWithNoFPClass(Ctx, ArgNoFPClass | OldAttr));
    Changed = true;
  }

  return Changed;
}

static bool deduceFunctionAttributeInRPO(Module &M, LazyCallGraph &CG) {
  // We only have a post-order SCC traversal (because SCCs are inherently
  // discovered in post-order), so we accumulate them in a vector and then walk
  // it in reverse. This is simpler than using the RPO iterator infrastructure
  // because we need to combine SCC detection and the PO walk of the call
  // graph. We can also cheat egregiously because we're primarily interested in

Review comment (suggestion):
IIRC RetNoFPClass is never the proper subset of OldAttr.
```suggestion
      F.addRetAttr(Attribute::getWithNoFPClass(Ctx, RetNoFPClass));
```

Code after:
  F.setDoesNotRecurse();
  ++NumNoRecurse;
  return true;
}

static bool addNoFPClassAttrsTopDown(Function &F) {
  assert(!F.isDeclaration() && "Cannot deduce nofpclass without a definition!");
  unsigned NumArgs = F.arg_size();
  SmallVector<FPClassTest, 8> ArgsNoFPClass(NumArgs, fcAllFlags);
  FPClassTest RetNoFPClass = fcAllFlags;

  bool Changed = false;
  for (User *U : F.users()) {
    auto *CB = dyn_cast<CallBase>(U);
    if (!CB || CB->getCalledFunction() != &F)
      return false;

    RetNoFPClass &= CB->getRetNoFPClass();
    for (unsigned I = 0; I != NumArgs; ++I) {
      // TODO: Consider computeKnownFPClass, at least with a small search
      // depth. This will currently not catch non-splat vectors.
      const APFloat *Cst;
      if (match(CB->getArgOperand(I), m_APFloat(Cst)))
        ArgsNoFPClass[I] &= ~Cst->classify();
      else
        ArgsNoFPClass[I] &= CB->getParamNoFPClass(I);
    }
  }

  LLVMContext &Ctx = F.getContext();

  if (RetNoFPClass != fcNone) {
    FPClassTest OldAttr = F.getAttributes().getRetNoFPClass();
    if (OldAttr != RetNoFPClass) {
      F.addRetAttr(Attribute::getWithNoFPClass(Ctx, RetNoFPClass));
      Changed = true;
    }
  }

  for (unsigned I = 0; I != NumArgs; ++I) {
    FPClassTest ArgNoFPClass = ArgsNoFPClass[I];
    if (ArgNoFPClass == fcNone)
      continue;
    FPClassTest OldAttr = F.getParamNoFPClass(I);
    if (OldAttr == ArgNoFPClass)
      continue;

    F.addParamAttr(I, Attribute::getWithNoFPClass(Ctx, ArgNoFPClass));
    Changed = true;
  }