summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--llvm/include/llvm/IR/Function.h5
-rw-r--r--llvm/include/llvm/IR/LegacyPassManagers.h9
-rw-r--r--llvm/include/llvm/IR/Module.h5
-rw-r--r--llvm/lib/Analysis/CallGraphSCCPass.cpp6
-rw-r--r--llvm/lib/Analysis/LoopPass.cpp4
-rw-r--r--llvm/lib/IR/Function.cpp8
-rw-r--r--llvm/lib/IR/LegacyPassManager.cpp69
-rw-r--r--llvm/lib/IR/Module.cpp7
-rw-r--r--llvm/test/Other/size-remarks.ll164
9 files changed, 273 insertions, 4 deletions
diff --git a/llvm/include/llvm/IR/Function.h b/llvm/include/llvm/IR/Function.h
index 3fa96df2c86..029172e7ba8 100644
--- a/llvm/include/llvm/IR/Function.h
+++ b/llvm/include/llvm/IR/Function.h
@@ -141,6 +141,11 @@ public:
// Provide fast operand accessors.
DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value);
+ /// Returns the number of non-debug IR instructions in this function.
+ /// This is equivalent to the sum of the sizes of each basic block contained
+ /// within this function.
+ unsigned getInstructionCount();
+
/// Returns the FunctionType for me.
FunctionType *getFunctionType() const {
return cast<FunctionType>(getValueType());
diff --git a/llvm/include/llvm/IR/LegacyPassManagers.h b/llvm/include/llvm/IR/LegacyPassManagers.h
index 3dc4a776dba..90036c6ce24 100644
--- a/llvm/include/llvm/IR/LegacyPassManagers.h
+++ b/llvm/include/llvm/IR/LegacyPassManagers.h
@@ -403,6 +403,15 @@ public:
InheritedAnalysis[Index++] = (*I)->getAvailableAnalysis();
}
+ /// Set the initial size of the module if the user has specified that they
+ /// want remarks for size.
+ /// Returns 0 if the remark was not requested.
+ unsigned initSizeRemarkInfo(Module &M);
+
+ /// Emit a remark signifying that the number of IR instructions in the module
+ /// changed.
+ void emitInstrCountChangedRemark(Pass *P, Module &M, unsigned CountBefore);
+
protected:
// Top level manager.
PMTopLevelManager *TPM;
diff --git a/llvm/include/llvm/IR/Module.h b/llvm/include/llvm/IR/Module.h
index 0d1265d0753..500e3a50dee 100644
--- a/llvm/include/llvm/IR/Module.h
+++ b/llvm/include/llvm/IR/Module.h
@@ -207,6 +207,11 @@ public:
/// @returns the module identifier as a string
const std::string &getModuleIdentifier() const { return ModuleID; }
+ /// Returns the number of non-debug IR instructions in the module.
+ /// This is equivalent to the sum of the IR instruction counts of each
+ /// function contained in the module.
+ unsigned getInstructionCount();
+
/// Get the module's original source file name. When compiling from
/// bitcode, this is taken from a bitcode record where it was recorded.
/// For other compiles it is the same as the ModuleID, which would
diff --git a/llvm/lib/Analysis/CallGraphSCCPass.cpp b/llvm/lib/Analysis/CallGraphSCCPass.cpp
index 4bb181e352d..ef61c65463f 100644
--- a/llvm/lib/Analysis/CallGraphSCCPass.cpp
+++ b/llvm/lib/Analysis/CallGraphSCCPass.cpp
@@ -120,6 +120,7 @@ bool CGPassManager::RunPassOnSCC(Pass *P, CallGraphSCC &CurSCC,
bool &DevirtualizedCall) {
bool Changed = false;
PMDataManager *PM = P->getAsPMDataManager();
+ Module &M = CG.getModule();
if (!PM) {
CallGraphSCCPass *CGSP = (CallGraphSCCPass*)P;
@@ -130,7 +131,12 @@ bool CGPassManager::RunPassOnSCC(Pass *P, CallGraphSCC &CurSCC,
{
TimeRegion PassTimer(getPassTimer(CGSP));
+ unsigned InstrCount = initSizeRemarkInfo(M);
Changed = CGSP->runOnSCC(CurSCC);
+
+ // If the pass modified the module, it may have modified the instruction
+ // count of the module. Try emitting a remark.
+ emitInstrCountChangedRemark(P, M, InstrCount);
}
// After the CGSCCPass is done, when assertions are enabled, use
diff --git a/llvm/lib/Analysis/LoopPass.cpp b/llvm/lib/Analysis/LoopPass.cpp
index 208bd53a3a8..00d88e8189e 100644
--- a/llvm/lib/Analysis/LoopPass.cpp
+++ b/llvm/lib/Analysis/LoopPass.cpp
@@ -151,6 +151,7 @@ void LPPassManager::markLoopAsDeleted(Loop &L) {
bool LPPassManager::runOnFunction(Function &F) {
auto &LIWP = getAnalysis<LoopInfoWrapperPass>();
LI = &LIWP.getLoopInfo();
+ Module &M = *F.getParent();
#if 0
DominatorTree *DT = &getAnalysis<DominatorTreeWrapperPass>().getDomTree();
#endif
@@ -200,8 +201,9 @@ bool LPPassManager::runOnFunction(Function &F) {
{
PassManagerPrettyStackEntry X(P, *CurrentLoop->getHeader());
TimeRegion PassTimer(getPassTimer(P));
-
+ unsigned InstrCount = initSizeRemarkInfo(M);
Changed |= P->runOnLoop(CurrentLoop, *this);
+ emitInstrCountChangedRemark(P, M, InstrCount);
}
if (Changed)
diff --git a/llvm/lib/IR/Function.cpp b/llvm/lib/IR/Function.cpp
index 20619167bae..4c7b6b74205 100644
--- a/llvm/lib/IR/Function.cpp
+++ b/llvm/lib/IR/Function.cpp
@@ -194,6 +194,14 @@ LLVMContext &Function::getContext() const {
return getType()->getContext();
}
+unsigned Function::getInstructionCount() {
+ unsigned NumInstrs = 0;
+ for (BasicBlock &BB : BasicBlocks)
+ NumInstrs += std::distance(BB.instructionsWithoutDebug().begin(),
+ BB.instructionsWithoutDebug().end());
+ return NumInstrs;
+}
+
void Function::removeFromParent() {
getParent()->getFunctionList().remove(getIterator());
}
diff --git a/llvm/lib/IR/LegacyPassManager.cpp b/llvm/lib/IR/LegacyPassManager.cpp
index c13e710dd3b..74481b0e501 100644
--- a/llvm/lib/IR/LegacyPassManager.cpp
+++ b/llvm/lib/IR/LegacyPassManager.cpp
@@ -13,6 +13,7 @@
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/ADT/Statistic.h"
+#include "llvm/IR/DiagnosticInfo.h"
#include "llvm/IR/IRPrintingPasses.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/LegacyPassManagers.h"
@@ -134,8 +135,65 @@ bool PMDataManager::isPassDebuggingExecutionsOrMore() const {
return PassDebugging >= Executions;
}
+unsigned PMDataManager::initSizeRemarkInfo(Module &M) {
+ // Only calculate getInstructionCount if the size-info remark is requested.
+ if (M.getContext().getDiagHandlerPtr()->isAnalysisRemarkEnabled("size-info"))
+ return M.getInstructionCount();
+ return 0;
+}
+
+void PMDataManager::emitInstrCountChangedRemark(Pass *P, Module &M,
+ unsigned CountBefore) {
+ // Did the user request the remark? If not, quit.
+ if (!M.getContext().getDiagHandlerPtr()->isAnalysisRemarkEnabled("size-info"))
+ return;
+
+ // We need a function containing at least one basic block in order to output
+ // remarks. Since it's possible that the first function in the module doesn't
+ // actually contain a basic block, we have to go and find one that's suitable
+ // for emitting remarks.
+ auto It = std::find_if(M.begin(), M.end(),
+ [](const Function &Fn) { return !Fn.empty(); });
+ // Didn't find a function. Quit.
+ if (It == M.end())
+ return;
+
+ // We found a function containing at least one basic block.
+ Function *F = &*It;
+ // How many instructions are in the module now?
+ unsigned CountAfter = M.getInstructionCount();
+
+ // If there was no change, don't emit a remark.
+ if (CountBefore == CountAfter)
+ return;
+
+ // If it's a pass manager, don't emit a remark. (This hinges on the assumption
+ // that the only passes that return non-null with getAsPMDataManager are pass
+ // managers.) The reason we have to do this is to avoid emitting remarks for
+ // CGSCC passes.
+ if (P->getAsPMDataManager())
+ return;
+
+ // Compute a possibly negative delta between the instruction count before
+ // running P, and after running P.
+ int64_t Delta = (int64_t)CountAfter - (int64_t)CountBefore;
+
+ BasicBlock &BB = *F->begin();
+ OptimizationRemarkAnalysis R("size-info", "IRSizeChange",
+ DiagnosticLocation(), &BB);
+ // FIXME: Move ore namespace to DiagnosticInfo so that we can use it. This
+ // would let us use NV instead of DiagnosticInfoOptimizationBase::Argument.
+ R << DiagnosticInfoOptimizationBase::Argument("Pass", P->getPassName())
+ << ": IR instruction count changed from "
+ << DiagnosticInfoOptimizationBase::Argument("IRInstrsBefore", CountBefore)
+ << " to "
+ << DiagnosticInfoOptimizationBase::Argument("IRInstrsAfter", CountAfter)
+ << "; Delta: "
+ << DiagnosticInfoOptimizationBase::Argument("DeltaInstrCount", Delta);
+ F->getContext().diagnose(R); // Not using ORE for layering reasons.
+}
void PassManagerPrettyStackEntry::print(raw_ostream &OS) const {
if (!V && !M)
@@ -1284,6 +1342,7 @@ bool BBPassManager::runOnFunction(Function &F) {
return false;
bool Changed = doInitialization(F);
+ Module &M = *F.getParent();
for (BasicBlock &BB : F)
for (unsigned Index = 0; Index < getNumContainedPasses(); ++Index) {
@@ -1299,8 +1358,9 @@ bool BBPassManager::runOnFunction(Function &F) {
// If the pass crashes, remember this.
PassManagerPrettyStackEntry X(BP, BB);
TimeRegion PassTimer(getPassTimer(BP));
-
+ unsigned InstrCount = initSizeRemarkInfo(M);
LocalChanged |= BP->runOnBasicBlock(BB);
+ emitInstrCountChangedRemark(BP, M, InstrCount);
}
Changed |= LocalChanged;
@@ -1500,7 +1560,7 @@ bool FPPassManager::runOnFunction(Function &F) {
return false;
bool Changed = false;
-
+ Module &M = *F.getParent();
// Collect inherited analysis from Module level pass manager.
populateInheritedAnalysis(TPM->activeStack);
@@ -1516,8 +1576,9 @@ bool FPPassManager::runOnFunction(Function &F) {
{
PassManagerPrettyStackEntry X(FP, F);
TimeRegion PassTimer(getPassTimer(FP));
-
+ unsigned InstrCount = initSizeRemarkInfo(M);
LocalChanged |= FP->runOnFunction(F);
+ emitInstrCountChangedRemark(FP, M, InstrCount);
}
Changed |= LocalChanged;
@@ -1594,7 +1655,9 @@ MPPassManager::runOnModule(Module &M) {
PassManagerPrettyStackEntry X(MP, M);
TimeRegion PassTimer(getPassTimer(MP));
+ unsigned InstrCount = initSizeRemarkInfo(M);
LocalChanged |= MP->runOnModule(M);
+ emitInstrCountChangedRemark(MP, M, InstrCount);
}
Changed |= LocalChanged;
diff --git a/llvm/lib/IR/Module.cpp b/llvm/lib/IR/Module.cpp
index 9f1e6096932..f1802406353 100644
--- a/llvm/lib/IR/Module.cpp
+++ b/llvm/lib/IR/Module.cpp
@@ -464,6 +464,13 @@ unsigned Module::getCodeViewFlag() const {
return cast<ConstantInt>(Val->getValue())->getZExtValue();
}
+unsigned Module::getInstructionCount() {
+ unsigned NumInstrs = 0;
+ for (Function &F : FunctionList)
+ NumInstrs += F.getInstructionCount();
+ return NumInstrs;
+}
+
Comdat *Module::getOrInsertComdat(StringRef Name) {
auto &Entry = *ComdatSymTab.insert(std::make_pair(Name, Comdat())).first;
Entry.second.Name = &Entry;
diff --git a/llvm/test/Other/size-remarks.ll b/llvm/test/Other/size-remarks.ll
new file mode 100644
index 00000000000..864057b5c4b
--- /dev/null
+++ b/llvm/test/Other/size-remarks.ll
@@ -0,0 +1,164 @@
+; Ensure that IR count remarks in the legacy pass manager work.
+; What this test should check for:
+; * Positive, nonzero sizes before/after
+; * Nonzero deltas
+; * Sizes are being tracked properly across multiple remarks. E.g, if we have
+; original_count_1, final_count_1, and
+; original_count_2, final_count_2,
+; Then original_count_2 == final_count_1.
+
+; For these remarks, the "function" field in the YAML file doesn't matter.
+; Each of the testcases work by combining the output remarks with the
+; optimization record emit using -pass-remarks-output. This is done to prevent
+; test flakiness wrt instruction counts, but also ensure that the output values
+; are equivalent in both outputs.
+
+; RUN: opt < %s -inline -pass-remarks-analysis='size-info' \
+; RUN: -pass-remarks-output=%t.yaml -S -o /dev/null 2> %t; \
+; RUN: cat %t %t.yaml | FileCheck %s -check-prefix=CGSCC
+; CGSCC: remark: <unknown>:0:0: Function Integration/Inlining:
+; CGSCC-SAME: IR instruction count changed from
+; CGSCC-SAME: [[ORIG:[1-9][0-9]*]] to [[FINAL:[1-9][0-9]*]];
+; CGSCC-SAME: Delta: [[DELTA:-?[1-9][0-9]*]]
+; CGSCC: --- !Analysis
+; CGSCC-NEXT: Pass: size-info
+; CGSCC-NEXT: Name: IRSizeChange
+; CGSCC-NEXT: Function:
+; CGSCC-NEXT: Args:
+; CGSCC-NEXT: - Pass: Function Integration/Inlining
+; CGSCC-NEXT: - String: ': IR instruction count changed from '
+; CGSCC-NEXT: - IRInstrsBefore: '[[ORIG]]'
+; CGSCC-NEXT: - String: ' to '
+; CGSCC-NEXT: - IRInstrsAfter: '[[FINAL]]'
+; CGSCC-NEXT: - String: '; Delta: '
+; CGSCC-NEXT: - DeltaInstrCount: '[[DELTA]]'
+
+; RUN: opt < %s -instcombine -pass-remarks-analysis='size-info' \
+; RUN:-pass-remarks-output=%t.yaml -S -o /dev/null 2> %t; \
+; RUN: cat %t %t.yaml | FileCheck %s -check-prefix=FUNC
+; FUNC: remark: <unknown>:0:0: Combine redundant instructions:
+; FUNC-SAME: IR instruction count changed from
+; FUNC-SAME: [[SIZE1:[1-9][0-9]*]] to [[SIZE2:[1-9][0-9]*]];
+; FUNC-SAME: Delta: [[DELTA1:-?[1-9][0-9]*]]
+; FUNC-NEXT: remark: <unknown>:0:0: Combine redundant instructions:
+; FUNC-SAME: IR instruction count changed from
+; FUNC-SAME: [[SIZE2]] to [[SIZE3:[1-9][0-9]*]];
+; FUNC-SAME: Delta: [[DELTA2:-?[1-9][0-9]*]]
+; FUNC: --- !Analysis
+; FUNC-NEXT: Pass: size-info
+; FUNC-NEXT: Name: IRSizeChange
+; FUNC-NEXT: Function:
+; FUNC-NEXT: Args:
+; FUNC-NEXT: - Pass: Combine redundant instructions
+; FUNC-NEXT: - String: ': IR instruction count changed from '
+; FUNC-NEXT: - IRInstrsBefore: '[[SIZE1]]'
+; FUNC-NEXT: - String: ' to '
+; FUNC-NEXT: - IRInstrsAfter: '[[SIZE2]]'
+; FUNC-NEXT: - String: '; Delta: '
+; FUNC-NEXT: - DeltaInstrCount: '[[DELTA1]]'
+; FUNC: --- !Analysis
+; FUNC-NEXT: Pass: size-info
+; FUNC-NEXT: Name: IRSizeChange
+; FUNC-NEXT: Function:
+; FUNC-NEXT: Args:
+; FUNC-NEXT: - Pass: Combine redundant instructions
+; FUNC-NEXT: - String: ': IR instruction count changed from '
+; FUNC-NEXT: - IRInstrsBefore: '[[SIZE2]]'
+; FUNC-NEXT: - String: ' to '
+; FUNC-NEXT: - IRInstrsAfter: '[[SIZE3]]'
+; FUNC-NEXT: - String: '; Delta: '
+; FUNC-NEXT: - DeltaInstrCount: '[[DELTA2]]'
+
+; RUN: opt < %s -globaldce -pass-remarks-analysis='size-info' \
+; RUN: -pass-remarks-output=%t.yaml -S -o /dev/null 2> %t; \
+; RUN: cat %t %t.yaml | FileCheck %s -check-prefix=MODULE
+; MODULE: remark:
+; MODULE-SAME: Dead Global Elimination:
+; MODULE-SAME: IR instruction count changed from
+; MODULE-SAME: [[ORIG:[1-9][0-9]*]] to [[FINAL:[1-9][0-9]*]];
+; MODULE-SAME: Delta: [[DELTA:-?[1-9][0-9]*]]
+; MODULE: --- !Analysis
+; MODULE-NEXT: Pass: size-info
+; MODULE-NEXT: Name: IRSizeChange
+; MODULE-NEXT: Function:
+; MODULE-NEXT: Args:
+; MODULE-NEXT: - Pass: Dead Global Elimination
+; MODULE-NEXT: - String: ': IR instruction count changed from '
+; MODULE-NEXT: - IRInstrsBefore: '[[ORIG]]'
+; MODULE-NEXT: - String: ' to '
+; MODULE-NEXT: - IRInstrsAfter: '[[FINAL]]'
+; MODULE-NEXT: - String: '; Delta: '
+; MODULE-NEXT: - DeltaInstrCount: '[[DELTA]]'
+
+; RUN: opt < %s -dce -pass-remarks-analysis='size-info' \
+; RUN: -pass-remarks-output=%t.yaml -S -o /dev/null 2> %t; \
+; RUN: cat %t %t.yaml | FileCheck %s -check-prefix=BB
+; BB: remark: <unknown>:0:0: Dead Code Elimination:
+; BB-SAME: IR instruction count changed from
+; BB-SAME: [[ORIG:[1-9][0-9]*]] to [[FINAL:[1-9][0-9]*]];
+; BB-SAME: Delta: [[DELTA:-?[1-9][0-9]*]]
+; BB: --- !Analysis
+; BB-NEXT: Pass: size-info
+; BB-NEXT: Name: IRSizeChange
+; BB-NEXT: Function:
+; BB-NEXT: Args:
+; BB-NEXT: - Pass: Dead Code Elimination
+; BB-NEXT: - String: ': IR instruction count changed from '
+; BB-NEXT: - IRInstrsBefore: '[[ORIG]]'
+; BB-NEXT: - String: ' to '
+; BB-NEXT: - IRInstrsAfter: '[[FINAL]]'
+; BB-NEXT: - String: '; Delta: '
+; BB-NEXT: - DeltaInstrCount: '[[DELTA]]'
+
+; RUN: opt < %s -loop-unroll -pass-remarks-analysis='size-info' \
+; RUN: -pass-remarks-output=%t.yaml -S -o /dev/null 2> %t; \
+; RUN: cat %t %t.yaml | FileCheck %s -check-prefix=LOOP
+; LOOP: remark: <unknown>:0:0: Unroll loops:
+; LOOP-SAME: IR instruction count changed from
+; LOOP-SAME: [[ORIG:[1-9][0-9]*]] to [[FINAL:[1-9][0-9]*]];
+; LOOP-SAME: Delta: [[DELTA:-?[1-9][0-9]*]]
+; LOOP: --- !Analysis
+; LOOP-NEXT: Pass: size-info
+; LOOP-NEXT: Name: IRSizeChange
+; LOOP-NEXT: Function:
+; LOOP-NEXT: Args:
+; LOOP-DAG: - Pass: Unroll loops
+; LOOP-NEXT: - String: ': IR instruction count changed from '
+; LOOP-NEXT: - IRInstrsBefore: '[[ORIG]]'
+; LOOP-NEXT: - String: ' to '
+; LOOP-NEXT: - IRInstrsAfter: '[[FINAL]]'
+; LOOP-NEXT: - String: '; Delta: '
+; LOOP-NEXT: - DeltaInstrCount: '[[DELTA]]'
+declare i1 ()* @boop()
+
+define internal i1 @pluto() {
+ %F = call i1 ()* () @boop( )
+ %c = icmp eq i1 ()* %F, @pluto
+ ret i1 %c
+}
+
+define i32 @foo(i32 %x) {
+entry:
+ %x.addr = alloca i32, align 4
+ store i32 %x, i32* %x.addr, align 4
+ %0 = load i32, i32* %x.addr, align 4
+ ret i32 %0
+}
+
+define i32 @bar(i32 %x) {
+entry:
+ %x.addr = alloca i32, align 4
+ store i32 %x, i32* %x.addr, align 4
+ %0 = load i32, i32* %x.addr, align 4
+ %call = call i32 @foo(i32 %0)
+ br label %for.body
+for.body:
+ %s.06 = phi i32 [ 0, %entry ], [ %add, %for.body ]
+ %i.05 = phi i32 [ 0, %entry ], [ %inc, %for.body ]
+ %add = add nsw i32 %i.05, 4
+ %inc = add nsw i32 %i.05, 1
+ %exitcond = icmp eq i32 %inc, 16
+ br i1 %exitcond, label %for.end, label %for.body
+for.end:
+ ret i32 %add
+}
OpenPOWER on IntegriCloud