/// 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;
}
}
+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.
// 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;
}
--- /dev/null
+# 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