1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-23 11:13:28 +01:00

[Profile] Enhance expect lowering to handle correlated branches

builtin_expect applied on && or || expressions were not
handled properly before. With this patch, the problem is fixed.

Differential Revision: http://reviews.llvm.org/D33164

llvm-svn: 304517
This commit is contained in:
Xinliang David Li 2017-06-02 02:09:31 +00:00
parent e27877efb8
commit 7623117f61
4 changed files with 663 additions and 0 deletions

View File

@ -14,6 +14,7 @@
#include "llvm/Transforms/Scalar/LowerExpectIntrinsic.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/ADT/iterator_range.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/Function.h"
@ -83,6 +84,149 @@ static bool handleSwitchExpect(SwitchInst &SI) {
return true;
}
/// Handler for PHINodes that define the value argument to an
/// @llvm.expect call.
///
/// If the operand of the phi has a constant value and it 'contradicts'
/// with the expected value of phi def, then the corresponding incoming
/// edge of the phi is unlikely to be taken. Using that information,
/// the branch probability info for the originating branch can be inferred.
static void handlePhiDef(CallInst *Expect) {
Value &Arg = *Expect->getArgOperand(0);
ConstantInt *ExpectedValue = cast<ConstantInt>(Expect->getArgOperand(1));
const APInt &ExpectedPhiValue = ExpectedValue->getValue();
// Walk up in backward a list of instructions that
// have 'copy' semantics by 'stripping' the copies
// until a PHI node or an instruction of unknown kind
// is reached. Negation via xor is also handled.
//
// C = PHI(...);
// B = C;
// A = B;
// D = __builtin_expect(A, 0);
//
Value *V = &Arg;
SmallVector<Instruction *, 4> Operations;
while (!isa<PHINode>(V)) {
if (ZExtInst *ZExt = dyn_cast<ZExtInst>(V)) {
V = ZExt->getOperand(0);
Operations.push_back(ZExt);
continue;
}
if (SExtInst *SExt = dyn_cast<SExtInst>(V)) {
V = SExt->getOperand(0);
Operations.push_back(SExt);
continue;
}
BinaryOperator *BinOp = dyn_cast<BinaryOperator>(V);
if (!BinOp || BinOp->getOpcode() != Instruction::Xor)
return;
ConstantInt *CInt = dyn_cast<ConstantInt>(BinOp->getOperand(1));
if (!CInt)
return;
V = BinOp->getOperand(0);
Operations.push_back(BinOp);
}
// Executes the recorded operations on input 'Value'.
auto ApplyOperations = [&](const APInt &Value) {
APInt Result = Value;
for (auto Op : llvm::reverse(Operations)) {
switch (Op->getOpcode()) {
case Instruction::Xor:
Result ^= cast<ConstantInt>(Op->getOperand(1))->getValue();
break;
case Instruction::ZExt:
Result = Result.zext(Op->getType()->getIntegerBitWidth());
break;
case Instruction::SExt:
Result = Result.sext(Op->getType()->getIntegerBitWidth());
break;
default:
llvm_unreachable("Unexpected operation");
}
}
return Result;
};
auto *PhiDef = dyn_cast<PHINode>(V);
// Get the first dominating conditional branch of the operand
// i's incoming block.
auto GetDomConditional = [&](unsigned i) -> BranchInst * {
BasicBlock *BB = PhiDef->getIncomingBlock(i);
BranchInst *BI = dyn_cast<BranchInst>(BB->getTerminator());
if (BI && BI->isConditional())
return BI;
BB = BB->getSinglePredecessor();
if (!BB)
return nullptr;
BI = dyn_cast<BranchInst>(BB->getTerminator());
if (!BI || BI->isUnconditional())
return nullptr;
return BI;
};
// Now walk through all Phi operands to find phi oprerands with values
// conflicting with the expected phi output value. Any such operand
// indicates the incoming edge to that operand is unlikely.
for (unsigned i = 0, e = PhiDef->getNumIncomingValues(); i != e; ++i) {
Value *PhiOpnd = PhiDef->getIncomingValue(i);
ConstantInt *CI = dyn_cast<ConstantInt>(PhiOpnd);
if (!CI)
continue;
// Not an interesting case when IsUnlikely is false -- we can not infer
// anything useful when the operand value matches the expected phi
// output.
if (ExpectedPhiValue == ApplyOperations(CI->getValue()))
continue;
BranchInst *BI = GetDomConditional(i);
if (!BI)
continue;
MDBuilder MDB(PhiDef->getContext());
// There are two situations in which an operand of the PhiDef comes
// from a given successor of a branch instruction BI.
// 1) When the incoming block of the operand is the successor block;
// 2) When the incoming block is BI's enclosing block and the
// successor is the PhiDef's enclosing block.
//
// Returns true if the operand which comes from OpndIncomingBB
// comes from outgoing edge of BI that leads to Succ block.
auto *OpndIncomingBB = PhiDef->getIncomingBlock(i);
auto IsOpndComingFromSuccessor = [&](BasicBlock *Succ) {
if (OpndIncomingBB == Succ)
// If this successor is the incoming block for this
// Phi operand, then this successor does lead to the Phi.
return true;
if (OpndIncomingBB == BI->getParent() && Succ == PhiDef->getParent())
// Otherwise, if the edge is directly from the branch
// to the Phi, this successor is the one feeding this
// Phi operand.
return true;
return false;
};
if (IsOpndComingFromSuccessor(BI->getSuccessor(1)))
BI->setMetadata(
LLVMContext::MD_prof,
MDB.createBranchWeights(LikelyBranchWeight, UnlikelyBranchWeight));
else if (IsOpndComingFromSuccessor(BI->getSuccessor(0)))
BI->setMetadata(
LLVMContext::MD_prof,
MDB.createBranchWeights(UnlikelyBranchWeight, LikelyBranchWeight));
}
}
// Handle both BranchInst and SelectInst.
template <class BrSelInst> static bool handleBrSelExpect(BrSelInst &BSI) {
@ -187,6 +331,10 @@ static bool lowerExpectIntrinsic(Function &F) {
Function *Fn = CI->getCalledFunction();
if (Fn && Fn->getIntrinsicID() == Intrinsic::expect) {
// Before erasing the llvm.expect, walk backward to find
// phi that define llvm.expect's first arg, and
// infer branch probability:
handlePhiDef(CI);
Value *Exp = CI->getArgOperand(0);
CI->replaceAllUsesWith(Exp);
CI->eraseFromParent();

View File

@ -0,0 +1,356 @@
; RUN: opt -lower-expect -S -o - < %s | FileCheck %s
; RUN: opt -S -passes='function(lower-expect)' < %s | FileCheck %s
; The C case
; if (__builtin_expect((x > goo() && y > hoo() && z > too()), 1))
; For the above case, all 3 branches should be annotated.
;
; if (__builtin_expect((x > goo() && y > hoo() && z > too()), 0))
; For the above case, we don't have enough information, so
; only the last branch is annotated.
define void @foo(i32 %arg, i32 %arg1, i32 %arg2, i32 %arg3) {
; CHECK-LABEL: void @foo
bb:
%tmp8 = call i32 @goo()
%tmp9 = icmp sgt i32 %tmp8, %arg
br i1 %tmp9, label %bb10, label %bb18
; CHECK: !prof [[WEIGHT:![0-9]+]]
bb10: ; preds = %bb
%tmp12 = call i32 @hoo()
%tmp13 = icmp sgt i32 %arg1, %tmp12
br i1 %tmp13, label %bb14, label %bb18
; CHECK: br i1 %tmp13, {{.*}}!prof [[WEIGHT]]
bb14: ; preds = %bb10
%tmp16 = call i32 @too()
%tmp17 = icmp sgt i32 %arg2, %tmp16
br label %bb18
bb18: ; preds = %bb14, %bb10, %bb
%tmp19 = phi i1 [ false, %bb10 ], [ false, %bb ], [ %tmp17, %bb14 ]
%tmp20 = xor i1 %tmp19, true
%tmp21 = xor i1 %tmp20, true
%tmp22 = zext i1 %tmp21 to i32
%tmp23 = sext i32 %tmp22 to i64
%tmp24 = call i64 @llvm.expect.i64(i64 %tmp23, i64 1)
%tmp25 = icmp ne i64 %tmp24, 0
br i1 %tmp25, label %bb26, label %bb28
; CHECK: br i1 %tmp25,{{.*}}!prof [[WEIGHT]]
bb26: ; preds = %bb18
%tmp27 = call i32 @goo()
br label %bb30
bb28: ; preds = %bb18
%tmp29 = call i32 @hoo()
br label %bb30
bb30: ; preds = %bb28, %bb26
ret void
}
define void @foo2(i32 %arg, i32 %arg1, i32 %arg2, i32 %arg3) {
; CHECK-LABEL: void @foo2
bb:
%tmp8 = call i32 @goo()
%tmp9 = icmp sgt i32 %tmp8, %arg
br i1 %tmp9, label %bb10, label %bb18
; CHECK: br i1 %tmp9
; CHECK-NOT: !prof
bb10: ; preds = %bb
%tmp12 = call i32 @hoo()
%tmp13 = icmp sgt i32 %arg1, %tmp12
br i1 %tmp13, label %bb14, label %bb18
; CHECK: br i1 %tmp13
; CHECK-NOT: !prof
bb14: ; preds = %bb10
%tmp16 = call i32 @too()
%tmp17 = icmp sgt i32 %arg2, %tmp16
br label %bb18
bb18: ; preds = %bb14, %bb10, %bb
%tmp19 = phi i1 [ false, %bb10 ], [ false, %bb ], [ %tmp17, %bb14 ]
%tmp20 = xor i1 %tmp19, true
%tmp21 = xor i1 %tmp20, true
%tmp22 = zext i1 %tmp21 to i32
%tmp23 = sext i32 %tmp22 to i64
%tmp24 = call i64 @llvm.expect.i64(i64 %tmp23, i64 0)
%tmp25 = icmp ne i64 %tmp24, 0
br i1 %tmp25, label %bb26, label %bb28
; CHECK: br i1 %tmp25,{{.*}}!prof [[WEIGHT2:![0-9]+]]
bb26: ; preds = %bb18
%tmp27 = call i32 @goo()
br label %bb30
bb28: ; preds = %bb18
%tmp29 = call i32 @hoo()
br label %bb30
bb30: ; preds = %bb28, %bb26
ret void
}
define void @foo_i32(i32 %arg, i32 %arg1, i32 %arg2, i32 %arg3) {
; CHECK-LABEL: void @foo_i32
bb:
%tmp8 = call i32 @goo()
%tmp9 = icmp sgt i32 %tmp8, %arg
br i1 %tmp9, label %bb10, label %bb18
; CHECK: !prof [[WEIGHT]]
bb10: ; preds = %bb
%tmp12 = call i32 @hoo()
%tmp13 = icmp sgt i32 %arg1, %tmp12
br i1 %tmp13, label %bb14, label %bb18
; CHECK: br i1 %tmp13, {{.*}}!prof [[WEIGHT]]
bb14: ; preds = %bb10
%tmp16 = call i32 @too()
%tmp17 = icmp sgt i32 %arg2, %tmp16
br label %bb18
bb18: ; preds = %bb14, %bb10, %bb
%tmp19 = phi i32 [ 5, %bb10 ], [ 5, %bb ], [ %tmp16, %bb14 ]
%tmp23 = sext i32 %tmp19 to i64
%tmp24 = call i64 @llvm.expect.i64(i64 %tmp23, i64 4)
%tmp25 = icmp ne i64 %tmp24, 0
br i1 %tmp25, label %bb26, label %bb28
; CHECK: br i1 %tmp25,{{.*}}!prof [[WEIGHT]]
bb26: ; preds = %bb18
%tmp27 = call i32 @goo()
br label %bb30
bb28: ; preds = %bb18
%tmp29 = call i32 @hoo()
br label %bb30
bb30: ; preds = %bb28, %bb26
ret void
}
define void @foo_i32_not_unlikely(i32 %arg, i32 %arg1, i32 %arg2, i32 %arg3) {
; CHECK-LABEL: void @foo_i32_not_unlikely
bb:
%tmp8 = call i32 @goo()
%tmp9 = icmp sgt i32 %tmp8, %arg
br i1 %tmp9, label %bb10, label %bb18
; CHECK: br i1 %tmp9
; CHECK-NOT: !prof
bb10: ; preds = %bb
%tmp12 = call i32 @hoo()
%tmp13 = icmp sgt i32 %arg1, %tmp12
br i1 %tmp13, label %bb14, label %bb18
; CHECK: br i1 %tmp13
; CHECK-NOT: !prof
bb14: ; preds = %bb10
%tmp16 = call i32 @too()
%tmp17 = icmp sgt i32 %arg2, %tmp16
br label %bb18
bb18: ; preds = %bb14, %bb10, %bb
%tmp19 = phi i32 [ 4, %bb10 ], [ 4, %bb ], [ %tmp16, %bb14 ]
%tmp23 = sext i32 %tmp19 to i64
%tmp24 = call i64 @llvm.expect.i64(i64 %tmp23, i64 4)
%tmp25 = icmp ne i64 %tmp24, 0
br i1 %tmp25, label %bb26, label %bb28
; CHECK: br i1 %tmp25,{{.*}}!prof [[WEIGHT]]
bb26: ; preds = %bb18
%tmp27 = call i32 @goo()
br label %bb30
bb28: ; preds = %bb18
%tmp29 = call i32 @hoo()
br label %bb30
bb30: ; preds = %bb28, %bb26
ret void
}
define void @foo_i32_xor(i32 %arg, i32 %arg1, i32 %arg2, i32 %arg3) {
; CHECK-LABEL: void @foo_i32_xor
bb:
%tmp8 = call i32 @goo()
%tmp9 = icmp sgt i32 %tmp8, %arg
br i1 %tmp9, label %bb10, label %bb18
; CHECK: br i1 %tmp9,{{.*}}!prof [[WEIGHT]]
bb10: ; preds = %bb
%tmp12 = call i32 @hoo()
%tmp13 = icmp sgt i32 %arg1, %tmp12
br i1 %tmp13, label %bb14, label %bb18
; CHECK: br i1 %tmp13,{{.*}}!prof [[WEIGHT]]
bb14: ; preds = %bb10
%tmp16 = call i32 @too()
%tmp17 = icmp sgt i32 %arg2, %tmp16
br label %bb18
bb18: ; preds = %bb14, %bb10, %bb
%tmp19 = phi i32 [ 6, %bb10 ], [ 6, %bb ], [ %tmp16, %bb14 ]
%tmp20 = xor i32 %tmp19, 3
%tmp23 = sext i32 %tmp20 to i64
%tmp24 = call i64 @llvm.expect.i64(i64 %tmp23, i64 4)
%tmp25 = icmp ne i64 %tmp24, 0
br i1 %tmp25, label %bb26, label %bb28
; CHECK: br i1 %tmp25,{{.*}}!prof [[WEIGHT]]
bb26: ; preds = %bb18
%tmp27 = call i32 @goo()
br label %bb30
bb28: ; preds = %bb18
%tmp29 = call i32 @hoo()
br label %bb30
bb30: ; preds = %bb28, %bb26
ret void
}
define void @foo_i8_sext(i32 %arg, i32 %arg1, i8 %arg2, i32 %arg3) {
; CHECK-LABEL: void @foo_i8_sext
bb:
%tmp8 = call i32 @goo()
%tmp9 = icmp sgt i32 %tmp8, %arg
br i1 %tmp9, label %bb10, label %bb18
; CHECK: br i1 %tmp9,{{.*}}!prof [[WEIGHT]]
bb10: ; preds = %bb
%tmp12 = call i32 @hoo()
%tmp13 = icmp sgt i32 %arg1, %tmp12
br i1 %tmp13, label %bb14, label %bb18
; CHECK: br i1 %tmp13,{{.*}}!prof [[WEIGHT]]
bb14: ; preds = %bb10
%tmp16 = call i8 @too8()
%tmp17 = icmp sgt i8 %arg2, %tmp16
br label %bb18
bb18: ; preds = %bb14, %bb10, %bb
%tmp19 = phi i8 [ 255, %bb10 ], [ 255, %bb ], [ %tmp16, %bb14 ]
%tmp23 = sext i8 %tmp19 to i64
; after sign extension, the operand value becomes -1 which does not match 255
%tmp24 = call i64 @llvm.expect.i64(i64 %tmp23, i64 255)
%tmp25 = icmp ne i64 %tmp24, 0
br i1 %tmp25, label %bb26, label %bb28
; CHECK: br i1 %tmp25,{{.*}}!prof [[WEIGHT]]
bb26: ; preds = %bb18
%tmp27 = call i32 @goo()
br label %bb30
bb28: ; preds = %bb18
%tmp29 = call i32 @hoo()
br label %bb30
bb30: ; preds = %bb28, %bb26
ret void
}
define void @foo_i8_sext_not_unlikely(i32 %arg, i32 %arg1, i8 %arg2, i32 %arg3) {
; CHECK-LABEL: void @foo_i8_sext_not_unlikely
bb:
%tmp8 = call i32 @goo()
%tmp9 = icmp sgt i32 %tmp8, %arg
br i1 %tmp9, label %bb10, label %bb18
; CHECK: br i1 %tmp9
; CHECK-NOT: !prof
bb10: ; preds = %bb
%tmp12 = call i32 @hoo()
%tmp13 = icmp sgt i32 %arg1, %tmp12
br i1 %tmp13, label %bb14, label %bb18
; CHECK: br i1 %tmp13
; CHECK-NOT: !prof
bb14: ; preds = %bb10
%tmp16 = call i8 @too8()
%tmp17 = icmp sgt i8 %arg2, %tmp16
br label %bb18
bb18: ; preds = %bb14, %bb10, %bb
%tmp19 = phi i8 [ 255, %bb10 ], [ 255, %bb ], [ %tmp16, %bb14 ]
%tmp23 = sext i8 %tmp19 to i64
; after sign extension, the operand value becomes -1 which matches -1
%tmp24 = call i64 @llvm.expect.i64(i64 %tmp23, i64 -1)
%tmp25 = icmp ne i64 %tmp24, 0
br i1 %tmp25, label %bb26, label %bb28
; CHECK: br i1 %tmp25,{{.*}}!prof [[WEIGHT]]
bb26: ; preds = %bb18
%tmp27 = call i32 @goo()
br label %bb30
bb28: ; preds = %bb18
%tmp29 = call i32 @hoo()
br label %bb30
bb30: ; preds = %bb28, %bb26
ret void
}
define void @foo_i32_xor_not_unlikely(i32 %arg, i32 %arg1, i32 %arg2, i32 %arg3) {
; CHECK-LABEL: void @foo_i32_xor_not_unlikely
bb:
%tmp8 = call i32 @goo()
%tmp9 = icmp sgt i32 %tmp8, %arg
br i1 %tmp9, label %bb10, label %bb18
; CHECK: br i1 %tmp9
; CHECK-NOT: !prof
bb10: ; preds = %bb
%tmp12 = call i32 @hoo()
%tmp13 = icmp sgt i32 %arg1, %tmp12
br i1 %tmp13, label %bb14, label %bb18
; CHECK: br i1 %tmp13
; CHECK-NOT: !prof
bb14: ; preds = %bb10
%tmp16 = call i32 @too()
%tmp17 = icmp sgt i32 %arg2, %tmp16
br label %bb18
bb18: ; preds = %bb14, %bb10, %bb
%tmp19 = phi i32 [ 6, %bb10 ], [ 6, %bb ], [ %tmp16, %bb14 ]
%tmp20 = xor i32 %tmp19, 2
%tmp23 = sext i32 %tmp20 to i64
%tmp24 = call i64 @llvm.expect.i64(i64 %tmp23, i64 4)
%tmp25 = icmp ne i64 %tmp24, 0
br i1 %tmp25, label %bb26, label %bb28
; CHECK: br i1 %tmp25,{{.*}}!prof [[WEIGHT]]
bb26: ; preds = %bb18
%tmp27 = call i32 @goo()
br label %bb30
bb28: ; preds = %bb18
%tmp29 = call i32 @hoo()
br label %bb30
bb30: ; preds = %bb28, %bb26
ret void
}
declare i32 @goo()
declare i32 @hoo()
declare i32 @too()
declare i8 @too8()
; Function Attrs: nounwind readnone
declare i64 @llvm.expect.i64(i64, i64)
!llvm.ident = !{!0}
!0 = !{!"clang version 5.0.0 (trunk 302965)"}
; CHECK: [[WEIGHT]] = !{!"branch_weights", i32 2000, i32 1}
; CHECK: [[WEIGHT2]] = !{!"branch_weights", i32 1, i32 2000}

View File

@ -0,0 +1,103 @@
; RUN: opt -lower-expect -S -o - < %s | FileCheck %s
; RUN: opt -S -passes='function(lower-expect)' < %s | FileCheck %s
;
; if (__builtin_expect((x > goo() || y > hoo()), 1)) {
; ..
; }
; For the above case, only the second branch should be
; annotated.
; if (__builtin_expect((x > goo() || y > hoo()), 0)) {
; ..
; }
; For the above case, two branches should be annotated.
; Function Attrs: noinline nounwind uwtable
define void @foo(i32 %arg, i32 %arg1, i32 %arg2, i32 %arg3) {
; CHECK-LABEL: void @foo
bb:
%tmp8 = call i32 @goo()
%tmp9 = icmp slt i32 %arg, %tmp8
br i1 %tmp9, label %bb14, label %bb10
; CHECK: br i1 %tmp9
; CHECK-NOT: br i1 %tmp9{{.*}}!prof
bb10: ; preds = %bb
%tmp12 = call i32 @hoo()
%tmp13 = icmp sgt i32 %arg1, %tmp12
br label %bb14
bb14: ; preds = %bb10, %bb
%tmp15 = phi i1 [ true, %bb ], [ %tmp13, %bb10 ]
%tmp16 = zext i1 %tmp15 to i32
%tmp17 = sext i32 %tmp16 to i64
%expect = call i64 @llvm.expect.i64(i64 %tmp17, i64 1)
%tmp18 = icmp ne i64 %expect, 0
br i1 %tmp18, label %bb19, label %bb21
; CHECK: br i1 %tmp18{{.*}}!prof [[WEIGHT:![0-9]+]]
bb19: ; preds = %bb14
%tmp20 = call i32 @goo()
br label %bb23
bb21: ; preds = %bb14
%tmp22 = call i32 @hoo()
br label %bb23
bb23: ; preds = %bb21, %bb19
ret void
}
define void @foo2(i32 %arg, i32 %arg1, i32 %arg2, i32 %arg3) {
; CHECK-LABEL: void @foo2
bb:
%tmp = alloca i32, align 4
%tmp4 = alloca i32, align 4
%tmp5 = alloca i32, align 4
%tmp6 = alloca i32, align 4
store i32 %arg, i32* %tmp, align 4
store i32 %arg1, i32* %tmp4, align 4
store i32 %arg2, i32* %tmp5, align 4
store i32 %arg3, i32* %tmp6, align 4
%tmp7 = load i32, i32* %tmp, align 4
%tmp8 = call i32 @goo()
%tmp9 = icmp slt i32 %tmp7, %tmp8
br i1 %tmp9, label %bb14, label %bb10
; CHECK: br i1 %tmp9{{.*}}!prof [[WEIGHT2:![0-9]+]]
bb10: ; preds = %bb
%tmp11 = load i32, i32* %tmp5, align 4
%tmp12 = call i32 @hoo()
%tmp13 = icmp sgt i32 %tmp11, %tmp12
br label %bb14
bb14: ; preds = %bb10, %bb
%tmp15 = phi i1 [ true, %bb ], [ %tmp13, %bb10 ]
%tmp16 = zext i1 %tmp15 to i32
%tmp17 = sext i32 %tmp16 to i64
%expect = call i64 @llvm.expect.i64(i64 %tmp17, i64 0)
%tmp18 = icmp ne i64 %expect, 0
br i1 %tmp18, label %bb19, label %bb21
; CHECK: br i1 %tmp18{{.*}}!prof [[WEIGHT2]]
bb19: ; preds = %bb14
%tmp20 = call i32 @goo()
br label %bb23
bb21: ; preds = %bb14
%tmp22 = call i32 @hoo()
br label %bb23
bb23: ; preds = %bb21, %bb19
ret void
}
declare i32 @goo()
declare i32 @hoo()
declare i64 @llvm.expect.i64(i64, i64)
!llvm.ident = !{!0}
!0 = !{!"clang version 5.0.0 (trunk 302965)"}
; CHECK: [[WEIGHT]] = !{!"branch_weights", i32 2000, i32 1}
; CHECK: [[WEIGHT2]] = !{!"branch_weights", i32 1, i32 2000}

View File

@ -0,0 +1,56 @@
; RUN: opt -lower-expect -S -o - < %s | FileCheck %s
; RUN: opt -S -passes='function(lower-expect)' < %s | FileCheck %s
; return __builtin_expect((a > b ? 1, goo(), 0);
;
; Function Attrs: noinline nounwind uwtable
define i32 @foo(i32 %arg, i32 %arg1) {
; CHECK-LABEL: i32 @foo
bb:
%tmp5 = icmp sgt i32 %arg, %arg1
br i1 %tmp5, label %bb9, label %bb7
; CHECK: br i1 %tmp5{{.*}}!prof [[WEIGHT:![0-9]+]]
bb7: ; preds = %bb
%tmp8 = call i32 @goo()
br label %bb9
bb9: ; preds = %bb7, %bb9
%tmp10 = phi i32 [ 1, %bb ], [ %tmp8, %bb7 ]
%tmp11 = sext i32 %tmp10 to i64
%expect = call i64 @llvm.expect.i64(i64 %tmp11, i64 0)
%tmp12 = trunc i64 %expect to i32
ret i32 %tmp12
}
define i32 @foo2(i32 %arg, i32 %arg1) {
bb:
%tmp5 = icmp sgt i32 %arg, %arg1
br i1 %tmp5, label %bb6, label %bb7
; CHECK: br i1 %tmp5{{.*}}!prof [[WEIGHT:![0-9]+]]
bb6: ; preds = %bb
br label %bb9
bb7: ; preds = %bb
%tmp8 = call i32 @goo()
br label %bb9
bb9: ; preds = %bb7, %bb6
%tmp10 = phi i32 [ 1, %bb6 ], [ %tmp8, %bb7 ]
%tmp11 = sext i32 %tmp10 to i64
%expect = call i64 @llvm.expect.i64(i64 %tmp11, i64 0)
%tmp12 = trunc i64 %expect to i32
ret i32 %tmp12
}
declare i32 @goo()
declare i64 @llvm.expect.i64(i64, i64)
!llvm.ident = !{!0}
!0 = !{!"clang version 5.0.0 (trunk 302965)"}
; CHECK: [[WEIGHT]] = !{!"branch_weights", i32 1, i32 2000}