[NFC] Move a recently added utility into a location to enable reuse

About to refresh a patch that uses this in FunctionAtrrs, doing the move seperately to control build times.
This commit is contained in:
Philip Reames 2021-04-14 15:05:16 -07:00
parent 61a85da882
commit 3ce61fb6d6
3 changed files with 44 additions and 36 deletions

View File

@ -488,6 +488,15 @@ bool canReplaceOperandWithVariable(const Instruction *I, unsigned OpIdx);
/// Invert the given true/false value, possibly reusing an existing copy. /// Invert the given true/false value, possibly reusing an existing copy.
Value *invertCondition(Value *Condition); Value *invertCondition(Value *Condition);
//===----------------------------------------------------------------------===//
// Assorted
//
/// If we can infer one attribute from another on the declaration of a
/// function, explicitly materialize the maximal set in the IR.
bool inferAttributesFromOthers(Function &F);
} // end namespace llvm } // end namespace llvm
#endif // LLVM_TRANSFORMS_UTILS_LOCAL_H #endif // LLVM_TRANSFORMS_UTILS_LOCAL_H

View File

@ -15,52 +15,21 @@
#include "llvm/Support/Debug.h" #include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h" #include "llvm/Support/raw_ostream.h"
#include "llvm/Transforms/Utils/BuildLibCalls.h" #include "llvm/Transforms/Utils/BuildLibCalls.h"
#include "llvm/Transforms/Utils/Local.h"
using namespace llvm; using namespace llvm;
#define DEBUG_TYPE "inferattrs" #define DEBUG_TYPE "inferattrs"
/// If we can infer one attribute from another on the declaration of a
/// function, explicitly materialize the maximal set for readability in the IR.
/// Doing this also allows our CGSCC inference to avoid needing to duplicate
/// this logic on all calls to declarations (as declarations aren't explicitly
/// visited by CGSCC passes in the new pass manager.)
static bool inferAttributesFromOthers(Function &F) {
// Note: We explicitly check for attributes rather than using cover functions
// because some of the cover functions include the logic being implemented.
bool Changed = false;
// readnone + not convergent implies nosync
if (!F.hasFnAttribute(Attribute::NoSync) &&
F.doesNotAccessMemory() && !F.isConvergent()) {
F.setNoSync();
Changed = true;
}
// readonly implies nofree
if (!F.hasFnAttribute(Attribute::NoFree) && F.onlyReadsMemory()) {
F.setDoesNotFreeMemory();
Changed = true;
}
// willreturn implies mustprogress
if (!F.hasFnAttribute(Attribute::MustProgress) && F.willReturn()) {
F.setMustProgress();
Changed = true;
}
// TODO: There are a bunch of cases of restrictive memory effects we
// can infer by inspecting arguments of argmemonly-ish functions.
return Changed;
}
static bool inferAllPrototypeAttributes( static bool inferAllPrototypeAttributes(
Module &M, function_ref<TargetLibraryInfo &(Function &)> GetTLI) { Module &M, function_ref<TargetLibraryInfo &(Function &)> GetTLI) {
bool Changed = false; bool Changed = false;
for (Function &F : M.functions()) for (Function &F : M.functions())
// We only infer things using the prototype and the name; we don't need // We only infer things using the prototype and the name; we don't need
// definitions. // definitions. This ensures libfuncs are annotated and also allows our
// CGSCC inference to avoid needing to duplicate the inference from other
// attribute logic on all calls to declarations (as declarations aren't
// explicitly visited by CGSCC passes in the new pass manager.)
if (F.isDeclaration() && !F.hasOptNone()) { if (F.isDeclaration() && !F.hasOptNone()) {
Changed |= inferLibFuncAttributes(F, GetTLI(F)); Changed |= inferLibFuncAttributes(F, GetTLI(F));
Changed |= inferAttributesFromOthers(F); Changed |= inferAttributesFromOthers(F);

View File

@ -3392,3 +3392,33 @@ Value *llvm::invertCondition(Value *Condition) {
Inverted->insertBefore(&*Parent->getFirstInsertionPt()); Inverted->insertBefore(&*Parent->getFirstInsertionPt());
return Inverted; return Inverted;
} }
bool llvm::inferAttributesFromOthers(Function &F) {
// Note: We explicitly check for attributes rather than using cover functions
// because some of the cover functions include the logic being implemented.
bool Changed = false;
// readnone + not convergent implies nosync
if (!F.hasFnAttribute(Attribute::NoSync) &&
F.doesNotAccessMemory() && !F.isConvergent()) {
F.setNoSync();
Changed = true;
}
// readonly implies nofree
if (!F.hasFnAttribute(Attribute::NoFree) && F.onlyReadsMemory()) {
F.setDoesNotFreeMemory();
Changed = true;
}
// willreturn implies mustprogress
if (!F.hasFnAttribute(Attribute::MustProgress) && F.willReturn()) {
F.setMustProgress();
Changed = true;
}
// TODO: There are a bunch of cases of restrictive memory effects we
// can infer by inspecting arguments of argmemonly-ish functions.
return Changed;
}