diff --git a/llvm/lib/CodeGen/MachineOutliner.cpp b/llvm/lib/CodeGen/MachineOutliner.cpp --- a/llvm/lib/CodeGen/MachineOutliner.cpp +++ b/llvm/lib/CodeGen/MachineOutliner.cpp @@ -59,6 +59,9 @@ #include "llvm/ADT/SmallSet.h" #include "llvm/ADT/Statistic.h" #include "llvm/ADT/Twine.h" +#include "llvm/Analysis/BlockFrequencyInfo.h" +#include "llvm/Analysis/BranchProbabilityInfo.h" +#include "llvm/Analysis/LoopInfo.h" #include "llvm/Analysis/OptimizationRemarkEmitter.h" #include "llvm/CodeGen/LivePhysRegs.h" #include "llvm/CodeGen/MachineModuleInfo.h" @@ -67,6 +70,7 @@ #include "llvm/CodeGen/TargetInstrInfo.h" #include "llvm/CodeGen/TargetSubtargetInfo.h" #include "llvm/IR/DIBuilder.h" +#include "llvm/IR/Dominators.h" #include "llvm/IR/IRBuilder.h" #include "llvm/IR/Mangler.h" #include "llvm/InitializePasses.h" @@ -113,6 +117,10 @@ cl::desc( "Number of times to rerun the outliner after the initial outline")); +static cl::opt UseProfileData( + "machine-outliner-use-profile-data", cl::init(false), cl::Hidden, + cl::desc("Use profile data to avoid outlining hot blocks.")); + namespace { /// Maps \p MachineInstrs to unsigned integers and stores the mappings. @@ -891,7 +899,16 @@ const TargetInstrInfo *TII = MF->getSubtarget().getInstrInfo(); - if (!RunOnAllFunctions && !TII->shouldOutlineFromFunctionByDefault(*MF)) + Optional BFI; + if (UseProfileData) { + DominatorTree DT(F); + LoopInfo LI(DT); + BranchProbabilityInfo BPI(F, LI); + BFI.emplace(F, BPI, LI); + } + + if (!RunOnAllFunctions && !TII->shouldOutlineFromFunctionByDefault(*MF) && + !UseProfileData) continue; // We have a MachineFunction. Ask the target if it's suitable for outlining. @@ -917,6 +934,11 @@ if (MBB.hasAddressTaken()) continue; + // If we have profile data and want to use it, avoid outlining hot blocks. + if (UseProfileData && + !BFI->isBlockRarelyExecuted(MBB.getBasicBlock()).getValueOr(false)) + continue; + // MBB is suitable for outlining. Map it to a list of unsigneds. Mapper.convertToUnsignedVec(MBB, *TII); } diff --git a/llvm/test/CodeGen/AArch64/machine-outliner-profile.ll b/llvm/test/CodeGen/AArch64/machine-outliner-profile.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/AArch64/machine-outliner-profile.ll @@ -0,0 +1,68 @@ +; RUN: llc -verify-machineinstrs -enable-machine-outliner -machine-outliner-use-profile-data -mtriple=aarch64-linux-gnu < %s | FileCheck %s + +declare void @z(i32, i32, i32, i32) + +; CHECK-LABEL: cold: +define void @cold() !prof !0 { +entry: +; CHECK: [[OUTLINED:OUTLINED_FUNCTION_[0-9]+]] + tail call void @z(i32 1, i32 2, i32 3, i32 4) + ret void +; CHECK: .cfi_endproc +} + +; CHECK-LABEL: hot: +define void @hot() !prof !1 { +entry: +; CHECK-NOT: [[OUTLINED]] + tail call void @z(i32 1, i32 2, i32 3, i32 4) + ret void +; CHECK: .cfi_endproc +} + +; CHECK-LABEL: small_cold: +define void @small_cold() optsize minsize !prof !0 { +entry: +; CHECK: [[OUTLINED]] + tail call void @z(i32 1, i32 2, i32 3, i32 4) + ret void +; CHECK: .cfi_endproc +} + +; CHECK-LABEL: small_hot: +define void @small_hot() optsize minsize !prof !1 { +entry: +; CHECK-NOT: [[OUTLINED]] + tail call void @z(i32 1, i32 2, i32 3, i32 4) + ret void +; CHECK: .cfi_endproc +} + +; CHECK-LABEL: no_profile: +define void @no_profile() { +entry: +; CHECK-NOT: [[OUTLINED]] + tail call void @z(i32 1, i32 2, i32 3, i32 4) + ret void +; CHECK: .cfi_endproc +} + +; CHECK-LABEL: cold2: +define void @cold2() !prof !0 { +entry: +; CHECK: [[OUTLINED]] + tail call void @z(i32 1, i32 2, i32 3, i32 4) + ret void +; CHECK: .cfi_endproc +} + +; CHECK: [[OUTLINED]]: +; CHECK-SAME: // @{{.*}} Tail Call +; CHECK: mov w0, #1 +; CHECK-NEXT: mov w1, #2 +; CHECK-NEXT: mov w2, #3 +; CHECK-NEXT: mov w3, #4 +; CHECK-NEXT: b z + +!0 = !{!"function_entry_count", i64 0} +!1 = !{!"function_entry_count", i64 1}