Index: lib/CodeGen/MachineOutliner.cpp =================================================================== --- lib/CodeGen/MachineOutliner.cpp +++ lib/CodeGen/MachineOutliner.cpp @@ -46,6 +46,7 @@ #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineInstrBuilder.h" #include "llvm/CodeGen/MachineModuleInfo.h" +#include "llvm/CodeGen/MachineOptimizationRemarkEmitter.h" #include "llvm/CodeGen/Passes.h" #include "llvm/IR/IRBuilder.h" #include "llvm/Support/Allocator.h" @@ -64,6 +65,7 @@ #define DEBUG_TYPE "machine-outliner" using namespace llvm; +using namespace ore; STATISTIC(NumOutlined, "Number of candidates outlined"); STATISTIC(FunctionsCreated, "Number of functions created"); @@ -829,6 +831,10 @@ size_t FnIdx = 0; size_t MaxLen = 0; + // Count the number of candidates we considered for outlining. Used to give + // remarks an identifier. + size_t NumCandidatesEvaluated = 0; + // FIXME: Visit internal nodes instead of leaves. for (SuffixTreeNode *Leaf : ST.LeafVector) { assert(Leaf && "Leaves in LeafVector cannot be null!"); @@ -851,6 +857,10 @@ if (StringLen < 2) continue; + // We've found something we might want to outline. Keep track of an ID for + // remarks. + NumCandidatesEvaluated++; + size_t CallOverhead = 0; size_t SequenceOverhead = StringLen; @@ -895,8 +905,43 @@ size_t OutliningCost = CallOverhead + FrameOverhead + SequenceOverhead; size_t NotOutliningCost = SequenceOverhead * Parent.OccurrenceCount; - if (NotOutliningCost <= OutliningCost) + // Is it better to outline this candidate than not? + if (NotOutliningCost <= OutliningCost) { + // Outlining this candidate would take more instructions than not + // outlining. + // Emit a remark explaining why we didn't outline this candidate. + std::pair C = + CandidateClass[0]; + MachineOptimizationRemarkEmitter MORE( + *(C.first->getParent()->getParent()), nullptr); + MachineOptimizationRemarkMissed R(DEBUG_TYPE, "NotOutliningCheaper", + C.first->getDebugLoc(), + C.first->getParent()); + R << NV("StartLoc0", C.first->getDebugLoc()) << ": Did not outline " + << NV("Length", StringLen) + << " instructions. Outlined instruction count (" + << NV("OutliningCost", OutliningCost) << ")" + << " >= unoutlined instruction count (" + << NV("NotOutliningCost", NotOutliningCost) << ")" + << " (Also found at: "; + + // Tell the user the other places the candidate was found. + size_t i = 1; + for (size_t e = CandidateClass.size() - 1; i < e; i++) { + R << NV("StartLoc" + std::to_string(i), + CandidateClass[i].first->getDebugLoc()) + << ", "; + } + + R << NV("StartLoc" + std::to_string(i), + CandidateClass[i].first->getDebugLoc()) + << ")"; + + MORE.emit(R); + + // Move to the next candidate. continue; + } size_t Benefit = NotOutliningCost - OutliningCost; Index: test/CodeGen/AArch64/machine-outliner-remarks.ll =================================================================== --- test/CodeGen/AArch64/machine-outliner-remarks.ll +++ test/CodeGen/AArch64/machine-outliner-remarks.ll @@ -0,0 +1,65 @@ +; RUN: llc %s -enable-machine-outliner -mtriple=aarch64-unknown-unknown -o /dev/null -pass-remarks=machine-outliner -pass-remarks-output=%t.yaml +; RUN: cat %t.yaml | FileCheck %s -check-prefix=YAML +; YAML: --- !Missed +; YAML-NEXT: Pass: machine-outliner +; YAML-NEXT: Name: NotOutliningCheaper +; YAML-NEXT: DebugLoc: { File: machine-outliner-remarks.ll, Line: 5, Column: 9 } +; YAML-NEXT: Function: dog +; YAML-NEXT: Args: +; YAML-NEXT: - StartLoc0: 'machine-outliner-remarks.ll:5:9' +; YAML-NEXT: DebugLoc: { File: machine-outliner-remarks.ll, Line: 5, Column: 9 } +; YAML-NEXT: - String: ': Did not outline ' +; YAML-NEXT: - Length: '2' +; YAML-NEXT: - String: ' instructions. Outlined instruction count (' +; YAML-NEXT: - OutliningCost: '9' +; YAML-NEXT: - String: ')' +; YAML-NEXT: - String: ' >= unoutlined instruction count (' +; YAML-NEXT: - NotOutliningCost: '4' +; YAML-NEXT: - String: ')' +; YAML-NEXT: - String: ' (Also found at: ' +; YAML-NEXT: - StartLoc1: 'machine-outliner-remarks.ll:13:9' +; YAML-NEXT: DebugLoc: { File: machine-outliner-remarks.ll, Line: 13, Column: 9 } +; YAML-NEXT: - String: ')' + +define void @dog() #0 !dbg !8 { +entry: + %x = alloca i32, align 4 + %y = alloca i32, align 4 + store i32 0, i32* %x, align 4, !dbg !11 + store i32 1, i32* %y, align 4, !dbg !12 + ret void, !dbg !13 +} + +define void @cat() #0 !dbg !14 { +entry: + %x = alloca i32, align 4 + %y = alloca i32, align 4 + store i32 0, i32* %x, align 4, !dbg !15 + store i32 1, i32* %y, align 4, !dbg !16 + ret void, !dbg !17 +} + +attributes #0 = { noredzone nounwind ssp uwtable "no-frame-pointer-elim"="false" "target-cpu"="cyclone" } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!3, !4, !5, !6} +!llvm.ident = !{!7} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2) +!1 = !DIFile(filename: "machine-outliner-remarks.ll", directory: "/tmp") +!2 = !{} +!3 = !{i32 2, !"Dwarf Version", i32 4} +!4 = !{i32 2, !"Debug Info Version", i32 3} +!5 = !{i32 1, !"wchar_size", i32 4} +!6 = !{i32 7, !"PIC Level", i32 2} +!7 = !{!""} +!8 = distinct !DISubprogram(name: "dog", scope: !1, file: !1, line: 2, type: !9, isLocal: false, isDefinition: true, scopeLine: 3, flags: DIFlagPrototyped, isOptimized: false, unit: !0, variables: !2) +!9 = !DISubroutineType(types: !10) +!10 = !{null} +!11 = !DILocation(line: 4, column: 9, scope: !8) +!12 = !DILocation(line: 5, column: 9, scope: !8) +!13 = !DILocation(line: 6, column: 1, scope: !8) +!14 = distinct !DISubprogram(name: "cat", scope: !1, file: !1, line: 10, type: !9, isLocal: false, isDefinition: true, scopeLine: 11, flags: DIFlagPrototyped, isOptimized: false, unit: !0, variables: !2) +!15 = !DILocation(line: 12, column: 9, scope: !14) +!16 = !DILocation(line: 13, column: 9, scope: !14) +!17 = !DILocation(line: 14, column: 1, scope: !14)