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

Code before:
      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
  // synthesizing norecurse and so we can only save the singular SCCs as SCCs
  // with multiple functions in them will clearly be recursive.

  SmallVector<Function *, 16> Worklist;
  CG.buildRefSCCs();
  for (LazyCallGraph::RefSCC &RC : CG.postorder_ref_sccs()) {
    for (LazyCallGraph::SCC &SCC : RC) {
      if (SCC.size() != 1)
        continue;
      Function &F = SCC.begin()->getFunction();
      if (!F.isDeclaration() && F.hasInternalLinkage())
        Worklist.push_back(&F);
    }

Review comment (suggestion):
```suggestion
    F.addParamAttr(I, Attribute::getWithNoFPClass(Ctx, ArgNoFPClass));
```

Code after:
    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;
  }

  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
  // synthesizing norecurse and so we can only save the singular SCCs as SCCs
  // with multiple functions in them will clearly be recursive.

  SmallVector<Function *, 16> Worklist;