[clang][CodeGen] Lower Likelihood attributes to @llvm.expect intrin instead of branch weights

08196e0b2e exposed LowerExpectIntrinsic's
internal implementation detail in the form of
LikelyBranchWeight/UnlikelyBranchWeight options to the outside.

While this isn't incorrect from the results viewpoint,
this is suboptimal from the layering viewpoint,
and causes confusion - should transforms also use those weights,
or should they use something else, D98898?

So go back to status quo by making LikelyBranchWeight/UnlikelyBranchWeight
internal again, and fixing all the code that used it directly,
which currently is only clang codegen, thankfully,
to emit proper @llvm.expect intrinsics instead.
This commit is contained in:
Roman Lebedev 2021-03-21 22:13:47 +03:00
parent 37d6be9052
commit e3a4701627
No known key found for this signature in database
GPG Key ID: 083C3EBB4A1689E0
7 changed files with 524 additions and 157 deletions

View File

@ -821,8 +821,11 @@ void CodeGenFunction::EmitWhileStmt(const WhileStmt &S,
llvm::BasicBlock *ExitBlock = LoopExit.getBlock();
if (ConditionScope.requiresCleanups())
ExitBlock = createBasicBlock("while.exit");
llvm::MDNode *Weights = createProfileOrBranchWeightsForLoop(
S.getCond(), getProfileCount(S.getBody()), S.getBody());
llvm::MDNode *Weights =
createProfileWeightsForLoop(S.getCond(), getProfileCount(S.getBody()));
if (!Weights && CGM.getCodeGenOpts().OptimizationLevel)
BoolCondVal = emitCondLikelihoodViaExpectIntrinsic(
BoolCondVal, Stmt::getLikelihood(S.getBody()));
Builder.CreateCondBr(BoolCondVal, LoopBody, ExitBlock, Weights);
if (ExitBlock != LoopExit.getBlock()) {
@ -1008,8 +1011,11 @@ void CodeGenFunction::EmitForStmt(const ForStmt &S,
// C99 6.8.5p2/p4: The first substatement is executed if the expression
// compares unequal to 0. The condition must be a scalar type.
llvm::Value *BoolCondVal = EvaluateExprAsBool(S.getCond());
llvm::MDNode *Weights = createProfileOrBranchWeightsForLoop(
S.getCond(), getProfileCount(S.getBody()), S.getBody());
llvm::MDNode *Weights =
createProfileWeightsForLoop(S.getCond(), getProfileCount(S.getBody()));
if (!Weights && CGM.getCodeGenOpts().OptimizationLevel)
BoolCondVal = emitCondLikelihoodViaExpectIntrinsic(
BoolCondVal, Stmt::getLikelihood(S.getBody()));
if (llvm::ConstantInt *C = dyn_cast<llvm::ConstantInt>(BoolCondVal))
if (C->isOne())
@ -1094,8 +1100,11 @@ CodeGenFunction::EmitCXXForRangeStmt(const CXXForRangeStmt &S,
// The body is executed if the expression, contextually converted
// to bool, is true.
llvm::Value *BoolCondVal = EvaluateExprAsBool(S.getCond());
llvm::MDNode *Weights = createProfileOrBranchWeightsForLoop(
S.getCond(), getProfileCount(S.getBody()), S.getBody());
llvm::MDNode *Weights =
createProfileWeightsForLoop(S.getCond(), getProfileCount(S.getBody()));
if (!Weights && CGM.getCodeGenOpts().OptimizationLevel)
BoolCondVal = emitCondLikelihoodViaExpectIntrinsic(
BoolCondVal, Stmt::getLikelihood(S.getBody()));
Builder.CreateCondBr(BoolCondVal, ForBody, ExitBlock, Weights);
if (ExitBlock != LoopExit.getBlock()) {
@ -1369,7 +1378,7 @@ void CodeGenFunction::EmitCaseStmtRange(const CaseStmt &S,
// this case.
(*SwitchWeights)[0] += ThisCount;
} else if (SwitchLikelihood)
Weights = createBranchWeights(LH);
Cond = emitCondLikelihoodViaExpectIntrinsic(Cond, LH);
Builder.CreateCondBr(Cond, CaseDest, FalseDest, Weights);

View File

@ -1764,31 +1764,39 @@ void CodeGenFunction::EmitBranchOnBoolExpr(const Expr *Cond,
return;
}
// If the branch has a condition wrapped by __builtin_unpredictable,
// create metadata that specifies that the branch is unpredictable.
// Don't bother if not optimizing because that metadata would not be used.
llvm::MDNode *Unpredictable = nullptr;
auto *Call = dyn_cast<CallExpr>(Cond->IgnoreImpCasts());
if (Call && CGM.getCodeGenOpts().OptimizationLevel != 0) {
auto *FD = dyn_cast_or_null<FunctionDecl>(Call->getCalleeDecl());
if (FD && FD->getBuiltinID() == Builtin::BI__builtin_unpredictable) {
llvm::MDBuilder MDHelper(getLLVMContext());
Unpredictable = MDHelper.createUnpredictable();
}
}
llvm::MDNode *Weights = createBranchWeights(LH);
if (!Weights) {
uint64_t CurrentCount = std::max(getCurrentProfileCount(), TrueCount);
Weights = createProfileWeights(TrueCount, CurrentCount - TrueCount);
}
// Emit the code with the fully general case.
llvm::Value *CondV;
{
ApplyDebugLocation DL(*this, Cond);
CondV = EvaluateExprAsBool(Cond);
}
llvm::MDNode *Weights = nullptr;
llvm::MDNode *Unpredictable = nullptr;
// If optimizing, lower unpredictability/probability knowledge about cond.
if (CGM.getCodeGenOpts().OptimizationLevel != 0) {
// If the branch has a condition wrapped by __builtin_unpredictable,
// create metadata that specifies that the branch is unpredictable.
if (auto *Call = dyn_cast<CallExpr>(Cond->IgnoreImpCasts())) {
auto *FD = dyn_cast_or_null<FunctionDecl>(Call->getCalleeDecl());
if (FD && FD->getBuiltinID() == Builtin::BI__builtin_unpredictable) {
llvm::MDBuilder MDHelper(getLLVMContext());
Unpredictable = MDHelper.createUnpredictable();
}
}
// If there is a Likelihood knowledge for the cond, lower it.
llvm::Value *NewCondV = emitCondLikelihoodViaExpectIntrinsic(CondV, LH);
if (CondV != NewCondV)
CondV = NewCondV;
else {
// Otherwise, lower profile counts.
uint64_t CurrentCount = std::max(getCurrentProfileCount(), TrueCount);
Weights = createProfileWeights(TrueCount, CurrentCount - TrueCount);
}
}
Builder.CreateCondBr(CondV, TrueBlock, FalseBlock, Weights, Unpredictable);
}
@ -2632,35 +2640,26 @@ llvm::DebugLoc CodeGenFunction::SourceLocToDebugLoc(SourceLocation Location) {
return llvm::DebugLoc();
}
static Optional<std::pair<uint32_t, uint32_t>>
getLikelihoodWeights(Stmt::Likelihood LH) {
llvm::Value *
CodeGenFunction::emitCondLikelihoodViaExpectIntrinsic(llvm::Value *Cond,
Stmt::Likelihood LH) {
switch (LH) {
case Stmt::LH_Unlikely:
return std::pair<uint32_t, uint32_t>(llvm::UnlikelyBranchWeight,
llvm::LikelyBranchWeight);
case Stmt::LH_None:
return None;
return Cond;
case Stmt::LH_Likely:
return std::pair<uint32_t, uint32_t>(llvm::LikelyBranchWeight,
llvm::UnlikelyBranchWeight);
case Stmt::LH_Unlikely:
// Don't generate llvm.expect on -O0 as the backend won't use it for
// anything.
if (CGM.getCodeGenOpts().OptimizationLevel == 0)
return Cond;
llvm::Type *CondTy = Cond->getType();
assert(CondTy->isIntegerTy(1) && "expecting condition to be a boolean");
llvm::Function *FnExpect =
CGM.getIntrinsic(llvm::Intrinsic::expect, CondTy);
llvm::Value *ExpectedValueOfCond =
llvm::ConstantInt::getBool(CondTy, LH == Stmt::LH_Likely);
return Builder.CreateCall(FnExpect, {Cond, ExpectedValueOfCond},
Cond->getName() + ".expval");
}
llvm_unreachable("Unknown Likelihood");
}
llvm::MDNode *CodeGenFunction::createBranchWeights(Stmt::Likelihood LH) const {
Optional<std::pair<uint32_t, uint32_t>> LHW = getLikelihoodWeights(LH);
if (!LHW)
return nullptr;
llvm::MDBuilder MDHelper(CGM.getLLVMContext());
return MDHelper.createBranchWeights(LHW->first, LHW->second);
}
llvm::MDNode *CodeGenFunction::createProfileOrBranchWeightsForLoop(
const Stmt *Cond, uint64_t LoopCount, const Stmt *Body) const {
llvm::MDNode *Weights = createProfileWeightsForLoop(Cond, LoopCount);
if (!Weights && CGM.getCodeGenOpts().OptimizationLevel)
Weights = createBranchWeights(Stmt::getLikelihood(Body));
return Weights;
}

View File

@ -1445,8 +1445,9 @@ private:
};
OpenMPCancelExitStack OMPCancelStack;
/// Calculate branch weights for the likelihood attribute
llvm::MDNode *createBranchWeights(Stmt::Likelihood LH) const;
/// Lower the Likelihood knowledge about the \p Cond via llvm.expect intrin.
llvm::Value *emitCondLikelihoodViaExpectIntrinsic(llvm::Value *Cond,
Stmt::Likelihood LH);
CodeGenPGO PGO;
@ -1457,13 +1458,6 @@ private:
llvm::MDNode *createProfileWeightsForLoop(const Stmt *Cond,
uint64_t LoopCount) const;
/// Calculate the branch weight for PGO data or the likelihood attribute.
/// The function tries to get the weight of \ref createProfileWeightsForLoop.
/// If that fails it gets the weight of \ref createBranchWeights.
llvm::MDNode *createProfileOrBranchWeightsForLoop(const Stmt *Cond,
uint64_t LoopCount,
const Stmt *Body) const;
public:
/// Increment the profiler's counter for the given statement by \p StepV.
/// If \p StepV is null, the default increment is 1.

View File

@ -1,60 +1,263 @@
// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py
// RUN: %clang_cc1 -O1 -disable-llvm-passes -emit-llvm %s -o - -triple=x86_64-linux-gnu -verify
// RUN: %clang_cc1 -O1 -disable-llvm-passes -emit-llvm %s -o - -triple=x86_64-linux-gnu | FileCheck %s
// CHECK-LABEL: @_Z2wli(
// CHECK-NEXT: entry:
// CHECK-NEXT: [[E_ADDR:%.*]] = alloca i32, align 4
// CHECK-NEXT: store i32 [[E:%.*]], i32* [[E_ADDR]], align 4, !tbaa [[TBAA2:![0-9]+]]
// CHECK-NEXT: br label [[WHILE_COND:%.*]]
// CHECK: while.cond:
// CHECK-NEXT: [[TMP0:%.*]] = load i32, i32* [[E_ADDR]], align 4, !tbaa [[TBAA2]]
// CHECK-NEXT: [[TOBOOL:%.*]] = icmp ne i32 [[TMP0]], 0
// CHECK-NEXT: [[TOBOOL_EXPVAL:%.*]] = call i1 @llvm.expect.i1(i1 [[TOBOOL]], i1 true)
// CHECK-NEXT: br i1 [[TOBOOL_EXPVAL]], label [[WHILE_BODY:%.*]], label [[WHILE_END:%.*]]
// CHECK: while.body:
// CHECK-NEXT: [[TMP1:%.*]] = load i32, i32* [[E_ADDR]], align 4, !tbaa [[TBAA2]]
// CHECK-NEXT: [[INC:%.*]] = add nsw i32 [[TMP1]], 1
// CHECK-NEXT: store i32 [[INC]], i32* [[E_ADDR]], align 4, !tbaa [[TBAA2]]
// CHECK-NEXT: br label [[WHILE_COND]], !llvm.loop [[LOOP6:![0-9]+]]
// CHECK: while.end:
// CHECK-NEXT: ret void
//
void wl(int e){
// CHECK-LABEL: define{{.*}}wl
// CHECK: br {{.*}} !prof !6
while(e) [[likely]] ++e;
}
// CHECK-LABEL: @_Z2wui(
// CHECK-NEXT: entry:
// CHECK-NEXT: [[E_ADDR:%.*]] = alloca i32, align 4
// CHECK-NEXT: store i32 [[E:%.*]], i32* [[E_ADDR]], align 4, !tbaa [[TBAA2]]
// CHECK-NEXT: br label [[WHILE_COND:%.*]]
// CHECK: while.cond:
// CHECK-NEXT: [[TMP0:%.*]] = load i32, i32* [[E_ADDR]], align 4, !tbaa [[TBAA2]]
// CHECK-NEXT: [[TOBOOL:%.*]] = icmp ne i32 [[TMP0]], 0
// CHECK-NEXT: [[TOBOOL_EXPVAL:%.*]] = call i1 @llvm.expect.i1(i1 [[TOBOOL]], i1 false)
// CHECK-NEXT: br i1 [[TOBOOL_EXPVAL]], label [[WHILE_BODY:%.*]], label [[WHILE_END:%.*]]
// CHECK: while.body:
// CHECK-NEXT: [[TMP1:%.*]] = load i32, i32* [[E_ADDR]], align 4, !tbaa [[TBAA2]]
// CHECK-NEXT: [[INC:%.*]] = add nsw i32 [[TMP1]], 1
// CHECK-NEXT: store i32 [[INC]], i32* [[E_ADDR]], align 4, !tbaa [[TBAA2]]
// CHECK-NEXT: br label [[WHILE_COND]], !llvm.loop [[LOOP9:![0-9]+]]
// CHECK: while.end:
// CHECK-NEXT: ret void
//
void wu(int e){
// CHECK-LABEL: define{{.*}}wu
// CHECK: br {{.*}} !prof !10
while(e) [[unlikely]] ++e;
}
// CHECK-LABEL: @_Z15w_branch_elidedj(
// CHECK-NEXT: entry:
// CHECK-NEXT: [[E_ADDR:%.*]] = alloca i32, align 4
// CHECK-NEXT: store i32 [[E:%.*]], i32* [[E_ADDR]], align 4, !tbaa [[TBAA2]]
// CHECK-NEXT: br label [[WHILE_BODY:%.*]]
// CHECK: while.body:
// CHECK-NEXT: [[TMP0:%.*]] = load i32, i32* [[E_ADDR]], align 4, !tbaa [[TBAA2]]
// CHECK-NEXT: [[INC:%.*]] = add i32 [[TMP0]], 1
// CHECK-NEXT: store i32 [[INC]], i32* [[E_ADDR]], align 4, !tbaa [[TBAA2]]
// CHECK-NEXT: br label [[WHILE_BODY]], !llvm.loop [[LOOP10:![0-9]+]]
//
void w_branch_elided(unsigned e){
// CHECK-LABEL: define{{.*}}w_branch_elided
// CHECK-NOT: br {{.*}} !prof
// expected-warning@+2 {{attribute 'likely' has no effect when annotating an infinite loop}}
// expected-note@+1 {{annotating the infinite loop here}}
while(1) [[likely]] ++e;
}
// CHECK-LABEL: @_Z2flj(
// CHECK-NEXT: entry:
// CHECK-NEXT: [[E_ADDR:%.*]] = alloca i32, align 4
// CHECK-NEXT: [[I:%.*]] = alloca i32, align 4
// CHECK-NEXT: store i32 [[E:%.*]], i32* [[E_ADDR]], align 4, !tbaa [[TBAA2]]
// CHECK-NEXT: [[TMP0:%.*]] = bitcast i32* [[I]] to i8*
// CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 4, i8* [[TMP0]]) #[[ATTR4:[0-9]+]]
// CHECK-NEXT: store i32 0, i32* [[I]], align 4, !tbaa [[TBAA2]]
// CHECK-NEXT: br label [[FOR_COND:%.*]]
// CHECK: for.cond:
// CHECK-NEXT: [[TMP1:%.*]] = load i32, i32* [[I]], align 4, !tbaa [[TBAA2]]
// CHECK-NEXT: [[TMP2:%.*]] = load i32, i32* [[E_ADDR]], align 4, !tbaa [[TBAA2]]
// CHECK-NEXT: [[CMP:%.*]] = icmp ne i32 [[TMP1]], [[TMP2]]
// CHECK-NEXT: [[CMP_EXPVAL:%.*]] = call i1 @llvm.expect.i1(i1 [[CMP]], i1 true)
// CHECK-NEXT: br i1 [[CMP_EXPVAL]], label [[FOR_BODY:%.*]], label [[FOR_COND_CLEANUP:%.*]]
// CHECK: for.cond.cleanup:
// CHECK-NEXT: [[TMP3:%.*]] = bitcast i32* [[I]] to i8*
// CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 4, i8* [[TMP3]]) #[[ATTR4]]
// CHECK-NEXT: br label [[FOR_END:%.*]]
// CHECK: for.body:
// CHECK-NEXT: br label [[FOR_INC:%.*]]
// CHECK: for.inc:
// CHECK-NEXT: [[TMP4:%.*]] = load i32, i32* [[E_ADDR]], align 4, !tbaa [[TBAA2]]
// CHECK-NEXT: [[INC:%.*]] = add i32 [[TMP4]], 1
// CHECK-NEXT: store i32 [[INC]], i32* [[E_ADDR]], align 4, !tbaa [[TBAA2]]
// CHECK-NEXT: br label [[FOR_COND]], !llvm.loop [[LOOP11:![0-9]+]]
// CHECK: for.end:
// CHECK-NEXT: ret void
//
void fl(unsigned e)
{
// CHECK-LABEL: define{{.*}}fl
// CHECK: br {{.*}} !prof !6
for(int i = 0; i != e; ++e) [[likely]];
}
// CHECK-LABEL: @_Z2fui(
// CHECK-NEXT: entry:
// CHECK-NEXT: [[E_ADDR:%.*]] = alloca i32, align 4
// CHECK-NEXT: [[I:%.*]] = alloca i32, align 4
// CHECK-NEXT: store i32 [[E:%.*]], i32* [[E_ADDR]], align 4, !tbaa [[TBAA2]]
// CHECK-NEXT: [[TMP0:%.*]] = bitcast i32* [[I]] to i8*
// CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 4, i8* [[TMP0]]) #[[ATTR4]]
// CHECK-NEXT: store i32 0, i32* [[I]], align 4, !tbaa [[TBAA2]]
// CHECK-NEXT: br label [[FOR_COND:%.*]]
// CHECK: for.cond:
// CHECK-NEXT: [[TMP1:%.*]] = load i32, i32* [[I]], align 4, !tbaa [[TBAA2]]
// CHECK-NEXT: [[TMP2:%.*]] = load i32, i32* [[E_ADDR]], align 4, !tbaa [[TBAA2]]
// CHECK-NEXT: [[CMP:%.*]] = icmp ne i32 [[TMP1]], [[TMP2]]
// CHECK-NEXT: [[CMP_EXPVAL:%.*]] = call i1 @llvm.expect.i1(i1 [[CMP]], i1 false)
// CHECK-NEXT: br i1 [[CMP_EXPVAL]], label [[FOR_BODY:%.*]], label [[FOR_COND_CLEANUP:%.*]]
// CHECK: for.cond.cleanup:
// CHECK-NEXT: [[TMP3:%.*]] = bitcast i32* [[I]] to i8*
// CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 4, i8* [[TMP3]]) #[[ATTR4]]
// CHECK-NEXT: br label [[FOR_END:%.*]]
// CHECK: for.body:
// CHECK-NEXT: br label [[FOR_INC:%.*]]
// CHECK: for.inc:
// CHECK-NEXT: [[TMP4:%.*]] = load i32, i32* [[E_ADDR]], align 4, !tbaa [[TBAA2]]
// CHECK-NEXT: [[INC:%.*]] = add nsw i32 [[TMP4]], 1
// CHECK-NEXT: store i32 [[INC]], i32* [[E_ADDR]], align 4, !tbaa [[TBAA2]]
// CHECK-NEXT: br label [[FOR_COND]], !llvm.loop [[LOOP12:![0-9]+]]
// CHECK: for.end:
// CHECK-NEXT: ret void
//
void fu(int e)
{
// CHECK-LABEL: define{{.*}}fu
// CHECK: br {{.*}} !prof !10
for(int i = 0; i != e; ++e) [[unlikely]];
}
// CHECK-LABEL: @_Z15f_branch_elidedv(
// CHECK-NEXT: entry:
// CHECK-NEXT: br label [[FOR_COND:%.*]]
// CHECK: for.cond:
// CHECK-NEXT: br label [[FOR_COND]], !llvm.loop [[LOOP13:![0-9]+]]
//
void f_branch_elided()
{
// CHECK-LABEL: define{{.*}}f_branch_elided
// CHECK-NOT: br {{.*}} !prof
for(;;) [[likely]];
}
// CHECK-LABEL: @_Z3frlOA4_i(
// CHECK-NEXT: entry:
// CHECK-NEXT: [[E_ADDR:%.*]] = alloca [4 x i32]*, align 8
// CHECK-NEXT: [[__RANGE1:%.*]] = alloca [4 x i32]*, align 8
// CHECK-NEXT: [[__BEGIN1:%.*]] = alloca i32*, align 8
// CHECK-NEXT: [[__END1:%.*]] = alloca i32*, align 8
// CHECK-NEXT: [[I:%.*]] = alloca i32, align 4
// CHECK-NEXT: store [4 x i32]* [[E:%.*]], [4 x i32]** [[E_ADDR]], align 8, !tbaa [[TBAA14:![0-9]+]]
// CHECK-NEXT: [[TMP0:%.*]] = bitcast [4 x i32]** [[__RANGE1]] to i8*
// CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 8, i8* [[TMP0]]) #[[ATTR4]]
// CHECK-NEXT: [[TMP1:%.*]] = load [4 x i32]*, [4 x i32]** [[E_ADDR]], align 8, !tbaa [[TBAA14]]
// CHECK-NEXT: store [4 x i32]* [[TMP1]], [4 x i32]** [[__RANGE1]], align 8, !tbaa [[TBAA14]]
// CHECK-NEXT: [[TMP2:%.*]] = bitcast i32** [[__BEGIN1]] to i8*
// CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 8, i8* [[TMP2]]) #[[ATTR4]]
// CHECK-NEXT: [[TMP3:%.*]] = load [4 x i32]*, [4 x i32]** [[__RANGE1]], align 8, !tbaa [[TBAA14]]
// CHECK-NEXT: [[ARRAYDECAY:%.*]] = getelementptr inbounds [4 x i32], [4 x i32]* [[TMP3]], i64 0, i64 0
// CHECK-NEXT: store i32* [[ARRAYDECAY]], i32** [[__BEGIN1]], align 8, !tbaa [[TBAA14]]
// CHECK-NEXT: [[TMP4:%.*]] = bitcast i32** [[__END1]] to i8*
// CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 8, i8* [[TMP4]]) #[[ATTR4]]
// CHECK-NEXT: [[TMP5:%.*]] = load [4 x i32]*, [4 x i32]** [[__RANGE1]], align 8, !tbaa [[TBAA14]]
// CHECK-NEXT: [[ARRAYDECAY1:%.*]] = getelementptr inbounds [4 x i32], [4 x i32]* [[TMP5]], i64 0, i64 0
// CHECK-NEXT: [[ADD_PTR:%.*]] = getelementptr inbounds i32, i32* [[ARRAYDECAY1]], i64 4
// CHECK-NEXT: store i32* [[ADD_PTR]], i32** [[__END1]], align 8, !tbaa [[TBAA14]]
// CHECK-NEXT: br label [[FOR_COND:%.*]]
// CHECK: for.cond:
// CHECK-NEXT: [[TMP6:%.*]] = load i32*, i32** [[__BEGIN1]], align 8, !tbaa [[TBAA14]]
// CHECK-NEXT: [[TMP7:%.*]] = load i32*, i32** [[__END1]], align 8, !tbaa [[TBAA14]]
// CHECK-NEXT: [[CMP:%.*]] = icmp ne i32* [[TMP6]], [[TMP7]]
// CHECK-NEXT: [[CMP_EXPVAL:%.*]] = call i1 @llvm.expect.i1(i1 [[CMP]], i1 true)
// CHECK-NEXT: br i1 [[CMP_EXPVAL]], label [[FOR_BODY:%.*]], label [[FOR_COND_CLEANUP:%.*]]
// CHECK: for.cond.cleanup:
// CHECK-NEXT: [[TMP8:%.*]] = bitcast i32** [[__END1]] to i8*
// CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 8, i8* [[TMP8]]) #[[ATTR4]]
// CHECK-NEXT: [[TMP9:%.*]] = bitcast i32** [[__BEGIN1]] to i8*
// CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 8, i8* [[TMP9]]) #[[ATTR4]]
// CHECK-NEXT: [[TMP10:%.*]] = bitcast [4 x i32]** [[__RANGE1]] to i8*
// CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 8, i8* [[TMP10]]) #[[ATTR4]]
// CHECK-NEXT: br label [[FOR_END:%.*]]
// CHECK: for.body:
// CHECK-NEXT: [[TMP11:%.*]] = bitcast i32* [[I]] to i8*
// CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 4, i8* [[TMP11]]) #[[ATTR4]]
// CHECK-NEXT: [[TMP12:%.*]] = load i32*, i32** [[__BEGIN1]], align 8, !tbaa [[TBAA14]]
// CHECK-NEXT: [[TMP13:%.*]] = load i32, i32* [[TMP12]], align 4, !tbaa [[TBAA2]]
// CHECK-NEXT: store i32 [[TMP13]], i32* [[I]], align 4, !tbaa [[TBAA2]]
// CHECK-NEXT: [[TMP14:%.*]] = bitcast i32* [[I]] to i8*
// CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 4, i8* [[TMP14]]) #[[ATTR4]]
// CHECK-NEXT: br label [[FOR_INC:%.*]]
// CHECK: for.inc:
// CHECK-NEXT: [[TMP15:%.*]] = load i32*, i32** [[__BEGIN1]], align 8, !tbaa [[TBAA14]]
// CHECK-NEXT: [[INCDEC_PTR:%.*]] = getelementptr inbounds i32, i32* [[TMP15]], i32 1
// CHECK-NEXT: store i32* [[INCDEC_PTR]], i32** [[__BEGIN1]], align 8, !tbaa [[TBAA14]]
// CHECK-NEXT: br label [[FOR_COND]], !llvm.loop [[LOOP16:![0-9]+]]
// CHECK: for.end:
// CHECK-NEXT: ret void
//
void frl(int (&&e) [4])
{
// CHECK-LABEL: define{{.*}}frl
// CHECK: br {{.*}} !prof !6
for(int i : e) [[likely]];
}
// CHECK-LABEL: @_Z3fruOA4_i(
// CHECK-NEXT: entry:
// CHECK-NEXT: [[E_ADDR:%.*]] = alloca [4 x i32]*, align 8
// CHECK-NEXT: [[__RANGE1:%.*]] = alloca [4 x i32]*, align 8
// CHECK-NEXT: [[__BEGIN1:%.*]] = alloca i32*, align 8
// CHECK-NEXT: [[__END1:%.*]] = alloca i32*, align 8
// CHECK-NEXT: [[I:%.*]] = alloca i32, align 4
// CHECK-NEXT: store [4 x i32]* [[E:%.*]], [4 x i32]** [[E_ADDR]], align 8, !tbaa [[TBAA14]]
// CHECK-NEXT: [[TMP0:%.*]] = bitcast [4 x i32]** [[__RANGE1]] to i8*
// CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 8, i8* [[TMP0]]) #[[ATTR4]]
// CHECK-NEXT: [[TMP1:%.*]] = load [4 x i32]*, [4 x i32]** [[E_ADDR]], align 8, !tbaa [[TBAA14]]
// CHECK-NEXT: store [4 x i32]* [[TMP1]], [4 x i32]** [[__RANGE1]], align 8, !tbaa [[TBAA14]]
// CHECK-NEXT: [[TMP2:%.*]] = bitcast i32** [[__BEGIN1]] to i8*
// CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 8, i8* [[TMP2]]) #[[ATTR4]]
// CHECK-NEXT: [[TMP3:%.*]] = load [4 x i32]*, [4 x i32]** [[__RANGE1]], align 8, !tbaa [[TBAA14]]
// CHECK-NEXT: [[ARRAYDECAY:%.*]] = getelementptr inbounds [4 x i32], [4 x i32]* [[TMP3]], i64 0, i64 0
// CHECK-NEXT: store i32* [[ARRAYDECAY]], i32** [[__BEGIN1]], align 8, !tbaa [[TBAA14]]
// CHECK-NEXT: [[TMP4:%.*]] = bitcast i32** [[__END1]] to i8*
// CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 8, i8* [[TMP4]]) #[[ATTR4]]
// CHECK-NEXT: [[TMP5:%.*]] = load [4 x i32]*, [4 x i32]** [[__RANGE1]], align 8, !tbaa [[TBAA14]]
// CHECK-NEXT: [[ARRAYDECAY1:%.*]] = getelementptr inbounds [4 x i32], [4 x i32]* [[TMP5]], i64 0, i64 0
// CHECK-NEXT: [[ADD_PTR:%.*]] = getelementptr inbounds i32, i32* [[ARRAYDECAY1]], i64 4
// CHECK-NEXT: store i32* [[ADD_PTR]], i32** [[__END1]], align 8, !tbaa [[TBAA14]]
// CHECK-NEXT: br label [[FOR_COND:%.*]]
// CHECK: for.cond:
// CHECK-NEXT: [[TMP6:%.*]] = load i32*, i32** [[__BEGIN1]], align 8, !tbaa [[TBAA14]]
// CHECK-NEXT: [[TMP7:%.*]] = load i32*, i32** [[__END1]], align 8, !tbaa [[TBAA14]]
// CHECK-NEXT: [[CMP:%.*]] = icmp ne i32* [[TMP6]], [[TMP7]]
// CHECK-NEXT: [[CMP_EXPVAL:%.*]] = call i1 @llvm.expect.i1(i1 [[CMP]], i1 false)
// CHECK-NEXT: br i1 [[CMP_EXPVAL]], label [[FOR_BODY:%.*]], label [[FOR_COND_CLEANUP:%.*]]
// CHECK: for.cond.cleanup:
// CHECK-NEXT: [[TMP8:%.*]] = bitcast i32** [[__END1]] to i8*
// CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 8, i8* [[TMP8]]) #[[ATTR4]]
// CHECK-NEXT: [[TMP9:%.*]] = bitcast i32** [[__BEGIN1]] to i8*
// CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 8, i8* [[TMP9]]) #[[ATTR4]]
// CHECK-NEXT: [[TMP10:%.*]] = bitcast [4 x i32]** [[__RANGE1]] to i8*
// CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 8, i8* [[TMP10]]) #[[ATTR4]]
// CHECK-NEXT: br label [[FOR_END:%.*]]
// CHECK: for.body:
// CHECK-NEXT: [[TMP11:%.*]] = bitcast i32* [[I]] to i8*
// CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 4, i8* [[TMP11]]) #[[ATTR4]]
// CHECK-NEXT: [[TMP12:%.*]] = load i32*, i32** [[__BEGIN1]], align 8, !tbaa [[TBAA14]]
// CHECK-NEXT: [[TMP13:%.*]] = load i32, i32* [[TMP12]], align 4, !tbaa [[TBAA2]]
// CHECK-NEXT: store i32 [[TMP13]], i32* [[I]], align 4, !tbaa [[TBAA2]]
// CHECK-NEXT: [[TMP14:%.*]] = bitcast i32* [[I]] to i8*
// CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 4, i8* [[TMP14]]) #[[ATTR4]]
// CHECK-NEXT: br label [[FOR_INC:%.*]]
// CHECK: for.inc:
// CHECK-NEXT: [[TMP15:%.*]] = load i32*, i32** [[__BEGIN1]], align 8, !tbaa [[TBAA14]]
// CHECK-NEXT: [[INCDEC_PTR:%.*]] = getelementptr inbounds i32, i32* [[TMP15]], i32 1
// CHECK-NEXT: store i32* [[INCDEC_PTR]], i32** [[__BEGIN1]], align 8, !tbaa [[TBAA14]]
// CHECK-NEXT: br label [[FOR_COND]], !llvm.loop [[LOOP17:![0-9]+]]
// CHECK: for.end:
// CHECK-NEXT: ret void
//
void fru(int (&&e) [4])
{
// CHECK-LABEL: define{{.*}}fru
// CHECK: br {{.*}} !prof !10
for(int i : e) [[unlikely]];
}
// CHECK: !6 = !{!"branch_weights", i32 2000, i32 1}
// CHECK: !10 = !{!"branch_weights", i32 1, i32 2000}

View File

@ -1,59 +1,111 @@
// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py
// RUN: %clang_cc1 -O1 -disable-llvm-passes -emit-llvm %s -o - -triple=x86_64-linux-gnu | FileCheck %s
extern volatile int i;
// CHECK-LABEL: @_Z8OneCaseLv(
// CHECK-NEXT: entry:
// CHECK-NEXT: [[TMP0:%.*]] = load volatile i32, i32* @i, align 4, !tbaa [[TBAA2:![0-9]+]]
// CHECK-NEXT: switch i32 [[TMP0]], label [[SW_EPILOG:%.*]] [
// CHECK-NEXT: i32 1, label [[SW_EPILOG]]
// CHECK-NEXT: ], !prof !6
// CHECK: sw.epilog:
// CHECK-NEXT: ret void
//
void OneCaseL() {
// CHECK-LABEL: define{{.*}}OneCaseL
// CHECK: switch
// CHECK: {{.*}} !prof !6
switch (i) {
[[likely]] case 1: break;
}
}
// CHECK-LABEL: @_Z8OneCaseUv(
// CHECK-NEXT: entry:
// CHECK-NEXT: [[TMP0:%.*]] = load volatile i32, i32* @i, align 4, !tbaa [[TBAA2]]
// CHECK-NEXT: switch i32 [[TMP0]], label [[SW_EPILOG:%.*]] [
// CHECK-NEXT: i32 1, label [[SW_BB:%.*]]
// CHECK-NEXT: ], !prof !7
// CHECK: sw.bb:
// CHECK-NEXT: [[TMP1:%.*]] = load volatile i32, i32* @i, align 4, !tbaa [[TBAA2]]
// CHECK-NEXT: [[INC:%.*]] = add nsw i32 [[TMP1]], 1
// CHECK-NEXT: store volatile i32 [[INC]], i32* @i, align 4, !tbaa [[TBAA2]]
// CHECK-NEXT: br label [[SW_EPILOG]]
// CHECK: sw.epilog:
// CHECK-NEXT: ret void
//
void OneCaseU() {
// CHECK-LABEL: define{{.*}}OneCaseU
// CHECK: switch
// CHECK: {{.*}} !prof !7
switch (i) {
[[unlikely]] case 1: ++i; break;
}
}
// CHECK-LABEL: @_Z10TwoCasesLNv(
// CHECK-NEXT: entry:
// CHECK-NEXT: [[TMP0:%.*]] = load volatile i32, i32* @i, align 4, !tbaa [[TBAA2]]
// CHECK-NEXT: switch i32 [[TMP0]], label [[SW_EPILOG:%.*]] [
// CHECK-NEXT: i32 1, label [[SW_EPILOG]]
// CHECK-NEXT: i32 2, label [[SW_EPILOG]]
// CHECK-NEXT: ], !prof !8
// CHECK: sw.epilog:
// CHECK-NEXT: ret void
//
void TwoCasesLN() {
// CHECK-LABEL: define{{.*}}TwoCasesLN
// CHECK: switch
// CHECK: {{.*}} !prof !8
switch (i) {
[[likely]] case 1: break;
case 2: break;
}
}
// CHECK-LABEL: @_Z10TwoCasesUNv(
// CHECK-NEXT: entry:
// CHECK-NEXT: [[TMP0:%.*]] = load volatile i32, i32* @i, align 4, !tbaa [[TBAA2]]
// CHECK-NEXT: switch i32 [[TMP0]], label [[SW_EPILOG:%.*]] [
// CHECK-NEXT: i32 1, label [[SW_EPILOG]]
// CHECK-NEXT: i32 2, label [[SW_EPILOG]]
// CHECK-NEXT: ], !prof !9
// CHECK: sw.epilog:
// CHECK-NEXT: ret void
//
void TwoCasesUN() {
// CHECK-LABEL: define{{.*}}TwoCasesUN
// CHECK: switch
// CHECK: {{.*}} !prof !9
switch (i) {
[[unlikely]] case 1: break;
case 2: break;
}
}
// CHECK-LABEL: @_Z10TwoCasesLUv(
// CHECK-NEXT: entry:
// CHECK-NEXT: [[TMP0:%.*]] = load volatile i32, i32* @i, align 4, !tbaa [[TBAA2]]
// CHECK-NEXT: switch i32 [[TMP0]], label [[SW_EPILOG:%.*]] [
// CHECK-NEXT: i32 1, label [[SW_EPILOG]]
// CHECK-NEXT: i32 2, label [[SW_EPILOG]]
// CHECK-NEXT: ], !prof !10
// CHECK: sw.epilog:
// CHECK-NEXT: ret void
//
void TwoCasesLU() {
// CHECK-LABEL: define{{.*}}TwoCasesLU
// CHECK: switch
// CHECK: {{.*}} !prof !10
switch (i) {
[[likely]] case 1: break;
[[unlikely]] case 2: break;
}
}
// CHECK-LABEL: @_Z20CasesFallthroughNNLNv(
// CHECK-NEXT: entry:
// CHECK-NEXT: [[TMP0:%.*]] = load volatile i32, i32* @i, align 4, !tbaa [[TBAA2]]
// CHECK-NEXT: switch i32 [[TMP0]], label [[SW_EPILOG:%.*]] [
// CHECK-NEXT: i32 1, label [[SW_BB:%.*]]
// CHECK-NEXT: i32 2, label [[SW_BB]]
// CHECK-NEXT: i32 3, label [[SW_BB1:%.*]]
// CHECK-NEXT: i32 4, label [[SW_BB1]]
// CHECK-NEXT: ], !prof !11
// CHECK: sw.bb:
// CHECK-NEXT: br label [[SW_BB1]]
// CHECK: sw.bb1:
// CHECK-NEXT: br label [[SW_EPILOG]]
// CHECK: sw.epilog:
// CHECK-NEXT: ret void
//
void CasesFallthroughNNLN() {
// CHECK-LABEL: define{{.*}}CasesFallthroughNNLN
// CHECK: switch
// CHECK: {{.*}} !prof !11
switch (i) {
case 1:
case 2:
@ -62,10 +114,23 @@ void CasesFallthroughNNLN() {
}
}
// CHECK-LABEL: @_Z20CasesFallthroughNNUNv(
// CHECK-NEXT: entry:
// CHECK-NEXT: [[TMP0:%.*]] = load volatile i32, i32* @i, align 4, !tbaa [[TBAA2]]
// CHECK-NEXT: switch i32 [[TMP0]], label [[SW_EPILOG:%.*]] [
// CHECK-NEXT: i32 1, label [[SW_BB:%.*]]
// CHECK-NEXT: i32 2, label [[SW_BB]]
// CHECK-NEXT: i32 3, label [[SW_BB1:%.*]]
// CHECK-NEXT: i32 4, label [[SW_BB1]]
// CHECK-NEXT: ], !prof !12
// CHECK: sw.bb:
// CHECK-NEXT: br label [[SW_BB1]]
// CHECK: sw.bb1:
// CHECK-NEXT: br label [[SW_EPILOG]]
// CHECK: sw.epilog:
// CHECK-NEXT: ret void
//
void CasesFallthroughNNUN() {
// CHECK-LABEL: define{{.*}}CasesFallthroughNNUN
// CHECK: switch
// CHECK: {{.*}} !prof !12
switch (i) {
case 1:
case 2:
@ -74,10 +139,32 @@ void CasesFallthroughNNUN() {
}
}
// CHECK-LABEL: @_Z28CasesFallthroughRangeSmallLNv(
// CHECK-NEXT: entry:
// CHECK-NEXT: [[TMP0:%.*]] = load volatile i32, i32* @i, align 4, !tbaa [[TBAA2]]
// CHECK-NEXT: switch i32 [[TMP0]], label [[SW_EPILOG:%.*]] [
// CHECK-NEXT: i32 1, label [[SW_BB:%.*]]
// CHECK-NEXT: i32 2, label [[SW_BB]]
// CHECK-NEXT: i32 3, label [[SW_BB]]
// CHECK-NEXT: i32 4, label [[SW_BB]]
// CHECK-NEXT: i32 5, label [[SW_BB]]
// CHECK-NEXT: i32 102, label [[SW_BB1:%.*]]
// CHECK-NEXT: i32 103, label [[SW_BB2:%.*]]
// CHECK-NEXT: i32 104, label [[SW_BB2]]
// CHECK-NEXT: ], !prof !13
// CHECK: sw.bb:
// CHECK-NEXT: [[TMP1:%.*]] = load volatile i32, i32* @i, align 4, !tbaa [[TBAA2]]
// CHECK-NEXT: [[INC:%.*]] = add nsw i32 [[TMP1]], 1
// CHECK-NEXT: store volatile i32 [[INC]], i32* @i, align 4, !tbaa [[TBAA2]]
// CHECK-NEXT: br label [[SW_BB1]]
// CHECK: sw.bb1:
// CHECK-NEXT: br label [[SW_BB2]]
// CHECK: sw.bb2:
// CHECK-NEXT: br label [[SW_EPILOG]]
// CHECK: sw.epilog:
// CHECK-NEXT: ret void
//
void CasesFallthroughRangeSmallLN() {
// CHECK-LABEL: define{{.*}}CasesFallthroughRangeSmallLN
// CHECK: switch
// CHECK: {{.*}} !prof !13
switch (i) {
case 1 ... 5: ++i;
case 102:
@ -86,10 +173,32 @@ void CasesFallthroughRangeSmallLN() {
}
}
// CHECK-LABEL: @_Z28CasesFallthroughRangeSmallUNv(
// CHECK-NEXT: entry:
// CHECK-NEXT: [[TMP0:%.*]] = load volatile i32, i32* @i, align 4, !tbaa [[TBAA2]]
// CHECK-NEXT: switch i32 [[TMP0]], label [[SW_EPILOG:%.*]] [
// CHECK-NEXT: i32 1, label [[SW_BB:%.*]]
// CHECK-NEXT: i32 2, label [[SW_BB]]
// CHECK-NEXT: i32 3, label [[SW_BB]]
// CHECK-NEXT: i32 4, label [[SW_BB]]
// CHECK-NEXT: i32 5, label [[SW_BB]]
// CHECK-NEXT: i32 102, label [[SW_BB1:%.*]]
// CHECK-NEXT: i32 103, label [[SW_BB2:%.*]]
// CHECK-NEXT: i32 104, label [[SW_BB2]]
// CHECK-NEXT: ], !prof !14
// CHECK: sw.bb:
// CHECK-NEXT: [[TMP1:%.*]] = load volatile i32, i32* @i, align 4, !tbaa [[TBAA2]]
// CHECK-NEXT: [[INC:%.*]] = add nsw i32 [[TMP1]], 1
// CHECK-NEXT: store volatile i32 [[INC]], i32* @i, align 4, !tbaa [[TBAA2]]
// CHECK-NEXT: br label [[SW_BB1]]
// CHECK: sw.bb1:
// CHECK-NEXT: br label [[SW_BB2]]
// CHECK: sw.bb2:
// CHECK-NEXT: br label [[SW_EPILOG]]
// CHECK: sw.epilog:
// CHECK-NEXT: ret void
//
void CasesFallthroughRangeSmallUN() {
// CHECK-LABEL: define{{.*}}CasesFallthroughRangeSmallUN
// CHECK: switch
// CHECK: {{.*}} !prof !14
switch (i) {
case 1 ... 5: ++i;
case 102:
@ -98,12 +207,26 @@ void CasesFallthroughRangeSmallUN() {
}
}
// CHECK-LABEL: @_Z29CasesFallthroughRangeLargeLLNv(
// CHECK-NEXT: entry:
// CHECK-NEXT: [[TMP0:%.*]] = load volatile i32, i32* @i, align 4, !tbaa [[TBAA2]]
// CHECK-NEXT: switch i32 [[TMP0]], label [[SW_CASERANGE:%.*]] [
// CHECK-NEXT: i32 1003, label [[SW_BB1:%.*]]
// CHECK-NEXT: i32 104, label [[SW_BB1]]
// CHECK-NEXT: ], !prof !8
// CHECK: sw.bb:
// CHECK-NEXT: br label [[SW_BB1]]
// CHECK: sw.bb1:
// CHECK-NEXT: br label [[SW_EPILOG:%.*]]
// CHECK: sw.caserange:
// CHECK-NEXT: [[TMP1:%.*]] = sub i32 [[TMP0]], 0
// CHECK-NEXT: [[INBOUNDS:%.*]] = icmp ule i32 [[TMP1]], 64
// CHECK-NEXT: [[INBOUNDS_EXPVAL:%.*]] = call i1 @llvm.expect.i1(i1 [[INBOUNDS]], i1 true)
// CHECK-NEXT: br i1 [[INBOUNDS_EXPVAL]], label [[SW_BB:%.*]], label [[SW_EPILOG]]
// CHECK: sw.epilog:
// CHECK-NEXT: ret void
//
void CasesFallthroughRangeLargeLLN() {
// CHECK-LABEL: define{{.*}}CasesFallthroughRangeLargeLLN
// CHECK: switch
// CHECK: {{.*}} !prof !8
// CHECK: caserange
// CHECK: br{{.*}} !prof !15
switch (i) {
[[likely]] case 0 ... 64:
[[likely]] case 1003:
@ -111,12 +234,26 @@ void CasesFallthroughRangeLargeLLN() {
}
}
// CHECK-LABEL: @_Z29CasesFallthroughRangeLargeUUNv(
// CHECK-NEXT: entry:
// CHECK-NEXT: [[TMP0:%.*]] = load volatile i32, i32* @i, align 4, !tbaa [[TBAA2]]
// CHECK-NEXT: switch i32 [[TMP0]], label [[SW_CASERANGE:%.*]] [
// CHECK-NEXT: i32 1003, label [[SW_BB1:%.*]]
// CHECK-NEXT: i32 104, label [[SW_BB1]]
// CHECK-NEXT: ], !prof !9
// CHECK: sw.bb:
// CHECK-NEXT: br label [[SW_BB1]]
// CHECK: sw.bb1:
// CHECK-NEXT: br label [[SW_EPILOG:%.*]]
// CHECK: sw.caserange:
// CHECK-NEXT: [[TMP1:%.*]] = sub i32 [[TMP0]], 0
// CHECK-NEXT: [[INBOUNDS:%.*]] = icmp ule i32 [[TMP1]], 64
// CHECK-NEXT: [[INBOUNDS_EXPVAL:%.*]] = call i1 @llvm.expect.i1(i1 [[INBOUNDS]], i1 false)
// CHECK-NEXT: br i1 [[INBOUNDS_EXPVAL]], label [[SW_BB:%.*]], label [[SW_EPILOG]]
// CHECK: sw.epilog:
// CHECK-NEXT: ret void
//
void CasesFallthroughRangeLargeUUN() {
// CHECK-LABEL: define{{.*}}CasesFallthroughRangeLargeUUN
// CHECK: switch
// CHECK: {{.*}} !prof !9
// CHECK: caserange
// CHECK: br{{.*}} !prof !16
switch (i) {
[[unlikely]] case 0 ... 64:
[[unlikely]] case 1003:
@ -124,30 +261,55 @@ void CasesFallthroughRangeLargeUUN() {
}
}
// CHECK-LABEL: @_Z15OneCaseDefaultLv(
// CHECK-NEXT: entry:
// CHECK-NEXT: [[TMP0:%.*]] = load volatile i32, i32* @i, align 4, !tbaa [[TBAA2]]
// CHECK-NEXT: switch i32 [[TMP0]], label [[SW_DEFAULT:%.*]] [
// CHECK-NEXT: i32 1, label [[SW_EPILOG:%.*]]
// CHECK-NEXT: ], !prof !15
// CHECK: sw.default:
// CHECK-NEXT: br label [[SW_EPILOG]]
// CHECK: sw.epilog:
// CHECK-NEXT: ret void
//
void OneCaseDefaultL() {
// CHECK-LABEL: define{{.*}}OneCaseDefaultL
// CHECK: switch
// CHECK: {{.*}} !prof !17
switch (i) {
case 1: break;
[[likely]] default: break;
}
}
// CHECK-LABEL: @_Z15OneCaseDefaultUv(
// CHECK-NEXT: entry:
// CHECK-NEXT: [[TMP0:%.*]] = load volatile i32, i32* @i, align 4, !tbaa [[TBAA2]]
// CHECK-NEXT: switch i32 [[TMP0]], label [[SW_DEFAULT:%.*]] [
// CHECK-NEXT: i32 1, label [[SW_EPILOG:%.*]]
// CHECK-NEXT: ], !prof !16
// CHECK: sw.default:
// CHECK-NEXT: br label [[SW_EPILOG]]
// CHECK: sw.epilog:
// CHECK-NEXT: ret void
//
void OneCaseDefaultU() {
// CHECK-LABEL: define{{.*}}OneCaseDefaultU
// CHECK: switch
// CHECK: {{.*}} !prof !18
switch (i) {
case 1: break;
[[unlikely]] default: break;
}
}
// CHECK-LABEL: @_Z18TwoCasesDefaultLNLv(
// CHECK-NEXT: entry:
// CHECK-NEXT: [[TMP0:%.*]] = load volatile i32, i32* @i, align 4, !tbaa [[TBAA2]]
// CHECK-NEXT: switch i32 [[TMP0]], label [[SW_DEFAULT:%.*]] [
// CHECK-NEXT: i32 1, label [[SW_EPILOG:%.*]]
// CHECK-NEXT: i32 2, label [[SW_EPILOG]]
// CHECK-NEXT: ], !prof !17
// CHECK: sw.default:
// CHECK-NEXT: br label [[SW_EPILOG]]
// CHECK: sw.epilog:
// CHECK-NEXT: ret void
//
void TwoCasesDefaultLNL() {
// CHECK-LABEL: define{{.*}}TwoCasesDefaultLNL
// CHECK: switch
// CHECK: {{.*}} !prof !19
switch (i) {
[[likely]] case 1: break;
case 2: break;
@ -155,10 +317,19 @@ void TwoCasesDefaultLNL() {
}
}
// CHECK-LABEL: @_Z18TwoCasesDefaultLNNv(
// CHECK-NEXT: entry:
// CHECK-NEXT: [[TMP0:%.*]] = load volatile i32, i32* @i, align 4, !tbaa [[TBAA2]]
// CHECK-NEXT: switch i32 [[TMP0]], label [[SW_DEFAULT:%.*]] [
// CHECK-NEXT: i32 1, label [[SW_EPILOG:%.*]]
// CHECK-NEXT: i32 2, label [[SW_EPILOG]]
// CHECK-NEXT: ], !prof !8
// CHECK: sw.default:
// CHECK-NEXT: br label [[SW_EPILOG]]
// CHECK: sw.epilog:
// CHECK-NEXT: ret void
//
void TwoCasesDefaultLNN() {
// CHECK-LABEL: define{{.*}}TwoCasesDefaultLNN
// CHECK: switch
// CHECK: {{.*}} !prof !8
switch (i) {
[[likely]] case 1: break;
case 2: break;
@ -166,29 +337,22 @@ void TwoCasesDefaultLNN() {
}
}
// CHECK-LABEL: @_Z18TwoCasesDefaultLNUv(
// CHECK-NEXT: entry:
// CHECK-NEXT: [[TMP0:%.*]] = load volatile i32, i32* @i, align 4, !tbaa [[TBAA2]]
// CHECK-NEXT: switch i32 [[TMP0]], label [[SW_DEFAULT:%.*]] [
// CHECK-NEXT: i32 1, label [[SW_EPILOG:%.*]]
// CHECK-NEXT: i32 2, label [[SW_EPILOG]]
// CHECK-NEXT: ], !prof !18
// CHECK: sw.default:
// CHECK-NEXT: br label [[SW_EPILOG]]
// CHECK: sw.epilog:
// CHECK-NEXT: ret void
//
void TwoCasesDefaultLNU() {
// CHECK-LABEL: define{{.*}}TwoCasesDefaultLNU
// CHECK: switch
// CHECK: {{.*}} !prof !20
switch (i) {
[[likely]] case 1: break;
case 2: break;
[[unlikely]] default: break;
}
}
// CHECK: !6 = !{!"branch_weights", i32 357913942, i32 715827883}
// CHECK: !7 = !{!"branch_weights", i32 536870912, i32 1}
// CHECK: !8 = !{!"branch_weights", i32 238609295, i32 715827883, i32 238609295}
// CHECK: !9 = !{!"branch_weights", i32 357913942, i32 1, i32 357913942}
// CHECK: !10 = !{!"branch_weights", i32 357913942, i32 715827883, i32 1}
// CHECK: !11 = !{!"branch_weights", i32 143165577, i32 143165577, i32 143165577, i32 715827883, i32 143165577}
// CHECK: !12 = !{!"branch_weights", i32 214748365, i32 214748365, i32 214748365, i32 1, i32 214748365}
// CHECK: !13 = !{!"branch_weights", i32 79536432, i32 79536432, i32 79536432, i32 79536432, i32 79536432, i32 79536432, i32 79536432, i32 715827883, i32 79536432}
// CHECK: !14 = !{!"branch_weights", i32 119304648, i32 119304648, i32 119304648, i32 119304648, i32 119304648, i32 119304648, i32 119304648, i32 1, i32 119304648}
// CHECK: !15 = !{!"branch_weights", i32 2000, i32 1}
// CHECK: !16 = !{!"branch_weights", i32 1, i32 2000}
// CHECK: !17 = !{!"branch_weights", i32 715827883, i32 357913942}
// CHECK: !18 = !{!"branch_weights", i32 1, i32 536870912}
// CHECK: !19 = !{!"branch_weights", i32 536870912, i32 536870912, i32 268435456}
// CHECK: !20 = !{!"branch_weights", i32 1, i32 715827883, i32 357913942}

View File

@ -17,7 +17,6 @@
#include "llvm/IR/Function.h"
#include "llvm/IR/PassManager.h"
#include "llvm/Support/CommandLine.h"
namespace llvm {
@ -32,8 +31,6 @@ struct LowerExpectIntrinsicPass : PassInfoMixin<LowerExpectIntrinsicPass> {
PreservedAnalyses run(Function &F, FunctionAnalysisManager &);
};
extern cl::opt<uint32_t> LikelyBranchWeight;
extern cl::opt<uint32_t> UnlikelyBranchWeight;
}
#endif

View File

@ -24,6 +24,7 @@
#include "llvm/IR/Metadata.h"
#include "llvm/InitializePasses.h"
#include "llvm/Pass.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Transforms/Scalar.h"
@ -41,15 +42,15 @@ STATISTIC(ExpectIntrinsicsHandled,
// only be used in extreme cases, we could make this ratio higher. As it stands,
// programmers may be using __builtin_expect() / llvm.expect to annotate that a
// branch is likely or unlikely to be taken.
//
// There is a known dependency on this ratio in CodeGenPrepare when transforming
// 'select' instructions. It may be worthwhile to hoist these values to some
// shared space, so they can be used directly by other passes.
cl::opt<uint32_t> llvm::LikelyBranchWeight(
// WARNING: these values are internal implementation detail of the pass.
// They should not be exposed to the outside of the pass, front-end codegen
// should emit @llvm.expect intrinsics instead of using these weights directly.
// Transforms should use TargetLowering getPredictableBranchThreshold() hook.
static cl::opt<uint32_t> LikelyBranchWeight(
"likely-branch-weight", cl::Hidden, cl::init(2000),
cl::desc("Weight of the branch likely to be taken (default = 2000)"));
cl::opt<uint32_t> llvm::UnlikelyBranchWeight(
static cl::opt<uint32_t> UnlikelyBranchWeight(
"unlikely-branch-weight", cl::Hidden, cl::init(1),
cl::desc("Weight of the branch unlikely to be taken (default = 1)"));