1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-10-18 18:42:46 +02:00

[NewPM][Lint] Port -lint to NewPM

This also changes -lint from an analysis to a pass. It's similar to
-verify, and that is a normal pass, and lives in llvm/IR.

Reviewed By: ychen

Differential Revision: https://reviews.llvm.org/D87057
This commit is contained in:
Arthur Eubanks 2020-09-02 21:54:27 -07:00
parent c65dfd8c46
commit 9f8be8e69b
8 changed files with 174 additions and 147 deletions

View File

@ -19,30 +19,30 @@
#ifndef LLVM_ANALYSIS_LINT_H
#define LLVM_ANALYSIS_LINT_H
#include "llvm/IR/PassManager.h"
namespace llvm {
class FunctionPass;
class Module;
class Function;
/// Create a lint pass.
///
/// Check a module or function.
FunctionPass *createLintPass();
FunctionPass *createLintLegacyPassPass();
/// Check a module.
/// Lint a module.
///
/// This should only be used for debugging, because it plays games with
/// PassManagers and stuff.
void lintModule(
const Module &M ///< The module to be checked
);
void lintModule(const Module &M);
// lintFunction - Check a function.
void lintFunction(
const Function &F ///< The function to be checked
);
// Lint a function.
void lintFunction(const Function &F);
} // End llvm namespace
class LintPass : public PassInfoMixin<LintPass> {
public:
PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM);
};
#endif
} // namespace llvm
#endif // LLVM_ANALYSIS_LINT_H

View File

@ -218,7 +218,7 @@ void initializeLegalizerPass(PassRegistry&);
void initializeGISelCSEAnalysisWrapperPassPass(PassRegistry &);
void initializeGISelKnownBitsAnalysisPass(PassRegistry &);
void initializeLibCallsShrinkWrapLegacyPassPass(PassRegistry&);
void initializeLintPass(PassRegistry&);
void initializeLintLegacyPassPass(PassRegistry &);
void initializeLiveDebugValuesPass(PassRegistry&);
void initializeLiveDebugVariablesPass(PassRegistry&);
void initializeLiveIntervalsPass(PassRegistry&);

View File

@ -203,7 +203,7 @@ namespace {
(void) llvm::createPrintFunctionPass(os);
(void) llvm::createModuleDebugInfoPrinterPass();
(void) llvm::createPartialInliningPass();
(void) llvm::createLintPass();
(void) llvm::createLintLegacyPassPass();
(void) llvm::createSinkingPass();
(void) llvm::createLowerAtomicPass();
(void) llvm::createCorrelatedValuePropagationPass();

View File

@ -57,7 +57,7 @@ void llvm::initializeAnalysis(PassRegistry &Registry) {
initializeLazyValueInfoWrapperPassPass(Registry);
initializeLazyValueInfoPrinterPass(Registry);
initializeLegacyDivergenceAnalysisPass(Registry);
initializeLintPass(Registry);
initializeLintLegacyPassPass(Registry);
initializeLoopInfoWrapperPassPass(Registry);
initializeMemDepPrinterPass(Registry);
initializeMemDerefPrinterPass(Registry);

View File

@ -63,6 +63,7 @@
#include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/PassManager.h"
#include "llvm/IR/Type.h"
#include "llvm/IR/Value.h"
#include "llvm/InitializePasses.h"
@ -80,134 +81,102 @@
using namespace llvm;
namespace {
namespace MemRef {
static const unsigned Read = 1;
static const unsigned Write = 2;
static const unsigned Callee = 4;
static const unsigned Branchee = 8;
} // end namespace MemRef
namespace MemRef {
static const unsigned Read = 1;
static const unsigned Write = 2;
static const unsigned Callee = 4;
static const unsigned Branchee = 8;
} // end namespace MemRef
class Lint : public FunctionPass, public InstVisitor<Lint> {
friend class InstVisitor<Lint>;
class Lint : public InstVisitor<Lint> {
friend class InstVisitor<Lint>;
void visitFunction(Function &F);
void visitFunction(Function &F);
void visitCallBase(CallBase &CB);
void visitMemoryReference(Instruction &I, Value *Ptr, uint64_t Size,
MaybeAlign Alignment, Type *Ty, unsigned Flags);
void visitEHBeginCatch(IntrinsicInst *II);
void visitEHEndCatch(IntrinsicInst *II);
void visitCallBase(CallBase &CB);
void visitMemoryReference(Instruction &I, Value *Ptr, uint64_t Size,
MaybeAlign Alignment, Type *Ty, unsigned Flags);
void visitEHBeginCatch(IntrinsicInst *II);
void visitEHEndCatch(IntrinsicInst *II);
void visitReturnInst(ReturnInst &I);
void visitLoadInst(LoadInst &I);
void visitStoreInst(StoreInst &I);
void visitXor(BinaryOperator &I);
void visitSub(BinaryOperator &I);
void visitLShr(BinaryOperator &I);
void visitAShr(BinaryOperator &I);
void visitShl(BinaryOperator &I);
void visitSDiv(BinaryOperator &I);
void visitUDiv(BinaryOperator &I);
void visitSRem(BinaryOperator &I);
void visitURem(BinaryOperator &I);
void visitAllocaInst(AllocaInst &I);
void visitVAArgInst(VAArgInst &I);
void visitIndirectBrInst(IndirectBrInst &I);
void visitExtractElementInst(ExtractElementInst &I);
void visitInsertElementInst(InsertElementInst &I);
void visitUnreachableInst(UnreachableInst &I);
void visitReturnInst(ReturnInst &I);
void visitLoadInst(LoadInst &I);
void visitStoreInst(StoreInst &I);
void visitXor(BinaryOperator &I);
void visitSub(BinaryOperator &I);
void visitLShr(BinaryOperator &I);
void visitAShr(BinaryOperator &I);
void visitShl(BinaryOperator &I);
void visitSDiv(BinaryOperator &I);
void visitUDiv(BinaryOperator &I);
void visitSRem(BinaryOperator &I);
void visitURem(BinaryOperator &I);
void visitAllocaInst(AllocaInst &I);
void visitVAArgInst(VAArgInst &I);
void visitIndirectBrInst(IndirectBrInst &I);
void visitExtractElementInst(ExtractElementInst &I);
void visitInsertElementInst(InsertElementInst &I);
void visitUnreachableInst(UnreachableInst &I);
Value *findValue(Value *V, bool OffsetOk) const;
Value *findValueImpl(Value *V, bool OffsetOk,
SmallPtrSetImpl<Value *> &Visited) const;
Value *findValue(Value *V, bool OffsetOk) const;
Value *findValueImpl(Value *V, bool OffsetOk,
SmallPtrSetImpl<Value *> &Visited) const;
public:
Module *Mod;
const DataLayout *DL;
AliasAnalysis *AA;
AssumptionCache *AC;
DominatorTree *DT;
TargetLibraryInfo *TLI;
public:
Module *Mod;
const DataLayout *DL;
AliasAnalysis *AA;
AssumptionCache *AC;
DominatorTree *DT;
TargetLibraryInfo *TLI;
std::string Messages;
raw_string_ostream MessagesStr;
std::string Messages;
raw_string_ostream MessagesStr;
static char ID; // Pass identification, replacement for typeid
Lint() : FunctionPass(ID), MessagesStr(Messages) {
initializeLintPass(*PassRegistry::getPassRegistry());
}
Lint(Module *Mod, const DataLayout *DL, AliasAnalysis *AA,
AssumptionCache *AC, DominatorTree *DT, TargetLibraryInfo *TLI)
: Mod(Mod), DL(DL), AA(AA), AC(AC), DT(DT), TLI(TLI),
MessagesStr(Messages) {}
bool runOnFunction(Function &F) override;
void getAnalysisUsage(AnalysisUsage &AU) const override {
AU.setPreservesAll();
AU.addRequired<AAResultsWrapperPass>();
AU.addRequired<AssumptionCacheTracker>();
AU.addRequired<TargetLibraryInfoWrapperPass>();
AU.addRequired<DominatorTreeWrapperPass>();
}
void print(raw_ostream &O, const Module *M) const override {}
void WriteValues(ArrayRef<const Value *> Vs) {
for (const Value *V : Vs) {
if (!V)
continue;
if (isa<Instruction>(V)) {
MessagesStr << *V << '\n';
} else {
V->printAsOperand(MessagesStr, true, Mod);
MessagesStr << '\n';
}
void WriteValues(ArrayRef<const Value *> Vs) {
for (const Value *V : Vs) {
if (!V)
continue;
if (isa<Instruction>(V)) {
MessagesStr << *V << '\n';
} else {
V->printAsOperand(MessagesStr, true, Mod);
MessagesStr << '\n';
}
}
}
/// A check failed, so printout out the condition and the message.
///
/// This provides a nice place to put a breakpoint if you want to see why
/// something is not correct.
void CheckFailed(const Twine &Message) { MessagesStr << Message << '\n'; }
/// A check failed, so printout out the condition and the message.
///
/// This provides a nice place to put a breakpoint if you want to see why
/// something is not correct.
void CheckFailed(const Twine &Message) { MessagesStr << Message << '\n'; }
/// A check failed (with values to print).
///
/// This calls the Message-only version so that the above is easier to set
/// a breakpoint on.
template <typename T1, typename... Ts>
void CheckFailed(const Twine &Message, const T1 &V1, const Ts &...Vs) {
CheckFailed(Message);
WriteValues({V1, Vs...});
}
};
/// A check failed (with values to print).
///
/// This calls the Message-only version so that the above is easier to set
/// a breakpoint on.
template <typename T1, typename... Ts>
void CheckFailed(const Twine &Message, const T1 &V1, const Ts &... Vs) {
CheckFailed(Message);
WriteValues({V1, Vs...});
}
};
} // end anonymous namespace
char Lint::ID = 0;
INITIALIZE_PASS_BEGIN(Lint, "lint", "Statically lint-checks LLVM IR",
false, true)
INITIALIZE_PASS_DEPENDENCY(AssumptionCacheTracker)
INITIALIZE_PASS_DEPENDENCY(TargetLibraryInfoWrapperPass)
INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)
INITIALIZE_PASS_DEPENDENCY(AAResultsWrapperPass)
INITIALIZE_PASS_END(Lint, "lint", "Statically lint-checks LLVM IR",
false, true)
// Assert - We know that cond should be true, if not print an error message.
#define Assert(C, ...) \
do { if (!(C)) { CheckFailed(__VA_ARGS__); return; } } while (false)
// Lint::run - This is the main Analysis entry point for a
// function.
//
bool Lint::runOnFunction(Function &F) {
Mod = F.getParent();
DL = &F.getParent()->getDataLayout();
AA = &getAnalysis<AAResultsWrapperPass>().getAAResults();
AC = &getAnalysis<AssumptionCacheTracker>().getAssumptionCache(F);
DT = &getAnalysis<DominatorTreeWrapperPass>().getDomTree();
TLI = &getAnalysis<TargetLibraryInfoWrapperPass>().getTLI(F);
visit(F);
dbgs() << MessagesStr.str();
Messages.clear();
return false;
}
#define Assert(C, ...) \
do { \
if (!(C)) { \
CheckFailed(__VA_ARGS__); \
return; \
} \
} while (false)
void Lint::visitFunction(Function &F) {
// This isn't undefined behavior, it's just a little unusual, and it's a
@ -281,8 +250,7 @@ void Lint::visitCallBase(CallBase &I) {
// Check that an sret argument points to valid memory.
if (Formal->hasStructRetAttr() && Actual->getType()->isPointerTy()) {
Type *Ty =
cast<PointerType>(Formal->getType())->getElementType();
Type *Ty = cast<PointerType>(Formal->getType())->getElementType();
visitMemoryReference(I, Actual, DL->getTypeStoreSize(Ty),
DL->getABITypeAlign(Ty), Ty,
MemRef::Read | MemRef::Write);
@ -309,12 +277,12 @@ void Lint::visitCallBase(CallBase &I) {
}
}
if (IntrinsicInst *II = dyn_cast<IntrinsicInst>(&I))
switch (II->getIntrinsicID()) {
default: break;
default:
break;
// TODO: Check more intrinsics
// TODO: Check more intrinsics
case Intrinsic::memcpy: {
MemCpyInst *MCI = cast<MemCpyInst>(&I);
@ -553,7 +521,8 @@ static bool isZero(Value *V, const DataLayout &DL, DominatorTree *DT,
VectorType *VecTy = dyn_cast<VectorType>(V->getType());
if (!VecTy) {
KnownBits Known = computeKnownBits(V, DL, 0, AC, dyn_cast<Instruction>(V), DT);
KnownBits Known =
computeKnownBits(V, DL, 0, AC, dyn_cast<Instruction>(V), DT);
return Known.isZero();
}
@ -682,11 +651,13 @@ Value *Lint::findValueImpl(Value *V, bool OffsetOk,
if (!VisitedBlocks.insert(BB).second)
break;
if (Value *U =
FindAvailableLoadedValue(L, BB, BBI, DefMaxInstsToScan, AA))
FindAvailableLoadedValue(L, BB, BBI, DefMaxInstsToScan, AA))
return findValueImpl(U, OffsetOk, Visited);
if (BBI != BB->begin()) break;
if (BBI != BB->begin())
break;
BB = BB->getUniquePredecessor();
if (!BB) break;
if (!BB)
break;
BBI = BB->end();
}
} else if (PHINode *PN = dyn_cast<PHINode>(V)) {
@ -696,8 +667,8 @@ Value *Lint::findValueImpl(Value *V, bool OffsetOk,
if (CI->isNoopCast(*DL))
return findValueImpl(CI->getOperand(0), OffsetOk, Visited);
} else if (ExtractValueInst *Ex = dyn_cast<ExtractValueInst>(V)) {
if (Value *W = FindInsertedValue(Ex->getAggregateOperand(),
Ex->getIndices()))
if (Value *W =
FindInsertedValue(Ex->getAggregateOperand(), Ex->getIndices()))
if (W != V)
return findValueImpl(W, OffsetOk, Visited);
} else if (ConstantExpr *CE = dyn_cast<ConstantExpr>(V)) {
@ -728,22 +699,75 @@ Value *Lint::findValueImpl(Value *V, bool OffsetOk,
return V;
}
PreservedAnalyses LintPass::run(Function &F, FunctionAnalysisManager &AM) {
auto *Mod = F.getParent();
auto *DL = &F.getParent()->getDataLayout();
auto *AA = &AM.getResult<AAManager>(F);
auto *AC = &AM.getResult<AssumptionAnalysis>(F);
auto *DT = &AM.getResult<DominatorTreeAnalysis>(F);
auto *TLI = &AM.getResult<TargetLibraryAnalysis>(F);
Lint L(Mod, DL, AA, AC, DT, TLI);
L.visit(F);
dbgs() << L.MessagesStr.str();
return PreservedAnalyses::all();
}
class LintLegacyPass : public FunctionPass {
public:
static char ID; // Pass identification, replacement for typeid
LintLegacyPass() : FunctionPass(ID) {
initializeLintLegacyPassPass(*PassRegistry::getPassRegistry());
}
bool runOnFunction(Function &F) override;
void getAnalysisUsage(AnalysisUsage &AU) const override {
AU.setPreservesAll();
AU.addRequired<AAResultsWrapperPass>();
AU.addRequired<AssumptionCacheTracker>();
AU.addRequired<TargetLibraryInfoWrapperPass>();
AU.addRequired<DominatorTreeWrapperPass>();
}
void print(raw_ostream &O, const Module *M) const override {}
};
char LintLegacyPass::ID = 0;
INITIALIZE_PASS_BEGIN(LintLegacyPass, "lint", "Statically lint-checks LLVM IR",
false, true)
INITIALIZE_PASS_DEPENDENCY(AssumptionCacheTracker)
INITIALIZE_PASS_DEPENDENCY(TargetLibraryInfoWrapperPass)
INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)
INITIALIZE_PASS_DEPENDENCY(AAResultsWrapperPass)
INITIALIZE_PASS_END(LintLegacyPass, "lint", "Statically lint-checks LLVM IR",
false, true)
bool LintLegacyPass::runOnFunction(Function &F) {
auto *Mod = F.getParent();
auto *DL = &F.getParent()->getDataLayout();
auto *AA = &getAnalysis<AAResultsWrapperPass>().getAAResults();
auto *AC = &getAnalysis<AssumptionCacheTracker>().getAssumptionCache(F);
auto *DT = &getAnalysis<DominatorTreeWrapperPass>().getDomTree();
auto *TLI = &getAnalysis<TargetLibraryInfoWrapperPass>().getTLI(F);
Lint L(Mod, DL, AA, AC, DT, TLI);
L.visit(F);
dbgs() << L.MessagesStr.str();
return false;
}
//===----------------------------------------------------------------------===//
// Implement the public interfaces to this file...
//===----------------------------------------------------------------------===//
FunctionPass *llvm::createLintPass() {
return new Lint();
}
FunctionPass *llvm::createLintLegacyPassPass() { return new LintLegacyPass(); }
/// lintFunction - Check a function for errors, printing messages on stderr.
///
void llvm::lintFunction(const Function &f) {
Function &F = const_cast<Function&>(f);
Function &F = const_cast<Function &>(f);
assert(!F.isDeclaration() && "Cannot lint external functions");
legacy::FunctionPassManager FPM(F.getParent());
Lint *V = new Lint();
auto *V = new LintLegacyPass();
FPM.add(V);
FPM.run(F);
}
@ -752,7 +776,7 @@ void llvm::lintFunction(const Function &f) {
///
void llvm::lintModule(const Module &M) {
legacy::PassManager PM;
Lint *V = new Lint();
auto *V = new LintLegacyPass();
PM.add(V);
PM.run(const_cast<Module&>(M));
PM.run(const_cast<Module &>(M));
}

View File

@ -39,6 +39,7 @@
#include "llvm/Analysis/InstCount.h"
#include "llvm/Analysis/LazyCallGraph.h"
#include "llvm/Analysis/LazyValueInfo.h"
#include "llvm/Analysis/Lint.h"
#include "llvm/Analysis/LoopAccessAnalysis.h"
#include "llvm/Analysis/LoopCacheAnalysis.h"
#include "llvm/Analysis/LoopInfo.h"

View File

@ -205,6 +205,7 @@ FUNCTION_PASS("irce", IRCEPass())
FUNCTION_PASS("float2int", Float2IntPass())
FUNCTION_PASS("no-op-function", NoOpFunctionPass())
FUNCTION_PASS("libcalls-shrinkwrap", LibCallsShrinkWrapPass())
FUNCTION_PASS("lint", LintPass())
FUNCTION_PASS("inject-tli-mappings", InjectTLIMappings())
FUNCTION_PASS("loweratomic", LowerAtomicPass())
FUNCTION_PASS("lower-expect", LowerExpectIntrinsicPass())

View File

@ -1,4 +1,5 @@
; RUN: opt -basic-aa -lint -disable-output < %s 2>&1 | FileCheck %s
; RUN: opt -aa-pipeline=basic-aa -passes=lint -disable-output < %s 2>&1 | FileCheck %s
target datalayout = "e-p:64:64:64"
declare fastcc void @bar()