[MachineOutliner] Add codegen size remarks to the MachineOutliner

Since the outliner is a module pass, it doesn't get codegen size remarks like
the other codegen passes do. This adds size remarks *to* the outliner.

This is kind of a workaround, so it's peppered with FIXMEs; size remarks
really ought to not ever be handled by the pass itself. However, since the
outliner is the only "MachineModulePass", this works for now. Since the
entire purpose of the MachineOutliner is to produce code size savings, it
really ought to be included in codgen size remarks.

If we ever go ahead and make a MachineModulePass (say, something similar to
MachineFunctionPass), then all of this ought to be moved there.

llvm-svn: 342009
This commit is contained in:
Jessica Paquette 2018-09-11 23:05:34 +00:00
parent 02e2e1a226
commit 214e572d5f
2 changed files with 184 additions and 1 deletions

View File

@ -812,8 +812,21 @@ struct MachineOutliner : public ModulePass {
/// These are used to construct a suffix tree.
void populateMapper(InstructionMapper &Mapper, Module &M,
MachineModuleInfo &MMI);
};
/// Initialize information necessary to output a size remark.
/// FIXME: This should be handled by the pass manager, not the outliner.
/// FIXME: This is nearly identical to the initSizeRemarkInfo in the legacy
/// pass manager.
void initSizeRemarkInfo(
const Module &M, const MachineModuleInfo &MMI,
StringMap<unsigned> &FunctionToInstrCount);
/// Emit the remark.
// FIXME: This should be handled by the pass manager, not the outliner.
void emitInstrCountChangedRemark(
const Module &M, const MachineModuleInfo &MMI,
const StringMap<unsigned> &FunctionToInstrCount);
};
} // Anonymous namespace.
char MachineOutliner::ID = 0;
@ -1388,6 +1401,75 @@ void MachineOutliner::populateMapper(InstructionMapper &Mapper, Module &M,
}
}
void MachineOutliner::initSizeRemarkInfo(
const Module &M, const MachineModuleInfo &MMI,
StringMap<unsigned> &FunctionToInstrCount) {
// Collect instruction counts for every function. We'll use this to emit
// per-function size remarks later.
for (const Function &F : M) {
MachineFunction *MF = MMI.getMachineFunction(F);
// We only care about MI counts here. If there's no MachineFunction at this
// point, then there won't be after the outliner runs, so let's move on.
if (!MF)
continue;
FunctionToInstrCount[F.getName().str()] = MF->getInstructionCount();
}
}
void MachineOutliner::emitInstrCountChangedRemark(
const Module &M, const MachineModuleInfo &MMI,
const StringMap<unsigned> &FunctionToInstrCount) {
// Iterate over each function in the module and emit remarks.
// Note that we won't miss anything by doing this, because the outliner never
// deletes functions.
for (const Function &F : M) {
MachineFunction *MF = MMI.getMachineFunction(F);
// The outliner never deletes functions. If we don't have a MF here, then we
// didn't have one prior to outlining either.
if (!MF)
continue;
std::string Fname = F.getName();
unsigned FnCountAfter = MF->getInstructionCount();
unsigned FnCountBefore = 0;
// Check if the function was recorded before.
auto It = FunctionToInstrCount.find(Fname);
// Did we have a previously-recorded size? If yes, then set FnCountBefore
// to that.
if (It != FunctionToInstrCount.end())
FnCountBefore = It->second;
// Compute the delta and emit a remark if there was a change.
int64_t FnDelta = static_cast<int64_t>(FnCountAfter) -
static_cast<int64_t>(FnCountBefore);
if (FnDelta == 0)
continue;
MachineOptimizationRemarkEmitter MORE(*MF, nullptr);
MORE.emit([&]() {
MachineOptimizationRemarkAnalysis R("size-info", "FunctionMISizeChange",
DiagnosticLocation(),
&MF->front());
R << DiagnosticInfoOptimizationBase::Argument("Pass", "Machine Outliner")
<< ": Function: "
<< DiagnosticInfoOptimizationBase::Argument("Function", F.getName())
<< ": MI instruction count changed from "
<< DiagnosticInfoOptimizationBase::Argument("MIInstrsBefore",
FnCountBefore)
<< " to "
<< DiagnosticInfoOptimizationBase::Argument("MIInstrsAfter",
FnCountAfter)
<< "; Delta: "
<< DiagnosticInfoOptimizationBase::Argument("Delta", FnDelta);
return R;
});
}
}
bool MachineOutliner::runOnModule(Module &M) {
// Check if there's anything in the module. If it's empty, then there's
// nothing to outline.
@ -1430,8 +1512,28 @@ bool MachineOutliner::runOnModule(Module &M) {
// Remove candidates that overlap with other candidates.
pruneOverlaps(CandidateList, FunctionList, Mapper, MaxCandidateLen);
// If we've requested size remarks, then collect the MI counts of every
// function before outlining, and the MI counts after outlining.
// FIXME: This shouldn't be in the outliner at all; it should ultimately be
// the pass manager's responsibility.
// This could pretty easily be placed in outline instead, but because we
// really ultimately *don't* want this here, it's done like this for now
// instead.
// Check if we want size remarks.
bool ShouldEmitSizeRemarks = M.shouldEmitInstrCountChangedRemark();
StringMap<unsigned> FunctionToInstrCount;
if (ShouldEmitSizeRemarks)
initSizeRemarkInfo(M, MMI, FunctionToInstrCount);
// Outline each of the candidates and return true if something was outlined.
bool OutlinedSomething = outline(M, CandidateList, FunctionList, Mapper);
// If we outlined something, we definitely changed the MI count of the
// module. If we've asked for size remarks, then output them.
// FIXME: This should be in the pass manager.
if (ShouldEmitSizeRemarks && OutlinedSomething)
emitInstrCountChangedRemark(M, MMI, FunctionToInstrCount);
return OutlinedSomething;
}

View File

@ -0,0 +1,81 @@
# RUN: llc -mtriple=aarch64-apple-darwin -run-pass=prologepilog \
# RUN: -run-pass=machine-outliner %s -pass-remarks-analysis='size-info' \
# RUN: -pass-remarks-output=%t.yaml -o /dev/null < %s 2> %t; \
# RUN: cat %t %t.yaml | FileCheck %s
# Ensure that the MachineOutliner produces codegen size remarks. Make sure...
# - Functions that are outlined from shrink in the remark (foo)
# - Outlined functions start with 0 instructions
# - Outlined functions end with the same number of instructions as the delta
# CHECK: remark: <unknown>:0:0: Machine Outliner: Function: foo:
# CHECK-SAME: MI instruction count changed from
# CHECK-SAME: [[FOO1:[1-9][0-9]*]] to [[FOO2:[1-9][0-9]*]];
# CHECK-SAME: Delta: [[FOODELTA:-?[1-9][0-9]*]]
# CHECK-NEXT: remark: <unknown>:0:0: Machine Outliner:
# CHECK-SAME: Function: OUTLINED_FUNCTION_0: MI instruction count changed from
# CHECK-SAME: 0 to [[OFUNCSIZE:[1-9][0-9]*]]; Delta: [[OFUNCSIZE]]
# CHECK-DAG: - Pass: Machine Outliner
# CHECK-NEXT: - String: ': Function: '
# CHECK-NEXT: - Function: foo
# CHECK-NEXT: - String: ': MI instruction count changed from '
# CHECK-NEXT: - MIInstrsBefore: '[[FOO1]]'
# CHECK-NEXT: - String: ' to '
# CHECK-NEXT: - MIInstrsAfter: '[[FOO2]]'
# CHECK-NEXT: - String: '; Delta: '
# CHECK-NEXT: - Delta: '[[FOODELTA]]'
# CHECK-NEXT:...
# CHECK-NEXT: --- !Analysis
# CHECK-NEXT: Pass: size-info
# CHECK-NEXT: Name: FunctionMISizeChange
# CHECK-NEXT: Function: OUTLINED_FUNCTION_0
# CHECK-NEXT: Args:
# CHECK-NEXT: - Pass: Machine Outliner
# CHECK-NEXT: - String: ': Function: '
# CHECK-NEXT: - Function: OUTLINED_FUNCTION_0
# CHECK-NEXT: - String: ': MI instruction count changed from '
# CHECK-NEXT: - MIInstrsBefore: '0'
# CHECK-NEXT: - String: ' to '
# CHECK-NEXT: - MIInstrsAfter: '[[OFUNCSIZE]]'
# CHECK-NEXT: - String: '; Delta: '
# CHECK-NEXT: - Delta: '[[OFUNCSIZE]]'
...
--- |
define void @foo() #0 {
ret void
}
attributes #0 = { minsize noinline noredzone "no-frame-pointer-elim"="true" }
...
---
name: foo
tracksRegLiveness: true
fixedStack:
body: |
bb.0:
liveins: $lr, $w9
$x25 = ORRXri $xzr, 1
$w9 = ORRWri $wzr, 1
$w9 = ORRWri $wzr, 1
$w9 = ORRWri $wzr, 1
$w9 = ORRWri $wzr, 1
$w9 = ORRWri $wzr, 1
$w9 = ORRWri $wzr, 2
bb.1:
liveins: $lr, $w9
$w9 = ORRWri $wzr, 1
$w9 = ORRWri $wzr, 1
$w9 = ORRWri $wzr, 1
$w9 = ORRWri $wzr, 1
$w9 = ORRWri $wzr, 1
$w9 = ORRWri $wzr, 2
bb.2:
liveins: $lr, $w9
$w9 = ORRWri $wzr, 1
$w9 = ORRWri $wzr, 1
$w9 = ORRWri $wzr, 1
$w9 = ORRWri $wzr, 1
$w9 = ORRWri $wzr, 1
$w9 = ORRWri $wzr, 2
RET undef $lr