mirror of
https://github.com/RPCS3/llvm.git
synced 2025-01-26 12:46:00 +00:00
[PowerPC] Add Branch Hints for Highly-Biased Branches
This branch adds hints for highly biased branches on the PPC architecture. Even in absence of profiling information, LLVM will mark code reaching unreachable terminators and other exceptional control flow constructs as highly unlikely to be reached. Patch by Tom Jablin! git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@255398 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
670d12555d
commit
8f2bcca5c7
@ -56,6 +56,14 @@ namespace PPC {
|
||||
PRED_BIT_UNSET = 1025
|
||||
};
|
||||
|
||||
// Bit for branch taken (plus) or not-taken (minus) hint
|
||||
enum BranchHintBit {
|
||||
BR_NO_HINT = 0x0,
|
||||
BR_NONTAKEN_HINT = 0x2,
|
||||
BR_TAKEN_HINT = 0x3,
|
||||
BR_HINT_MASK = 0X3
|
||||
};
|
||||
|
||||
/// Invert the specified predicate. != -> ==, < -> >=.
|
||||
Predicate InvertPredicate(Predicate Opcode);
|
||||
|
||||
|
@ -16,6 +16,8 @@
|
||||
#include "MCTargetDesc/PPCPredicates.h"
|
||||
#include "PPCMachineFunctionInfo.h"
|
||||
#include "PPCTargetMachine.h"
|
||||
#include "llvm/Analysis/BranchProbabilityInfo.h"
|
||||
#include "llvm/CodeGen/FunctionLoweringInfo.h"
|
||||
#include "llvm/CodeGen/MachineFunction.h"
|
||||
#include "llvm/CodeGen/MachineInstrBuilder.h"
|
||||
#include "llvm/CodeGen/MachineRegisterInfo.h"
|
||||
@ -52,6 +54,11 @@ static cl::opt<bool> BPermRewriterNoMasking(
|
||||
"bit permutations"),
|
||||
cl::Hidden);
|
||||
|
||||
static cl::opt<bool> EnableBranchHint(
|
||||
"ppc-use-branch-hint", cl::init(true),
|
||||
cl::desc("Enable static hinting of branches on ppc"),
|
||||
cl::Hidden);
|
||||
|
||||
namespace llvm {
|
||||
void initializePPCDAGToDAGISelPass(PassRegistry&);
|
||||
}
|
||||
@ -393,6 +400,57 @@ static bool isInt32Immediate(SDValue N, unsigned &Imm) {
|
||||
return isInt32Immediate(N.getNode(), Imm);
|
||||
}
|
||||
|
||||
static unsigned getBranchHint(unsigned PCC, FunctionLoweringInfo *FuncInfo,
|
||||
const SDValue &DestMBB) {
|
||||
assert(isa<BasicBlockSDNode>(DestMBB));
|
||||
|
||||
if (!FuncInfo->BPI) return PPC::BR_NO_HINT;
|
||||
|
||||
const BasicBlock *BB = FuncInfo->MBB->getBasicBlock();
|
||||
const TerminatorInst *BBTerm = BB->getTerminator();
|
||||
|
||||
if (BBTerm->getNumSuccessors() != 2) return PPC::BR_NO_HINT;
|
||||
|
||||
const BasicBlock *TBB = BBTerm->getSuccessor(0);
|
||||
const BasicBlock *FBB = BBTerm->getSuccessor(1);
|
||||
|
||||
uint32_t TWeight = FuncInfo->BPI->getEdgeWeight(BB, TBB);
|
||||
uint32_t FWeight = FuncInfo->BPI->getEdgeWeight(BB, FBB);
|
||||
|
||||
// We only want to handle cases which are easy to predict at static time, e.g.
|
||||
// C++ throw statement, that is very likely not taken, or calling never
|
||||
// returned function, e.g. stdlib exit(). So we set Threshold to filter
|
||||
// unwanted cases.
|
||||
//
|
||||
// Below is LLVM branch weight table, we only want to handle case 1, 2
|
||||
//
|
||||
// Case Taken:Nontaken Example
|
||||
// 1. Unreachable 1048575:1 C++ throw, stdlib exit(),
|
||||
// 2. Invoke-terminating 1:1048575
|
||||
// 3. Coldblock 4:64 __builtin_expect
|
||||
// 4. Loop Branch 124:4 For loop
|
||||
// 5. PH/ZH/FPH 20:12
|
||||
const uint32_t Threshold = 10000;
|
||||
|
||||
// Minimal weight should be at least 1
|
||||
if (std::max(TWeight, FWeight) /
|
||||
std::max(1u, std::min(TWeight, FWeight)) < Threshold)
|
||||
return PPC::BR_NO_HINT;
|
||||
|
||||
DEBUG(dbgs() << "Use branch hint for '" << FuncInfo->Fn->getName() << "::"
|
||||
<< BB->getName() << "'\n"
|
||||
<< " -> " << TBB->getName() << ": " << TWeight << "\n"
|
||||
<< " -> " << FBB->getName() << ": " << FWeight << "\n");
|
||||
|
||||
const BasicBlockSDNode *BBDN = cast<BasicBlockSDNode>(DestMBB);
|
||||
|
||||
// If Dest BasicBlock is False-BasicBlock (FBB), swap branch weight,
|
||||
// because we want 'TWeight' stands for 'branch weight' to Dest BasicBlock
|
||||
if (BBDN->getBasicBlock()->getBasicBlock() != TBB)
|
||||
std::swap(TWeight, FWeight);
|
||||
|
||||
return (TWeight > FWeight) ? PPC::BR_TAKEN_HINT : PPC::BR_NONTAKEN_HINT;
|
||||
}
|
||||
|
||||
// isOpcWithIntImmediate - This method tests to see if the node is a specific
|
||||
// opcode and that it has a immediate integer right operand.
|
||||
@ -2840,8 +2898,11 @@ SDNode *PPCDAGToDAGISel::Select(SDNode *N) {
|
||||
// Op #3 is the Dest MBB
|
||||
// Op #4 is the Flag.
|
||||
// Prevent PPC::PRED_* from being selected into LI.
|
||||
SDValue Pred =
|
||||
getI32Imm(cast<ConstantSDNode>(N->getOperand(1))->getZExtValue(), dl);
|
||||
unsigned PCC = cast<ConstantSDNode>(N->getOperand(1))->getZExtValue();
|
||||
if (EnableBranchHint)
|
||||
PCC |= getBranchHint(PCC, FuncInfo, N->getOperand(3));
|
||||
|
||||
SDValue Pred = getI32Imm(PCC, dl);
|
||||
SDValue Ops[] = { Pred, N->getOperand(2), N->getOperand(3),
|
||||
N->getOperand(0), N->getOperand(4) };
|
||||
return CurDAG->SelectNodeTo(N, PPC::BCC, MVT::Other, Ops);
|
||||
@ -2870,6 +2931,9 @@ SDNode *PPCDAGToDAGISel::Select(SDNode *N) {
|
||||
BitComp, N->getOperand(4), N->getOperand(0));
|
||||
}
|
||||
|
||||
if (EnableBranchHint)
|
||||
PCC |= getBranchHint(PCC, FuncInfo, N->getOperand(4));
|
||||
|
||||
SDValue CondCode = SelectCC(N->getOperand(2), N->getOperand(3), CC, dl);
|
||||
SDValue Ops[] = { getI32Imm(PCC, dl), CondCode,
|
||||
N->getOperand(4), N->getOperand(0) };
|
||||
|
135
test/CodeGen/PowerPC/branch-hint.ll
Normal file
135
test/CodeGen/PowerPC/branch-hint.ll
Normal file
@ -0,0 +1,135 @@
|
||||
; RUN: llc < %s -O1 -verify-machineinstrs -mtriple=powerpc64-unknown-linux-gnu -ppc-use-branch-hint=false | FileCheck %s
|
||||
; RUN: llc < %s -O1 -verify-machineinstrs -mtriple=powerpc64-unknown-linux-gnu -ppc-use-branch-hint=true | FileCheck %s -check-prefix=CHECK-HINT
|
||||
define void @branch_hint_1(i32 %src) {
|
||||
entry:
|
||||
%cmp = icmp eq i32 %src, 0
|
||||
br i1 %cmp, label %if.then, label %if.end
|
||||
|
||||
if.then:
|
||||
tail call void @foo() #0
|
||||
unreachable
|
||||
|
||||
if.end:
|
||||
call void @goo()
|
||||
ret void
|
||||
|
||||
; CHECK-LABEL: branch_hint_1:
|
||||
; CHECK: beq
|
||||
|
||||
; CHECK-HINT-LABEL: branch_hint_1:
|
||||
; CHECK-HINT: beq-
|
||||
}
|
||||
|
||||
define void @branch_hint_2(i32 %src) {
|
||||
entry:
|
||||
%cmp = icmp eq i32 %src, 0
|
||||
br i1 %cmp, label %if.then, label %if.end
|
||||
|
||||
if.then:
|
||||
call void @goo()
|
||||
ret void
|
||||
|
||||
if.end:
|
||||
tail call void @foo() #0
|
||||
unreachable
|
||||
|
||||
; CHECK-LABEL: @branch_hint_2
|
||||
; CHECK: bne
|
||||
|
||||
; CHECK-HINT-LABEL: @branch_hint_2
|
||||
; CHECK-HINT: bne-
|
||||
}
|
||||
|
||||
declare void @foo()
|
||||
attributes #0 = { noreturn }
|
||||
|
||||
define void @branch_hint_3(i32 %src) {
|
||||
entry:
|
||||
%cmp = icmp eq i32 %src, 0
|
||||
br i1 %cmp, label %if.then, label %if.end, !prof !0
|
||||
|
||||
if.then:
|
||||
call void @foo()
|
||||
ret void
|
||||
|
||||
if.end:
|
||||
call void @goo()
|
||||
ret void
|
||||
|
||||
; CHECK-LABEL: @branch_hint_3
|
||||
; CHECK: bne
|
||||
|
||||
; CHECK-HINT-LABEL: @branch_hint_3
|
||||
; CHECK-HINT: bne
|
||||
}
|
||||
|
||||
!0 = !{!"branch_weights", i32 64, i32 4}
|
||||
|
||||
define void @branch_hint_4(i32 %src) {
|
||||
entry:
|
||||
%cmp = icmp eq i32 %src, 0
|
||||
br i1 %cmp, label %if.then, label %if.end, !prof !1
|
||||
|
||||
if.then:
|
||||
call void @foo()
|
||||
ret void
|
||||
|
||||
if.end:
|
||||
call void @goo()
|
||||
ret void
|
||||
|
||||
; CHECK-HINT-LABEL: branch_hint_4
|
||||
; CHECK-HINT: bne
|
||||
}
|
||||
|
||||
!1 = !{!"branch_weights", i32 64, i32 8}
|
||||
|
||||
define void @branch_hint_5(i32 %src) {
|
||||
entry:
|
||||
%cmp = icmp eq i32 %src, 0
|
||||
br i1 %cmp, label %if.then, label %if.end
|
||||
|
||||
if.then:
|
||||
ret void
|
||||
|
||||
if.end:
|
||||
call void @goo()
|
||||
ret void
|
||||
|
||||
; CHECK-HINT-LABEL: branch_hint_5:
|
||||
; CHECK-HINT: beq
|
||||
}
|
||||
|
||||
declare void @goo()
|
||||
|
||||
define void @branch_hint_6(i32 %src1, i32 %src2, i32 %src3) {
|
||||
entry:
|
||||
%cmp = icmp eq i32 %src1, 0
|
||||
br i1 %cmp, label %if.end.6, label %if.end, !prof !3
|
||||
|
||||
if.end:
|
||||
%cmp1 = icmp eq i32 %src2, 0
|
||||
br i1 %cmp1, label %if.end.3, label %if.then.2
|
||||
|
||||
if.then.2:
|
||||
tail call void @foo() #0
|
||||
unreachable
|
||||
|
||||
if.end.3:
|
||||
%cmp4 = icmp eq i32 %src3, 1
|
||||
br i1 %cmp4, label %if.then.5, label %if.end.6
|
||||
|
||||
if.then.5:
|
||||
tail call void @foo() #0
|
||||
unreachable
|
||||
|
||||
if.end.6:
|
||||
ret void
|
||||
|
||||
; CHECK-HINT-LABEL: branch_hint_6:
|
||||
; CHECK-HINT: bne
|
||||
; CHECK-HINT: bne-
|
||||
; CHECK-HINT: bne+
|
||||
}
|
||||
|
||||
!3 = !{!"branch_weights", i32 64, i32 4}
|
Loading…
x
Reference in New Issue
Block a user