/// EvaluateExprAsBool - Perform the usual unary conversions on the specified
/// expression and compare the result against zero, returning an Int1Ty value.
llvm::Value *CodeGenFunction::EvaluateExprAsBool(const Expr *E) {
+ PGO.setCurrentStmt(E);
if (const MemberPointerType *MPT = E->getType()->getAs<MemberPointerType>()) {
llvm::Value *MemPtr = EmitScalarExpr(E);
return CGM.getCXXABI().EmitMemberPointerIsNotNull(*this, MemPtr, MPT);
eval.begin(*this);
LValue lhs = EmitLValue(expr->getTrueExpr());
eval.end(*this);
- Cnt.adjustForControlFlow();
if (!lhs.isSimple())
return EmitUnsupportedLValue(expr, "conditional operator");
// Any temporaries created here are conditional.
EmitBlock(rhsBlock);
- Cnt.beginElseRegion();
eval.begin(*this);
LValue rhs = EmitLValue(expr->getFalseExpr());
eval.end(*this);
- Cnt.adjustForControlFlow();
if (!rhs.isSimple())
return EmitUnsupportedLValue(expr, "conditional operator");
rhsBlock = Builder.GetInsertBlock();
EmitBlock(contBlock);
- Cnt.applyAdjustmentsToRegion();
llvm::PHINode *phi = Builder.CreatePHI(lhs.getAddress()->getType(), 2,
"cond-lvalue");
CGF.EmitBlock(LHSBlock);
Cnt.beginRegion(Builder);
Visit(E->getTrueExpr());
- Cnt.adjustForControlFlow();
eval.end(CGF);
assert(CGF.HaveInsertPoint() && "expression evaluation ended with no IP!");
eval.begin(CGF);
CGF.EmitBlock(RHSBlock);
- Cnt.beginElseRegion();
Visit(E->getFalseExpr());
- Cnt.adjustForControlFlow();
eval.end(CGF);
CGF.EmitBlock(ContBlock);
- Cnt.applyAdjustmentsToRegion();
}
void AggExprEmitter::VisitChooseExpr(const ChooseExpr *CE) {
CGF.EmitBlock(LHSBlock);
Cnt.beginRegion(Builder);
ComplexPairTy LHS = Visit(E->getTrueExpr());
- Cnt.adjustForControlFlow();
LHSBlock = Builder.GetInsertBlock();
CGF.EmitBranch(ContBlock);
eval.end(CGF);
eval.begin(CGF);
CGF.EmitBlock(RHSBlock);
- Cnt.beginElseRegion();
ComplexPairTy RHS = Visit(E->getFalseExpr());
- Cnt.adjustForControlFlow();
RHSBlock = Builder.GetInsertBlock();
CGF.EmitBlock(ContBlock);
eval.end(CGF);
- Cnt.applyAdjustmentsToRegion();
// Create a PHI node for the real part.
llvm::PHINode *RealPN = Builder.CreatePHI(LHS.first->getType(), 2, "cond.r");
CGF.EmitBlock(RHSBlock);
Cnt.beginRegion(Builder);
Value *RHSCond = CGF.EvaluateExprAsBool(E->getRHS());
- Cnt.adjustForControlFlow();
eval.end(CGF);
// Reaquire the RHS block, as there may be subblocks inserted.
Builder.SetCurrentDebugLocation(llvm::DebugLoc());
CGF.EmitBlock(ContBlock);
PN->addIncoming(RHSCond, RHSBlock);
- Cnt.applyAdjustmentsToRegion();
// ZExt result to int.
return Builder.CreateZExtOrBitCast(PN, ResTy, "land.ext");
CGF.EmitBlock(RHSBlock);
Cnt.beginRegion(Builder);
Value *RHSCond = CGF.EvaluateExprAsBool(E->getRHS());
- Cnt.adjustForControlFlow();
eval.end(CGF);
// into the phi node for the edge with the value of RHSCond.
CGF.EmitBlock(ContBlock);
PN->addIncoming(RHSCond, RHSBlock);
- Cnt.applyAdjustmentsToRegion();
// ZExt result to int.
return Builder.CreateZExtOrBitCast(PN, ResTy, "lor.ext");
eval.begin(CGF);
Value *LHS = Visit(lhsExpr);
eval.end(CGF);
- Cnt.adjustForControlFlow();
LHSBlock = Builder.GetInsertBlock();
Builder.CreateBr(ContBlock);
CGF.EmitBlock(RHSBlock);
- Cnt.beginElseRegion();
eval.begin(CGF);
Value *RHS = Visit(rhsExpr);
eval.end(CGF);
- Cnt.adjustForControlFlow();
RHSBlock = Builder.GetInsertBlock();
CGF.EmitBlock(ContBlock);
- Cnt.applyAdjustmentsToRegion();
// If the LHS or RHS is a throw expression, it will be legitimately null.
if (!LHS)
EmitAutoVarCleanups(variable);
// Perform the loop body, setting up break and continue labels.
- BreakContinueStack.push_back(BreakContinue(LoopEnd, AfterBody, &Cnt));
+ BreakContinueStack.push_back(BreakContinue(LoopEnd, AfterBody));
{
RunCleanupsScope Scope(*this);
EmitStmt(S.getBody());
void CodeGenFunction::EmitStmt(const Stmt *S) {
assert(S && "Null statement?");
+ PGO.setCurrentStmt(S);
// These statements have their own debug info handling.
if (EmitSimpleStmt(S))
EmitStopPoint(&S);
EmitBranchThroughCleanup(getJumpDestForLabel(S.getLabel()));
- PGO.setCurrentRegionUnreachable();
}
void CodeGenFunction::EmitIndirectGotoStmt(const IndirectGotoStmt &S) {
if (const LabelDecl *Target = S.getConstantTarget()) {
EmitBranchThroughCleanup(getJumpDestForLabel(Target));
- PGO.setCurrentRegionUnreachable();
return;
}
cast<llvm::PHINode>(IndGotoBB->begin())->addIncoming(V, CurBB);
EmitBranch(IndGotoBB);
- PGO.setCurrentRegionUnreachable();
}
void CodeGenFunction::EmitIfStmt(const IfStmt &S) {
RunCleanupsScope ThenScope(*this);
EmitStmt(S.getThen());
}
- Cnt.adjustForControlFlow();
EmitBranch(ContBlock);
// Emit the 'else' code if present.
if (getDebugInfo())
Builder.SetCurrentDebugLocation(llvm::DebugLoc());
EmitBlock(ElseBlock);
- Cnt.beginElseRegion();
{
RunCleanupsScope ElseScope(*this);
EmitStmt(Else);
}
- Cnt.adjustForControlFlow();
// There is no need to emit line number for unconditional branch.
if (getDebugInfo())
Builder.SetCurrentDebugLocation(llvm::DebugLoc());
// Emit the continuation block for code after the if.
EmitBlock(ContBlock, true);
- Cnt.applyAdjustmentsToRegion();
}
void CodeGenFunction::EmitWhileStmt(const WhileStmt &S) {
JumpDest LoopExit = getJumpDestInCurrentScope("while.end");
// Store the blocks to use for break and continue.
- BreakContinueStack.push_back(BreakContinue(LoopExit, LoopHeader, &Cnt));
+ BreakContinueStack.push_back(BreakContinue(LoopExit, LoopHeader));
// C++ [stmt.while]p2:
// When the condition of a while statement is a declaration, the
// while(1) is common, avoid extra exit blocks. Be sure
// to correctly handle break/continue though.
bool EmitBoolCondBranch = true;
- llvm::BranchInst *CondBr = NULL;
if (llvm::ConstantInt *C = dyn_cast<llvm::ConstantInt>(BoolCondVal))
if (C->isOne())
EmitBoolCondBranch = false;
llvm::BasicBlock *ExitBlock = LoopExit.getBlock();
if (ConditionScope.requiresCleanups())
ExitBlock = createBasicBlock("while.exit");
-
- CondBr = Builder.CreateCondBr(BoolCondVal, LoopBody, ExitBlock);
+ Builder.CreateCondBr(BoolCondVal, LoopBody, ExitBlock,
+ PGO.createLoopWeights(S.getCond(), Cnt));
if (ExitBlock != LoopExit.getBlock()) {
EmitBlock(ExitBlock);
Cnt.beginRegion(Builder);
EmitStmt(S.getBody());
}
- Cnt.adjustForControlFlow();
BreakContinueStack.pop_back();
- uint64_t LoopCount = Cnt.getCount();
- uint64_t ExitCount = Cnt.getLoopExitCount();
- if (EmitBoolCondBranch)
- CondBr->setMetadata(llvm::LLVMContext::MD_prof,
- PGO.createBranchWeights(LoopCount, ExitCount));
-
// Immediately force cleanup.
ConditionScope.ForceCleanup();
// Emit the exit block.
EmitBlock(LoopExit.getBlock(), true);
- PGO.setCurrentRegionCount(ExitCount + Cnt.getBreakCounter().getCount());
// The LoopHeader typically is just a branch if we skipped emitting
// a branch, try to erase it.
RegionCounter Cnt = getPGORegionCounter(&S);
// Store the blocks to use for break and continue.
- BreakContinueStack.push_back(BreakContinue(LoopExit, LoopCond, &Cnt));
+ BreakContinueStack.push_back(BreakContinue(LoopExit, LoopCond));
// Emit the body of the loop.
llvm::BasicBlock *LoopBody = createBasicBlock("do.body");
- EmitBlock(LoopBody);
- Cnt.beginRegion(Builder);
+ EmitBlockWithFallThrough(LoopBody, Cnt);
{
RunCleanupsScope BodyScope(*this);
EmitStmt(S.getBody());
}
- Cnt.adjustForControlFlow();
EmitBlock(LoopCond.getBlock());
if (C->isZero())
EmitBoolCondBranch = false;
- uint64_t LoopCount = Cnt.getCount() - Cnt.getParentCount();
- uint64_t ExitCount = Cnt.getLoopExitCount();
-
// As long as the condition is true, iterate the loop.
if (EmitBoolCondBranch)
Builder.CreateCondBr(BoolCondVal, LoopBody, LoopExit.getBlock(),
- PGO.createBranchWeights(LoopCount, ExitCount));
+ PGO.createLoopWeights(S.getCond(), Cnt));
// Emit the exit block.
EmitBlock(LoopExit.getBlock());
- PGO.setCurrentRegionCount(ExitCount + Cnt.getBreakCounter().getCount());
// The DoCond block typically is just a branch if we skipped
// emitting a branch, try to erase it.
}
void CodeGenFunction::EmitForStmt(const ForStmt &S) {
- RegionCounter Cnt = getPGORegionCounter(&S);
-
JumpDest LoopExit = getJumpDestInCurrentScope("for.end");
RunCleanupsScope ForScope(*this);
if (S.getInit())
EmitStmt(S.getInit());
+ RegionCounter Cnt = getPGORegionCounter(&S);
+
// Start the loop with a block that tests the condition.
// If there's an increment, the continue scope will be overwritten
// later.
Continue = getJumpDestInCurrentScope("for.inc");
// Store the blocks to use for break and continue.
- BreakContinueStack.push_back(BreakContinue(LoopExit, Continue, &Cnt));
+ BreakContinueStack.push_back(BreakContinue(LoopExit, Continue));
// Create a cleanup scope for the condition variable cleanups.
RunCleanupsScope ConditionScope(*this);
- llvm::BranchInst *CondBr = NULL;
if (S.getCond()) {
// If the for statement has a condition scope, emit the local variable
// declaration.
// 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());
- CondBr = Builder.CreateCondBr(BoolCondVal, ForBody, ExitBlock);
+ Builder.CreateCondBr(BoolCondVal, ForBody, ExitBlock,
+ PGO.createLoopWeights(S.getCond(), Cnt));
if (ExitBlock != LoopExit.getBlock()) {
EmitBlock(ExitBlock);
EmitBlock(Continue.getBlock());
EmitStmt(S.getInc());
}
- Cnt.adjustForControlFlow();
BreakContinueStack.pop_back();
- uint64_t LoopCount = Cnt.getCount();
- uint64_t ExitCount = Cnt.getLoopExitCount();
- if (S.getCond())
- CondBr->setMetadata(llvm::LLVMContext::MD_prof,
- PGO.createBranchWeights(LoopCount, ExitCount));
-
ConditionScope.ForceCleanup();
EmitBranch(CondBlock);
// Emit the fall-through block.
EmitBlock(LoopExit.getBlock(), true);
- PGO.setCurrentRegionCount(ExitCount + Cnt.getBreakCounter().getCount());
}
void CodeGenFunction::EmitCXXForRangeStmt(const CXXForRangeStmt &S) {
- RegionCounter Cnt = getPGORegionCounter(&S);
-
JumpDest LoopExit = getJumpDestInCurrentScope("for.end");
RunCleanupsScope ForScope(*this);
EmitStmt(S.getRangeStmt());
EmitStmt(S.getBeginEndStmt());
+ RegionCounter Cnt = getPGORegionCounter(&S);
+
// Start the loop with a block that tests the condition.
// If there's an increment, the continue scope will be overwritten
// later.
// The body is executed if the expression, contextually converted
// to bool, is true.
llvm::Value *BoolCondVal = EvaluateExprAsBool(S.getCond());
- llvm::BranchInst *CondBr = Builder.CreateCondBr(BoolCondVal,
- ForBody, ExitBlock);
+ Builder.CreateCondBr(BoolCondVal, ForBody, ExitBlock,
+ PGO.createLoopWeights(S.getCond(), Cnt));
if (ExitBlock != LoopExit.getBlock()) {
EmitBlock(ExitBlock);
JumpDest Continue = getJumpDestInCurrentScope("for.inc");
// Store the blocks to use for break and continue.
- BreakContinueStack.push_back(BreakContinue(LoopExit, Continue, &Cnt));
+ BreakContinueStack.push_back(BreakContinue(LoopExit, Continue));
{
// Create a separate cleanup scope for the loop variable and body.
// If there is an increment, emit it next.
EmitBlock(Continue.getBlock());
EmitStmt(S.getInc());
- Cnt.adjustForControlFlow();
BreakContinueStack.pop_back();
- uint64_t LoopCount = Cnt.getCount();
- uint64_t ExitCount = Cnt.getLoopExitCount();
- CondBr->setMetadata(llvm::LLVMContext::MD_prof,
- PGO.createBranchWeights(LoopCount, ExitCount));
-
EmitBranch(CondBlock);
ForScope.ForceCleanup();
// Emit the fall-through block.
EmitBlock(LoopExit.getBlock(), true);
- PGO.setCurrentRegionCount(ExitCount + Cnt.getBreakCounter().getCount());
}
void CodeGenFunction::EmitReturnOfRValue(RValue RV, QualType Ty) {
/*init*/ true);
}
EmitBranchThroughCleanup(ReturnBlock);
- PGO.setCurrentRegionUnreachable();
}
/// EmitReturnStmt - Note that due to GCC extensions, this can have an operand
cleanupScope.ForceCleanup();
EmitBranchThroughCleanup(ReturnBlock);
- PGO.setCurrentRegionUnreachable();
}
void CodeGenFunction::EmitDeclStmt(const DeclStmt &S) {
if (HaveInsertPoint())
EmitStopPoint(&S);
- BreakContinue &BC = BreakContinueStack.back();
- // We keep track of breaks from the loop so we can differentiate them from
- // non-local exits in PGO instrumentation. This only applies to loops, not
- // breaks from switch statements.
- if (BC.CountBreak)
- BC.LoopCnt->getBreakCounter().beginRegion(Builder);
- EmitBranchThroughCleanup(BC.BreakBlock);
- PGO.setCurrentRegionUnreachable();
+ EmitBranchThroughCleanup(BreakContinueStack.back().BreakBlock);
}
void CodeGenFunction::EmitContinueStmt(const ContinueStmt &S) {
if (HaveInsertPoint())
EmitStopPoint(&S);
- BreakContinue &BC = BreakContinueStack.back();
- // We keep track of continues in the loop so we can differentiate them from
- // non-local exits in PGO instrumentation.
- BC.LoopCnt->getContinueCounter().beginRegion(Builder);
- EmitBranchThroughCleanup(BC.ContinueBlock);
- PGO.setCurrentRegionUnreachable();
+ EmitBranchThroughCleanup(BreakContinueStack.back().ContinueBlock);
}
/// EmitCaseStmtRange - If case statement range is not too big then
// Emit the code for this case. We do this first to make sure it is
// properly chained from our predecessor before generating the
// switch machinery to enter this block.
- EmitBlock(createBasicBlock("sw.bb"));
- llvm::BasicBlock *CaseDest = Builder.GetInsertBlock();
- CaseCnt.beginRegion(Builder);
+ llvm::BasicBlock *CaseDest = createBasicBlock("sw.bb");
+ EmitBlockWithFallThrough(CaseDest, CaseCnt);
EmitStmt(S.getSubStmt());
// If range is empty, do nothing.
// FIXME: parameters such as this should not be hardcoded.
if (Range.ult(llvm::APInt(Range.getBitWidth(), 64))) {
// Range is small enough to add multiple switch instruction cases.
- uint64_t Total = CaseCnt.getCount() - CaseCnt.getParentCount();
+ uint64_t Total = CaseCnt.getCount();
unsigned NCases = Range.getZExtValue() + 1;
// We only have one region counter for the entire set of cases here, so we
// need to divide the weights evenly between the generated cases, ensuring
llvm::MDNode *Weights = 0;
if (SwitchWeights) {
- uint64_t ThisCount = CaseCnt.getCount() - CaseCnt.getParentCount();
+ uint64_t ThisCount = CaseCnt.getCount();
uint64_t DefaultCount = (*SwitchWeights)[0];
Weights = PGO.createBranchWeights(ThisCount, DefaultCount);
// Only do this optimization if there are no cleanups that need emitting.
if (isObviouslyBranchWithoutCleanups(Block)) {
if (SwitchWeights)
- SwitchWeights->push_back(CaseCnt.getCount() - CaseCnt.getParentCount());
+ SwitchWeights->push_back(CaseCnt.getCount());
SwitchInsn->addCase(CaseVal, Block.getBlock());
// If there was a fallthrough into this case, make sure to redirect it to
}
}
- EmitBlock(createBasicBlock("sw.bb"));
- llvm::BasicBlock *CaseDest = Builder.GetInsertBlock();
+ llvm::BasicBlock *CaseDest = createBasicBlock("sw.bb");
+ EmitBlockWithFallThrough(CaseDest, CaseCnt);
if (SwitchWeights)
- SwitchWeights->push_back(CaseCnt.getCount() - CaseCnt.getParentCount());
- CaseCnt.beginRegion(Builder);
+ SwitchWeights->push_back(CaseCnt.getCount());
SwitchInsn->addCase(CaseVal, CaseDest);
// Recursively emitting the statement is acceptable, but is not wonderful for
CaseCnt = getPGORegionCounter(NextCase);
if (SwitchWeights)
- SwitchWeights->push_back(CaseCnt.getCount() - CaseCnt.getParentCount());
- CaseCnt.beginRegion(Builder);
+ SwitchWeights->push_back(CaseCnt.getCount());
+ if (CGM.getCodeGenOpts().ProfileInstrGenerate) {
+ CaseDest = createBasicBlock("sw.bb");
+ EmitBlockWithFallThrough(CaseDest, CaseCnt);
+ }
SwitchInsn->addCase(CaseVal, CaseDest);
NextCase = dyn_cast<CaseStmt>(CurCase->getSubStmt());
assert(DefaultBlock->empty() &&
"EmitDefaultStmt: Default block already defined?");
- llvm::BasicBlock *SkipCountBB = 0;
- if (CGM.getCodeGenOpts().ProfileInstrGenerate) {
- // The PGO region here needs to count the number of times the edge occurs,
- // so fallthrough into this case will jump past the region counter to the
- // skipcount basic block.
- SkipCountBB = createBasicBlock("skipcount");
- EmitBranch(SkipCountBB);
- }
- EmitBlock(DefaultBlock);
-
RegionCounter Cnt = getPGORegionCounter(&S);
- Cnt.beginRegion(Builder, /*AddIncomingFallThrough=*/true);
+ EmitBlockWithFallThrough(DefaultBlock, Cnt);
- if (SkipCountBB)
- EmitBlock(SkipCountBB);
EmitStmt(S.getSubStmt());
}
// Clear the insertion point to indicate we are in unreachable code.
Builder.ClearInsertionPoint();
- PGO.setCurrentRegionUnreachable();
// All break statements jump to NextBlock. If BreakContinueStack is non-empty
- // then reuse last ContinueBlock and that block's counter.
+ // then reuse last ContinueBlock.
JumpDest OuterContinue;
- RegionCounter *OuterCount = 0;
- if (!BreakContinueStack.empty()) {
- BreakContinue &BC = BreakContinueStack.back();
- OuterContinue = BC.ContinueBlock;
- OuterCount = BC.LoopCnt;
- }
+ if (!BreakContinueStack.empty())
+ OuterContinue = BreakContinueStack.back().ContinueBlock;
- BreakContinueStack.push_back(BreakContinue(SwitchExit, OuterContinue,
- OuterCount, /*CountBreak=*/false));
+ BreakContinueStack.push_back(BreakContinue(SwitchExit, OuterContinue));
// Emit switch body.
EmitStmt(S.getBody());
EmitStmt(Body);
}
+/// When instrumenting to collect profile data, the counts for some blocks
+/// such as switch cases need to not include the fall-through counts, so
+/// emit a branch around the instrumentation code. When not instrumenting,
+/// this just calls EmitBlock().
+void CodeGenFunction::EmitBlockWithFallThrough(llvm::BasicBlock *BB,
+ RegionCounter &Cnt) {
+ llvm::BasicBlock *SkipCountBB = 0;
+ if (HaveInsertPoint() && CGM.getCodeGenOpts().ProfileInstrGenerate) {
+ // When instrumenting for profiling, the fallthrough to certain
+ // statements needs to skip over the instrumentation code so that we
+ // get an accurate count.
+ SkipCountBB = createBasicBlock("skipcount");
+ EmitBranch(SkipCountBB);
+ }
+ EmitBlock(BB);
+ Cnt.beginRegion(Builder, /*AddIncomingFallThrough=*/true);
+ if (SkipCountBB)
+ EmitBlock(SkipCountBB);
+}
+
/// Tries to mark the given function nounwind based on the
/// non-existence of any throwing calls within it. We believe this is
/// lightweight enough to do at -O0.
Cond = Cond->IgnoreParens();
if (const BinaryOperator *CondBOp = dyn_cast<BinaryOperator>(Cond)) {
- RegionCounter Cnt = getPGORegionCounter(CondBOp);
// Handle X && Y in a condition.
if (CondBOp->getOpcode() == BO_LAnd) {
+ RegionCounter Cnt = getPGORegionCounter(CondBOp);
+
// If we have "1 && X", simplify the code. "0 && X" would have constant
// folded if the case was simple enough.
bool ConstantBool = false;
eval.begin(*this);
EmitBranchOnBoolExpr(CondBOp->getRHS(), TrueBlock, FalseBlock, TrueCount);
eval.end(*this);
- Cnt.adjustForControlFlow();
- Cnt.applyAdjustmentsToRegion();
return;
}
if (CondBOp->getOpcode() == BO_LOr) {
+ RegionCounter Cnt = getPGORegionCounter(CondBOp);
+
// If we have "0 || X", simplify the code. "1 || X" would have constant
// folded if the case was simple enough.
bool ConstantBool = false;
EmitBranchOnBoolExpr(CondBOp->getRHS(), TrueBlock, FalseBlock, RHSCount);
eval.end(*this);
- Cnt.adjustForControlFlow();
- Cnt.applyAdjustmentsToRegion();
return;
}
// the conditional operator.
uint64_t LHSScaledTrueCount = 0;
if (TrueCount) {
- double LHSRatio = Cnt.getCount() / (double) PGO.getCurrentRegionCount();
+ double LHSRatio = Cnt.getCount() / (double) Cnt.getParentCount();
LHSScaledTrueCount = TrueCount * LHSRatio;
}
cond.begin(*this);
EmitBlock(RHSBlock);
- Cnt.beginElseRegion();
EmitBranchOnBoolExpr(CondOp->getRHS(), TrueBlock, FalseBlock,
TrueCount - LHSScaledTrueCount);
cond.end(*this);
// Create branch weights based on the number of times we get here and the
// number of times the condition should be true.
- uint64_t CurrentCount = PGO.getCurrentRegionCountWithMin(TrueCount);
+ uint64_t CurrentCount = std::max(PGO.getCurrentRegionCount(), TrueCount);
llvm::MDNode *Weights = PGO.createBranchWeights(TrueCount,
CurrentCount - TrueCount);
llvm::DenseMap<const LabelDecl*, JumpDest> LabelMap;
// BreakContinueStack - This keeps track of where break and continue
- // statements should jump to and the associated base counter for
- // instrumentation.
+ // statements should jump to.
struct BreakContinue {
- BreakContinue(JumpDest Break, JumpDest Continue, RegionCounter *LoopCnt,
- bool CountBreak = true)
- : BreakBlock(Break), ContinueBlock(Continue), LoopCnt(LoopCnt),
- CountBreak(CountBreak) {}
+ BreakContinue(JumpDest Break, JumpDest Continue)
+ : BreakBlock(Break), ContinueBlock(Continue) {}
JumpDest BreakBlock;
JumpDest ContinueBlock;
- RegionCounter *LoopCnt;
- bool CountBreak;
};
SmallVector<BreakContinue, 8> BreakContinueStack;
void EmitDestructorBody(FunctionArgList &Args);
void emitImplicitAssignmentOperatorBody(FunctionArgList &Args);
void EmitFunctionBody(FunctionArgList &Args, const Stmt *Body);
+ void EmitBlockWithFallThrough(llvm::BasicBlock *BB, RegionCounter &Cnt);
void EmitForwardingCallToLambda(const CXXMethodDecl *LambdaCallOperator,
CallArgList &CallArgs);
(*CounterMap)[S] = NextCounter++;
Visit(S->getSubStmt());
}
- /// Assign three counters - one for the body of the loop, one for breaks
- /// from the loop, and one for continues.
- ///
- /// The break and continue counters cover all such statements in this loop,
- /// and are used in calculations to find the number of times the condition
- /// and exit of the loop occur. They are needed so we can differentiate
- /// these statements from non-local exits like return and goto.
+ /// Assign a counter for the body of a while loop.
void VisitWhileStmt(const WhileStmt *S) {
- (*CounterMap)[S] = NextCounter;
- NextCounter += 3;
+ (*CounterMap)[S] = NextCounter++;
Visit(S->getCond());
Visit(S->getBody());
}
- /// Assign counters for the body of the loop, and for breaks and
- /// continues. See VisitWhileStmt.
+ /// Assign a counter for the body of a do-while loop.
void VisitDoStmt(const DoStmt *S) {
- (*CounterMap)[S] = NextCounter;
- NextCounter += 3;
+ (*CounterMap)[S] = NextCounter++;
Visit(S->getBody());
Visit(S->getCond());
}
- /// Assign counters for the body of the loop, and for breaks and
- /// continues. See VisitWhileStmt.
+ /// Assign a counter for the body of a for loop.
void VisitForStmt(const ForStmt *S) {
- (*CounterMap)[S] = NextCounter;
- NextCounter += 3;
+ (*CounterMap)[S] = NextCounter++;
+ if (S->getInit())
+ Visit(S->getInit());
const Expr *E;
if ((E = S->getCond()))
Visit(E);
- Visit(S->getBody());
if ((E = S->getInc()))
Visit(E);
+ Visit(S->getBody());
}
- /// Assign counters for the body of the loop, and for breaks and
- /// continues. See VisitWhileStmt.
+ /// Assign a counter for the body of a for-range loop.
void VisitCXXForRangeStmt(const CXXForRangeStmt *S) {
- (*CounterMap)[S] = NextCounter;
- NextCounter += 3;
- const Expr *E;
- if ((E = S->getCond()))
- Visit(E);
+ (*CounterMap)[S] = NextCounter++;
+ Visit(S->getRangeStmt());
+ Visit(S->getBeginEndStmt());
+ Visit(S->getCond());
+ Visit(S->getLoopVarStmt());
Visit(S->getBody());
- if ((E = S->getInc()))
- Visit(E);
+ Visit(S->getInc());
}
- /// Assign counters for the body of the loop, and for breaks and
- /// continues. See VisitWhileStmt.
+ /// Assign a counter for the body of a for-collection loop.
void VisitObjCForCollectionStmt(const ObjCForCollectionStmt *S) {
- (*CounterMap)[S] = NextCounter;
- NextCounter += 3;
+ (*CounterMap)[S] = NextCounter++;
Visit(S->getElement());
Visit(S->getBody());
}
Visit(E->getRHS());
}
};
+
+ /// A StmtVisitor that propagates the raw counts through the AST and
+ /// records the count at statements where the value may change.
+ struct ComputeRegionCounts : public ConstStmtVisitor<ComputeRegionCounts> {
+ /// PGO state.
+ CodeGenPGO &PGO;
+
+ /// A flag that is set when the current count should be recorded on the
+ /// next statement, such as at the exit of a loop.
+ bool RecordNextStmtCount;
+
+ /// The map of statements to count values.
+ llvm::DenseMap<const Stmt*, uint64_t> *CountMap;
+
+ /// BreakContinueStack - Keep counts of breaks and continues inside loops.
+ struct BreakContinue {
+ uint64_t BreakCount;
+ uint64_t ContinueCount;
+ BreakContinue() : BreakCount(0), ContinueCount(0) {}
+ };
+ SmallVector<BreakContinue, 8> BreakContinueStack;
+
+ ComputeRegionCounts(llvm::DenseMap<const Stmt*, uint64_t> *CountMap,
+ CodeGenPGO &PGO) :
+ PGO(PGO), RecordNextStmtCount(false), CountMap(CountMap) {
+ }
+
+ void RecordStmtCount(const Stmt *S) {
+ if (RecordNextStmtCount) {
+ (*CountMap)[S] = PGO.getCurrentRegionCount();
+ RecordNextStmtCount = false;
+ }
+ }
+
+ void VisitStmt(const Stmt *S) {
+ RecordStmtCount(S);
+ for (Stmt::const_child_range I = S->children(); I; ++I) {
+ if (*I)
+ this->Visit(*I);
+ }
+ }
+
+ void VisitFunctionDecl(const FunctionDecl *S) {
+ RegionCounter Cnt(PGO, S->getBody());
+ Cnt.beginRegion();
+ (*CountMap)[S->getBody()] = PGO.getCurrentRegionCount();
+ Visit(S->getBody());
+ }
+
+ void VisitReturnStmt(const ReturnStmt *S) {
+ RecordStmtCount(S);
+ if (S->getRetValue())
+ Visit(S->getRetValue());
+ PGO.setCurrentRegionUnreachable();
+ RecordNextStmtCount = true;
+ }
+
+ void VisitGotoStmt(const GotoStmt *S) {
+ RecordStmtCount(S);
+ PGO.setCurrentRegionUnreachable();
+ RecordNextStmtCount = true;
+ }
+
+ void VisitLabelStmt(const LabelStmt *S) {
+ RecordNextStmtCount = false;
+ RegionCounter Cnt(PGO, S);
+ Cnt.beginRegion();
+ (*CountMap)[S] = PGO.getCurrentRegionCount();
+ Visit(S->getSubStmt());
+ }
+
+ void VisitBreakStmt(const BreakStmt *S) {
+ RecordStmtCount(S);
+ assert(!BreakContinueStack.empty() && "break not in a loop or switch!");
+ BreakContinueStack.back().BreakCount += PGO.getCurrentRegionCount();
+ PGO.setCurrentRegionUnreachable();
+ RecordNextStmtCount = true;
+ }
+
+ void VisitContinueStmt(const ContinueStmt *S) {
+ RecordStmtCount(S);
+ assert(!BreakContinueStack.empty() && "continue stmt not in a loop!");
+ BreakContinueStack.back().ContinueCount += PGO.getCurrentRegionCount();
+ PGO.setCurrentRegionUnreachable();
+ RecordNextStmtCount = true;
+ }
+
+ void VisitWhileStmt(const WhileStmt *S) {
+ RecordStmtCount(S);
+ RegionCounter Cnt(PGO, S);
+ BreakContinueStack.push_back(BreakContinue());
+ // Visit the body region first so the break/continue adjustments can be
+ // included when visiting the condition.
+ Cnt.beginRegion();
+ (*CountMap)[S->getBody()] = PGO.getCurrentRegionCount();
+ Visit(S->getBody());
+ Cnt.adjustForControlFlow();
+
+ // ...then go back and propagate counts through the condition. The count
+ // at the start of the condition is the sum of the incoming edges,
+ // the backedge from the end of the loop body, and the edges from
+ // continue statements.
+ BreakContinue BC = BreakContinueStack.pop_back_val();
+ Cnt.setCurrentRegionCount(Cnt.getParentCount() +
+ Cnt.getAdjustedCount() + BC.ContinueCount);
+ (*CountMap)[S->getCond()] = PGO.getCurrentRegionCount();
+ Visit(S->getCond());
+ Cnt.adjustForControlFlow();
+ Cnt.applyAdjustmentsToRegion(BC.BreakCount + BC.ContinueCount);
+ RecordNextStmtCount = true;
+ }
+
+ void VisitDoStmt(const DoStmt *S) {
+ RecordStmtCount(S);
+ RegionCounter Cnt(PGO, S);
+ BreakContinueStack.push_back(BreakContinue());
+ Cnt.beginRegion(/*AddIncomingFallThrough=*/true);
+ (*CountMap)[S->getBody()] = PGO.getCurrentRegionCount();
+ Visit(S->getBody());
+ Cnt.adjustForControlFlow();
+
+ BreakContinue BC = BreakContinueStack.pop_back_val();
+ // The count at the start of the condition is equal to the count at the
+ // end of the body. The adjusted count does not include either the
+ // fall-through count coming into the loop or the continue count, so add
+ // both of those separately. This is coincidentally the same equation as
+ // with while loops but for different reasons.
+ Cnt.setCurrentRegionCount(Cnt.getParentCount() +
+ Cnt.getAdjustedCount() + BC.ContinueCount);
+ (*CountMap)[S->getCond()] = PGO.getCurrentRegionCount();
+ Visit(S->getCond());
+ Cnt.adjustForControlFlow();
+ Cnt.applyAdjustmentsToRegion(BC.BreakCount + BC.ContinueCount);
+ RecordNextStmtCount = true;
+ }
+
+ void VisitForStmt(const ForStmt *S) {
+ RecordStmtCount(S);
+ if (S->getInit())
+ Visit(S->getInit());
+ RegionCounter Cnt(PGO, S);
+ BreakContinueStack.push_back(BreakContinue());
+ // Visit the body region first. (This is basically the same as a while
+ // loop; see further comments in VisitWhileStmt.)
+ Cnt.beginRegion();
+ (*CountMap)[S->getBody()] = PGO.getCurrentRegionCount();
+ Visit(S->getBody());
+ Cnt.adjustForControlFlow();
+
+ // The increment is essentially part of the body but it needs to include
+ // the count for all the continue statements.
+ if (S->getInc()) {
+ Cnt.setCurrentRegionCount(PGO.getCurrentRegionCount() +
+ BreakContinueStack.back().ContinueCount);
+ (*CountMap)[S->getInc()] = PGO.getCurrentRegionCount();
+ Visit(S->getInc());
+ Cnt.adjustForControlFlow();
+ }
+
+ BreakContinue BC = BreakContinueStack.pop_back_val();
+
+ // ...then go back and propagate counts through the condition.
+ if (S->getCond()) {
+ Cnt.setCurrentRegionCount(Cnt.getParentCount() +
+ Cnt.getAdjustedCount() +
+ BC.ContinueCount);
+ (*CountMap)[S->getCond()] = PGO.getCurrentRegionCount();
+ Visit(S->getCond());
+ Cnt.adjustForControlFlow();
+ }
+ Cnt.applyAdjustmentsToRegion(BC.BreakCount + BC.ContinueCount);
+ RecordNextStmtCount = true;
+ }
+
+ void VisitCXXForRangeStmt(const CXXForRangeStmt *S) {
+ RecordStmtCount(S);
+ Visit(S->getRangeStmt());
+ Visit(S->getBeginEndStmt());
+ RegionCounter Cnt(PGO, S);
+ BreakContinueStack.push_back(BreakContinue());
+ // Visit the body region first. (This is basically the same as a while
+ // loop; see further comments in VisitWhileStmt.)
+ Cnt.beginRegion();
+ (*CountMap)[S->getLoopVarStmt()] = PGO.getCurrentRegionCount();
+ Visit(S->getLoopVarStmt());
+ Visit(S->getBody());
+ Cnt.adjustForControlFlow();
+
+ // The increment is essentially part of the body but it needs to include
+ // the count for all the continue statements.
+ Cnt.setCurrentRegionCount(PGO.getCurrentRegionCount() +
+ BreakContinueStack.back().ContinueCount);
+ (*CountMap)[S->getInc()] = PGO.getCurrentRegionCount();
+ Visit(S->getInc());
+ Cnt.adjustForControlFlow();
+
+ BreakContinue BC = BreakContinueStack.pop_back_val();
+
+ // ...then go back and propagate counts through the condition.
+ Cnt.setCurrentRegionCount(Cnt.getParentCount() +
+ Cnt.getAdjustedCount() +
+ BC.ContinueCount);
+ (*CountMap)[S->getCond()] = PGO.getCurrentRegionCount();
+ Visit(S->getCond());
+ Cnt.adjustForControlFlow();
+ Cnt.applyAdjustmentsToRegion(BC.BreakCount + BC.ContinueCount);
+ RecordNextStmtCount = true;
+ }
+
+ void VisitObjCForCollectionStmt(const ObjCForCollectionStmt *S) {
+ RecordStmtCount(S);
+ Visit(S->getElement());
+ RegionCounter Cnt(PGO, S);
+ BreakContinueStack.push_back(BreakContinue());
+ Cnt.beginRegion();
+ (*CountMap)[S->getBody()] = PGO.getCurrentRegionCount();
+ Visit(S->getBody());
+ BreakContinue BC = BreakContinueStack.pop_back_val();
+ Cnt.adjustForControlFlow();
+ Cnt.applyAdjustmentsToRegion(BC.BreakCount + BC.ContinueCount);
+ RecordNextStmtCount = true;
+ }
+
+ void VisitSwitchStmt(const SwitchStmt *S) {
+ RecordStmtCount(S);
+ Visit(S->getCond());
+ PGO.setCurrentRegionUnreachable();
+ BreakContinueStack.push_back(BreakContinue());
+ Visit(S->getBody());
+ // If the switch is inside a loop, add the continue counts.
+ BreakContinue BC = BreakContinueStack.pop_back_val();
+ if (!BreakContinueStack.empty())
+ BreakContinueStack.back().ContinueCount += BC.ContinueCount;
+ RegionCounter ExitCnt(PGO, S);
+ ExitCnt.beginRegion();
+ RecordNextStmtCount = true;
+ }
+
+ void VisitCaseStmt(const CaseStmt *S) {
+ RecordNextStmtCount = false;
+ RegionCounter Cnt(PGO, S);
+ Cnt.beginRegion(/*AddIncomingFallThrough=*/true);
+ (*CountMap)[S] = Cnt.getCount();
+ RecordNextStmtCount = true;
+ Visit(S->getSubStmt());
+ }
+
+ void VisitDefaultStmt(const DefaultStmt *S) {
+ RecordNextStmtCount = false;
+ RegionCounter Cnt(PGO, S);
+ Cnt.beginRegion(/*AddIncomingFallThrough=*/true);
+ (*CountMap)[S] = Cnt.getCount();
+ RecordNextStmtCount = true;
+ Visit(S->getSubStmt());
+ }
+
+ void VisitIfStmt(const IfStmt *S) {
+ RecordStmtCount(S);
+ RegionCounter Cnt(PGO, S);
+ Visit(S->getCond());
+
+ Cnt.beginRegion();
+ (*CountMap)[S->getThen()] = PGO.getCurrentRegionCount();
+ Visit(S->getThen());
+ Cnt.adjustForControlFlow();
+
+ if (S->getElse()) {
+ Cnt.beginElseRegion();
+ (*CountMap)[S->getElse()] = PGO.getCurrentRegionCount();
+ Visit(S->getElse());
+ Cnt.adjustForControlFlow();
+ }
+ Cnt.applyAdjustmentsToRegion(0);
+ RecordNextStmtCount = true;
+ }
+
+ void VisitCXXTryStmt(const CXXTryStmt *S) {
+ RecordStmtCount(S);
+ Visit(S->getTryBlock());
+ for (unsigned I = 0, E = S->getNumHandlers(); I < E; ++I)
+ Visit(S->getHandler(I));
+ RegionCounter Cnt(PGO, S);
+ Cnt.beginRegion();
+ RecordNextStmtCount = true;
+ }
+
+ void VisitCXXCatchStmt(const CXXCatchStmt *S) {
+ RecordNextStmtCount = false;
+ RegionCounter Cnt(PGO, S);
+ Cnt.beginRegion();
+ (*CountMap)[S] = PGO.getCurrentRegionCount();
+ Visit(S->getHandlerBlock());
+ }
+
+ void VisitConditionalOperator(const ConditionalOperator *E) {
+ RecordStmtCount(E);
+ RegionCounter Cnt(PGO, E);
+ Visit(E->getCond());
+
+ Cnt.beginRegion();
+ (*CountMap)[E->getTrueExpr()] = PGO.getCurrentRegionCount();
+ Visit(E->getTrueExpr());
+ Cnt.adjustForControlFlow();
+
+ Cnt.beginElseRegion();
+ (*CountMap)[E->getFalseExpr()] = PGO.getCurrentRegionCount();
+ Visit(E->getFalseExpr());
+ Cnt.adjustForControlFlow();
+
+ Cnt.applyAdjustmentsToRegion(0);
+ RecordNextStmtCount = true;
+ }
+
+ void VisitBinLAnd(const BinaryOperator *E) {
+ RecordStmtCount(E);
+ RegionCounter Cnt(PGO, E);
+ Visit(E->getLHS());
+ Cnt.beginRegion();
+ (*CountMap)[E->getRHS()] = PGO.getCurrentRegionCount();
+ Visit(E->getRHS());
+ Cnt.adjustForControlFlow();
+ Cnt.applyAdjustmentsToRegion(0);
+ RecordNextStmtCount = true;
+ }
+
+ void VisitBinLOr(const BinaryOperator *E) {
+ RecordStmtCount(E);
+ RegionCounter Cnt(PGO, E);
+ Visit(E->getLHS());
+ Cnt.beginRegion();
+ (*CountMap)[E->getRHS()] = PGO.getCurrentRegionCount();
+ Visit(E->getRHS());
+ Cnt.adjustForControlFlow();
+ Cnt.applyAdjustmentsToRegion(0);
+ RecordNextStmtCount = true;
+ }
+ };
}
void CodeGenPGO::assignRegionCounters(GlobalDecl &GD) {
mapRegionCounters(D);
if (InstrumentRegions)
emitCounterVariables();
- if (PGOData)
+ if (PGOData) {
loadRegionCounts(GD, PGOData);
+ computeRegionCounts(D);
+ }
}
void CodeGenPGO::mapRegionCounters(const Decl *D) {
NumRegionCounters = Walker.NextCounter;
}
+void CodeGenPGO::computeRegionCounts(const Decl *D) {
+ StmtCountMap = new llvm::DenseMap<const Stmt*, uint64_t>();
+ ComputeRegionCounts Walker(StmtCountMap, *this);
+ if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D))
+ Walker.VisitFunctionDecl(FD);
+}
+
void CodeGenPGO::emitCounterVariables() {
llvm::LLVMContext &Ctx = CGM.getLLVMContext();
llvm::ArrayType *CounterTy = llvm::ArrayType::get(llvm::Type::getInt64Ty(Ctx),
void CodeGenPGO::destroyRegionCounters() {
if (RegionCounterMap != 0)
delete RegionCounterMap;
+ if (StmtCountMap != 0)
+ delete StmtCountMap;
if (RegionCounts != 0)
delete RegionCounts;
}
}
return MDHelper.createBranchWeights(ScaledWeights);
}
+
+llvm::MDNode *CodeGenPGO::createLoopWeights(const Stmt *Cond,
+ RegionCounter &Cnt) {
+ if (!haveRegionCounts())
+ return 0;
+ uint64_t LoopCount = Cnt.getCount();
+ uint64_t CondCount = 0;
+ bool Found = getStmtCount(Cond, CondCount);
+ assert(Found && "missing expected loop condition count");
+ (void)Found;
+ if (CondCount == 0)
+ return 0;
+ return createBranchWeights(LoopCount,
+ std::max(CondCount, LoopCount) - LoopCount);
+}
unsigned NumRegionCounters;
llvm::GlobalVariable *RegionCounters;
llvm::DenseMap<const Stmt*, unsigned> *RegionCounterMap;
+ llvm::DenseMap<const Stmt*, uint64_t> *StmtCountMap;
std::vector<uint64_t> *RegionCounts;
uint64_t CurrentRegionCount;
public:
CodeGenPGO(CodeGenModule &CGM)
: CGM(CGM), NumRegionCounters(0), RegionCounters(0), RegionCounterMap(0),
- RegionCounts(0), CurrentRegionCount(0) {}
+ StmtCountMap(0), RegionCounts(0), CurrentRegionCount(0) {}
~CodeGenPGO() {}
/// Whether or not we have PGO region data for the current function. This is
/// Return the counter value of the current region.
uint64_t getCurrentRegionCount() const { return CurrentRegionCount; }
- /// Return the counter value of the current region, or \p Min if it is larger.
- uint64_t getCurrentRegionCountWithMin(uint64_t Min) {
- return std::max(Min, CurrentRegionCount);
- }
+
/// Set the counter value for the current region. This is used to keep track
/// of changes to the most recent counter from control flow and non-local
/// exits.
void setCurrentRegionCount(uint64_t Count) { CurrentRegionCount = Count; }
+
/// Indicate that the current region is never reached, and thus should have a
/// counter value of zero. This is important so that subsequent regions can
/// correctly track their parent counts.
void setCurrentRegionUnreachable() { setCurrentRegionCount(0); }
+ /// Check if an execution count is known for a given statement. If so, return
+ /// true and put the value in Count; else return false.
+ bool getStmtCount(const Stmt *S, uint64_t &Count) {
+ if (!StmtCountMap)
+ return false;
+ llvm::DenseMap<const Stmt*, uint64_t>::const_iterator
+ I = StmtCountMap->find(S);
+ if (I == StmtCountMap->end())
+ return false;
+ Count = I->second;
+ return true;
+ }
+
+ /// If the execution count for the current statement is known, record that
+ /// as the current count.
+ void setCurrentStmt(const Stmt *S) {
+ uint64_t Count;
+ if (getStmtCount(S, Count))
+ setCurrentRegionCount(Count);
+ }
+
/// Calculate branch weights appropriate for PGO data
llvm::MDNode *createBranchWeights(uint64_t TrueCount, uint64_t FalseCount);
llvm::MDNode *createBranchWeights(ArrayRef<uint64_t> Weights);
+ llvm::MDNode *createLoopWeights(const Stmt *Cond, RegionCounter &Cnt);
/// Assign counters to regions and configure them for PGO of a given
/// function. Does nothing if instrumentation is not enabled and either
private:
void mapRegionCounters(const Decl *D);
+ void computeRegionCounts(const Decl *D);
void loadRegionCounts(GlobalDecl &GD, PGOProfileData *PGOData);
void emitCounterVariables();
/// the region of the counter was entered, but for switch labels it's the
/// number of direct jumps to that label.
uint64_t getCount() const { return Count; }
+
/// Get the value of the counter with adjustments applied. Adjustments occur
/// when control enters or leaves the region abnormally; i.e., if there is a
/// jump to a label within the region, or if the function can return from
assert((Adjust > 0 || (uint64_t)(-Adjust) <= Count) && "Negative count");
return Count + Adjust;
}
+
/// Get the value of the counter in this region's parent, i.e., the region
/// that was active when this region began. This is useful for deriving
/// counts in implicitly counted regions, like the false case of a condition
/// or the normal exits of a loop.
uint64_t getParentCount() const { return ParentCount; }
- /// Get the number of times the condition of a loop will evaluate false. This
- /// is the number of times we enter the loop, adjusted by the difference
- /// between entering and exiting the loop body normally, excepting that
- /// 'continue' statements also bring us back here.
- ///
- /// Undefined if this counter is not counting a loop.
- uint64_t getLoopExitCount() const {
- return getParentCount() + getContinueCounter().getCount() +
- getAdjustedCount() - getCount();
- }
- /// Get the associated break counter. Undefined if this counter is not
- /// counting a loop.
- RegionCounter getBreakCounter() const {
- return RegionCounter(*PGO, Counter + 1);
- }
- /// Get the associated continue counter. Undefined if this counter is not
- /// counting a loop.
- RegionCounter getContinueCounter() const {
- return RegionCounter(*PGO, Counter + 2);
- }
-
/// Activate the counter by emitting an increment and starting to track
/// adjustments. If AddIncomingFallThrough is true, the current region count
/// will be added to the counter for the purposes of tracking the region.
void beginRegion(CGBuilderTy &Builder, bool AddIncomingFallThrough=false) {
+ beginRegion(AddIncomingFallThrough);
+ PGO->emitCounterIncrement(Builder, Counter);
+ }
+ void beginRegion(bool AddIncomingFallThrough=false) {
RegionCount = Count;
if (AddIncomingFallThrough)
RegionCount += PGO->getCurrentRegionCount();
PGO->setCurrentRegionCount(RegionCount);
- PGO->emitCounterIncrement(Builder, Counter);
}
+
/// For counters on boolean branches, begins tracking adjustments for the
/// uncounted path.
void beginElseRegion() {
PGO->setCurrentRegionCount(RegionCount);
}
+ /// Reset the current region count.
+ void setCurrentRegionCount(uint64_t CurrentCount) {
+ RegionCount = CurrentCount;
+ PGO->setCurrentRegionCount(RegionCount);
+ }
+
/// Adjust for non-local control flow after emitting a subexpression or
/// substatement. This must be called to account for constructs such as gotos,
/// labels, and returns, so that we can ensure that our region's count is
/// correct in the code that follows.
void adjustForControlFlow() {
Adjust += PGO->getCurrentRegionCount() - RegionCount;
+ // Reset the region count in case this is called again later.
+ RegionCount = PGO->getCurrentRegionCount();
}
- /// Commit all adjustments to the current region. This should be called after
- /// all blocks that adjust for control flow count have been emitted.
- void applyAdjustmentsToRegion() {
- PGO->setCurrentRegionCount(ParentCount + Adjust);
+
+ /// Commit all adjustments to the current region. If the region is a loop,
+ /// the LoopAdjust value should be the count of all the breaks and continues
+ /// from the loop, to compensate for those counts being deducted from the
+ /// adjustments for the body of the loop.
+ void applyAdjustmentsToRegion(uint64_t LoopAdjust) {
+ PGO->setCurrentRegionCount(ParentCount + Adjust + LoopAdjust);
}
};
-simple_loops 10
+simple_loops 4
1
100
-0
-0
100
-0
-0
-76
-0
-0
+75
-conditionals 13
+conditionals 11
1
100
-0
-0
50
50
33
99
100
-early_exits 13
+early_exits 9
1
0
51
1
25
1
-26
-0
-0
-1
0
-jumps 30
+jumps 22
1
1
0
-0
-0
1
0
0
-0
-0
1
0
1
3
2
0
-0
-0
3
0
1
1
10
0
-0
-0
10
9
-switches 21
+switches 19
1
1
1
15
-0
-7
7
1
0
-3
+2
2
3
3
1
0
-big_switch 19
+big_switch 17
1
32
-0
-0
32
1
0
-2
+1
1
11
11
issue_with_one_counter 1
0
-boolean_operators 10
+boolean_operators 8
1
100
-0
-0
34
66
17
33
50
+boolop_loops 9
+1
+50
+51
+50
+26
+50
+51
+50
+26
+
no_usable_data 5
1
1
main 1
1
+
// RUN: %clang %s -o - -emit-llvm -S -fprofile-instr-generate | FileCheck -check-prefix=PGOGEN %s
// RUN: %clang %s -o - -emit-llvm -S -fprofile-instr-use=%S/Inputs/instr-profile.pgodata | FileCheck -check-prefix=PGOUSE %s
-// PGOGEN: @[[SLC:__llvm_pgo_ctr[0-9]*]] = private global [10 x i64] zeroinitializer
-// PGOGEN: @[[IFC:__llvm_pgo_ctr[0-9]*]] = private global [13 x i64] zeroinitializer
-// PGOGEN: @[[EEC:__llvm_pgo_ctr[0-9]*]] = private global [13 x i64] zeroinitializer
-// PGOGEN: @[[JMC:__llvm_pgo_ctr[0-9]*]] = private global [30 x i64] zeroinitializer
-// PGOGEN: @[[SWC:__llvm_pgo_ctr[0-9]*]] = private global [21 x i64] zeroinitializer
-// PGOGEN: @[[BSC:__llvm_pgo_ctr[0-9]*]] = private global [19 x i64] zeroinitializer
-// PGOGEN: @[[BOC:__llvm_pgo_ctr[0-9]*]] = private global [10 x i64] zeroinitializer
+// PGOGEN: @[[SLC:__llvm_pgo_ctr[0-9]*]] = private global [4 x i64] zeroinitializer
+// PGOGEN: @[[IFC:__llvm_pgo_ctr[0-9]*]] = private global [11 x i64] zeroinitializer
+// PGOGEN: @[[EEC:__llvm_pgo_ctr[0-9]*]] = private global [9 x i64] zeroinitializer
+// PGOGEN: @[[JMC:__llvm_pgo_ctr[0-9]*]] = private global [22 x i64] zeroinitializer
+// PGOGEN: @[[SWC:__llvm_pgo_ctr[0-9]*]] = private global [19 x i64] zeroinitializer
+// PGOGEN: @[[BSC:__llvm_pgo_ctr[0-9]*]] = private global [17 x i64] zeroinitializer
+// PGOGEN: @[[BOC:__llvm_pgo_ctr[0-9]*]] = private global [8 x i64] zeroinitializer
+// PGOGEN: @[[BLC:__llvm_pgo_ctr[0-9]*]] = private global [9 x i64] zeroinitializer
// PGOGEN: @[[NOC:__llvm_pgo_ctr[0-9]*]] = private global [2 x i64] zeroinitializer
// PGOGEN: @[[MAC:__llvm_pgo_ctr[0-9]*]] = private global [1 x i64] zeroinitializer
// PGOUSE: br {{.*}} !prof ![[SL1:[0-9]+]]
for (i = 0; i < 100; ++i) {
}
- // PGOGEN: store {{.*}} @[[SLC]], i64 0, i64 4
+ // PGOGEN: store {{.*}} @[[SLC]], i64 0, i64 2
// PGOUSE: br {{.*}} !prof ![[SL2:[0-9]+]]
while (i > 0)
i--;
- // PGOGEN: store {{.*}} @[[SLC]], i64 0, i64 7
+ // PGOGEN: store {{.*}} @[[SLC]], i64 0, i64 3
// PGOUSE: br {{.*}} !prof ![[SL3:[0-9]+]]
do {} while (i++ < 75);
// PGOGEN: store {{.*}} @[[IFC]], i64 0, i64 1
// PGOUSE: br {{.*}} !prof ![[IF1:[0-9]+]]
for (int i = 0; i < 100; ++i) {
- // PGOGEN: store {{.*}} @[[IFC]], i64 0, i64 4
+ // PGOGEN: store {{.*}} @[[IFC]], i64 0, i64 2
// PGOUSE: br {{.*}} !prof ![[IF2:[0-9]+]]
if (i % 2) {
- // PGOGEN: store {{.*}} @[[IFC]], i64 0, i64 5
+ // PGOGEN: store {{.*}} @[[IFC]], i64 0, i64 3
// PGOUSE: br {{.*}} !prof ![[IF3:[0-9]+]]
if (i) {}
- // PGOGEN: store {{.*}} @[[IFC]], i64 0, i64 6
+ // PGOGEN: store {{.*}} @[[IFC]], i64 0, i64 4
// PGOUSE: br {{.*}} !prof ![[IF4:[0-9]+]]
} else if (i % 3) {
- // PGOGEN: store {{.*}} @[[IFC]], i64 0, i64 7
+ // PGOGEN: store {{.*}} @[[IFC]], i64 0, i64 5
// PGOUSE: br {{.*}} !prof ![[IF5:[0-9]+]]
if (i) {}
} else {
- // PGOGEN: store {{.*}} @[[IFC]], i64 0, i64 8
+ // PGOGEN: store {{.*}} @[[IFC]], i64 0, i64 6
// PGOUSE: br {{.*}} !prof ![[IF6:[0-9]+]]
if (i) {}
}
- // PGOGEN: store {{.*}} @[[IFC]], i64 0, i64 10
- // PGOGEN: store {{.*}} @[[IFC]], i64 0, i64 9
+ // PGOGEN: store {{.*}} @[[IFC]], i64 0, i64 8
+ // PGOGEN: store {{.*}} @[[IFC]], i64 0, i64 7
// PGOUSE: br {{.*}} !prof ![[IF7:[0-9]+]]
if (1 && i) {}
- // PGOGEN: store {{.*}} @[[IFC]], i64 0, i64 12
- // PGOGEN: store {{.*}} @[[IFC]], i64 0, i64 11
+ // PGOGEN: store {{.*}} @[[IFC]], i64 0, i64 10
+ // PGOGEN: store {{.*}} @[[IFC]], i64 0, i64 9
// PGOUSE: br {{.*}} !prof ![[IF8:[0-9]+]]
if (0 || i) {}
}
// PGOUSE: br {{.*}} !prof ![[EE2:[0-9]+]]
while (i < 100) {
i++;
- // PGOGEN: store {{.*}} @[[EEC]], i64 0, i64 5
+ // PGOGEN: store {{.*}} @[[EEC]], i64 0, i64 3
// PGOUSE: br {{.*}} !prof ![[EE3:[0-9]+]]
if (i > 50)
- // PGOGEN: store {{.*}} @[[EEC]], i64 0, i64 3
break;
- // PGOGEN: store {{.*}} @[[EEC]], i64 0, i64 6
+ // PGOGEN: store {{.*}} @[[EEC]], i64 0, i64 4
// PGOUSE: br {{.*}} !prof ![[EE4:[0-9]+]]
if (i % 2)
- // PGOGEN: store {{.*}} @[[EEC]], i64 0, i64 4
continue;
}
- // PGOGEN: store {{.*}} @[[EEC]], i64 0, i64 7
+ // PGOGEN: store {{.*}} @[[EEC]], i64 0, i64 5
// PGOUSE: br {{.*}} !prof ![[EE5:[0-9]+]]
if (i) {}
- // PGOGEN: store {{.*}} @[[EEC]], i64 0, i64 8
+ // PGOGEN: store {{.*}} @[[EEC]], i64 0, i64 6
do {
- // PGOGEN: store {{.*}} @[[EEC]], i64 0, i64 11
+ // PGOGEN: store {{.*}} @[[EEC]], i64 0, i64 7
// PGOUSE: br {{.*}} !prof ![[EE6:[0-9]+]]
if (i > 75)
return;
// PGOUSE: br {{.*}} !prof ![[EE7:[0-9]+]]
} while (i < 100);
- // PGOGEN: store {{.*}} @[[EEC]], i64 0, i64 12
+ // PGOGEN: store {{.*}} @[[EEC]], i64 0, i64 8
// Never reached -> no weights
if (i) {}
// Never reached -> no weights
if (i) {}
}
-// PGOGEN: store {{.*}} @[[JMC]], i64 0, i64 5
+// PGOGEN: store {{.*}} @[[JMC]], i64 0, i64 3
outofloop:
- // PGOGEN: store {{.*}} @[[JMC]], i64 0, i64 6
+ // PGOGEN: store {{.*}} @[[JMC]], i64 0, i64 4
// PGOUSE: br {{.*}} !prof ![[JM2:[0-9]+]]
if (i) {}
goto loop1;
- // PGOGEN: store {{.*}} @[[JMC]], i64 0, i64 7
+ // PGOGEN: store {{.*}} @[[JMC]], i64 0, i64 5
// PGOUSE: br {{.*}} !prof ![[JM3:[0-9]+]]
while (i) {
- // PGOGEN: store {{.*}} @[[JMC]], i64 0, i64 10
+ // PGOGEN: store {{.*}} @[[JMC]], i64 0, i64 6
loop1:
- // PGOGEN: store {{.*}} @[[JMC]], i64 0, i64 11
+ // PGOGEN: store {{.*}} @[[JMC]], i64 0, i64 7
// PGOUSE: br {{.*}} !prof ![[JM4:[0-9]+]]
if (i) {}
}
goto loop2;
-// PGOGEN: store {{.*}} @[[JMC]], i64 0, i64 12
+// PGOGEN: store {{.*}} @[[JMC]], i64 0, i64 8
first:
-// PGOGEN: store {{.*}} @[[JMC]], i64 0, i64 13
+// PGOGEN: store {{.*}} @[[JMC]], i64 0, i64 9
second:
-// PGOGEN: store {{.*}} @[[JMC]], i64 0, i64 14
+// PGOGEN: store {{.*}} @[[JMC]], i64 0, i64 10
third:
i++;
- // PGOGEN: store {{.*}} @[[JMC]], i64 0, i64 15
+ // PGOGEN: store {{.*}} @[[JMC]], i64 0, i64 11
// PGOUSE: br {{.*}} !prof ![[JM5:[0-9]+]]
if (i < 3)
goto loop2;
- // PGOGEN: store {{.*}} @[[JMC]], i64 0, i64 16
+ // PGOGEN: store {{.*}} @[[JMC]], i64 0, i64 12
// PGOUSE: br {{.*}} !prof ![[JM6:[0-9]+]]
while (i < 3) {
- // PGOGEN: store {{.*}} @[[JMC]], i64 0, i64 19
+ // PGOGEN: store {{.*}} @[[JMC]], i64 0, i64 13
loop2:
// PGOUSE: switch {{.*}} [
// PGOUSE: ], !prof ![[JM7:[0-9]+]]
switch (i) {
- // PGOGEN: store {{.*}} @[[JMC]], i64 0, i64 21
+ // PGOGEN: store {{.*}} @[[JMC]], i64 0, i64 15
case 0:
goto first;
- // PGOGEN: store {{.*}} @[[JMC]], i64 0, i64 22
+ // PGOGEN: store {{.*}} @[[JMC]], i64 0, i64 16
case 1:
goto second;
- // PGOGEN: store {{.*}} @[[JMC]], i64 0, i64 23
+ // PGOGEN: store {{.*}} @[[JMC]], i64 0, i64 17
case 2:
goto third;
}
- // PGOGEN: store {{.*}} @[[JMC]], i64 0, i64 20
+ // PGOGEN: store {{.*}} @[[JMC]], i64 0, i64 14
}
- // PGOGEN: store {{.*}} @[[JMC]], i64 0, i64 24
+ // PGOGEN: store {{.*}} @[[JMC]], i64 0, i64 18
// PGOUSE: br {{.*}} !prof ![[JM8:[0-9]+]]
for (i = 0; i < 10; ++i) {
goto withinloop;
// never reached -> no weights
if (i) {}
- // PGOGEN: store {{.*}} @[[JMC]], i64 0, i64 28
+ // PGOGEN: store {{.*}} @[[JMC]], i64 0, i64 20
withinloop:
- // PGOGEN: store {{.*}} @[[JMC]], i64 0, i64 29
+ // PGOGEN: store {{.*}} @[[JMC]], i64 0, i64 21
// PGOUSE: br {{.*}} !prof ![[JM9:[0-9]+]]
if (i) {}
}
// PGOUSE: switch {{.*}} [
// PGOUSE: ], !prof ![[SW2:[0-9]+]]
switch (i[weights]) {
- // PGOGEN: store {{.*}} @[[SWC]], i64 0, i64 7
+ // PGOGEN: store {{.*}} @[[SWC]], i64 0, i64 5
case 1:
- // PGOGEN: store {{.*}} @[[SWC]], i64 0, i64 8
+ // PGOGEN: store {{.*}} @[[SWC]], i64 0, i64 6
// PGOUSE: br {{.*}} !prof ![[SW3:[0-9]+]]
if (i) {}
// fallthrough
- // PGOGEN: store {{.*}} @[[SWC]], i64 0, i64 9
+ // PGOGEN: store {{.*}} @[[SWC]], i64 0, i64 7
case 2:
- // PGOGEN: store {{.*}} @[[SWC]], i64 0, i64 10
+ // PGOGEN: store {{.*}} @[[SWC]], i64 0, i64 8
// PGOUSE: br {{.*}} !prof ![[SW4:[0-9]+]]
if (i) {}
break;
- // PGOGEN: store {{.*}} @[[SWC]], i64 0, i64 11
+ // PGOGEN: store {{.*}} @[[SWC]], i64 0, i64 9
case 3:
- // PGOGEN: store {{.*}} @[[SWC]], i64 0, i64 12
+ // PGOGEN: store {{.*}} @[[SWC]], i64 0, i64 10
// PGOUSE: br {{.*}} !prof ![[SW5:[0-9]+]]
if (i) {}
continue;
- // PGOGEN: store {{.*}} @[[SWC]], i64 0, i64 13
+ // PGOGEN: store {{.*}} @[[SWC]], i64 0, i64 11
case 4:
- // PGOGEN: store {{.*}} @[[SWC]], i64 0, i64 14
+ // PGOGEN: store {{.*}} @[[SWC]], i64 0, i64 12
// PGOUSE: br {{.*}} !prof ![[SW6:[0-9]+]]
if (i) {}
// PGOUSE: switch {{.*}} [
// PGOUSE: ], !prof ![[SW7:[0-9]+]]
switch (i) {
- // PGOGEN: store {{.*}} @[[SWC]], i64 0, i64 16
+ // PGOGEN: store {{.*}} @[[SWC]], i64 0, i64 14
case 6 ... 9:
- // PGOGEN: store {{.*}} @[[SWC]], i64 0, i64 17
+ // PGOGEN: store {{.*}} @[[SWC]], i64 0, i64 15
// PGOUSE: br {{.*}} !prof ![[SW8:[0-9]+]]
if (i) {}
continue;
}
- // PGOGEN: store {{.*}} @[[SWC]], i64 0, i64 15
+ // PGOGEN: store {{.*}} @[[SWC]], i64 0, i64 13
- // PGOGEN: store {{.*}} @[[SWC]], i64 0, i64 18
+ // PGOGEN: store {{.*}} @[[SWC]], i64 0, i64 16
default:
- // PGOGEN: store {{.*}} @[[SWC]], i64 0, i64 19
+ // PGOGEN: store {{.*}} @[[SWC]], i64 0, i64 17
// PGOUSE: br {{.*}} !prof ![[SW9:[0-9]+]]
if (i == len - 1)
return;
}
- // PGOGEN: store {{.*}} @[[SWC]], i64 0, i64 6
+ // PGOGEN: store {{.*}} @[[SWC]], i64 0, i64 4
}
- // PGOGEN: store {{.*}} @[[SWC]], i64 0, i64 20
+ // PGOGEN: store {{.*}} @[[SWC]], i64 0, i64 18
// Never reached -> no weights
if (weights[0]) {}
// PGOUSE: switch {{.*}} [
// PGOUSE: ], !prof ![[BS2:[0-9]+]]
switch (1 << i) {
- // PGOGEN: store {{.*}} @[[BSC]], i64 0, i64 5
+ // PGOGEN: store {{.*}} @[[BSC]], i64 0, i64 3
case (1 << 0):
- // PGOGEN: store {{.*}} @[[BSC]], i64 0, i64 6
+ // PGOGEN: store {{.*}} @[[BSC]], i64 0, i64 4
// PGOUSE: br {{.*}} !prof ![[BS3:[0-9]+]]
if (i) {}
// fallthrough
- // PGOGEN: store {{.*}} @[[BSC]], i64 0, i64 7
+ // PGOGEN: store {{.*}} @[[BSC]], i64 0, i64 5
case (1 << 1):
- // PGOGEN: store {{.*}} @[[BSC]], i64 0, i64 8
+ // PGOGEN: store {{.*}} @[[BSC]], i64 0, i64 6
// PGOUSE: br {{.*}} !prof ![[BS4:[0-9]+]]
if (i) {}
break;
- // PGOGEN: store {{.*}} @[[BSC]], i64 0, i64 9
+ // PGOGEN: store {{.*}} @[[BSC]], i64 0, i64 7
case (1 << 2) ... (1 << 12):
- // PGOGEN: store {{.*}} @[[BSC]], i64 0, i64 10
+ // PGOGEN: store {{.*}} @[[BSC]], i64 0, i64 8
// PGOUSE: br {{.*}} !prof ![[BS5:[0-9]+]]
if (i) {}
break;
// The branch for the large case range above appears after the case body
// PGOUSE: br {{.*}} !prof ![[BS6:[0-9]+]]
- // PGOGEN: store {{.*}} @[[BSC]], i64 0, i64 11
+ // PGOGEN: store {{.*}} @[[BSC]], i64 0, i64 9
case (1 << 13):
- // PGOGEN: store {{.*}} @[[BSC]], i64 0, i64 12
+ // PGOGEN: store {{.*}} @[[BSC]], i64 0, i64 10
// PGOUSE: br {{.*}} !prof ![[BS7:[0-9]+]]
if (i) {}
break;
- // PGOGEN: store {{.*}} @[[BSC]], i64 0, i64 13
+ // PGOGEN: store {{.*}} @[[BSC]], i64 0, i64 11
case (1 << 14) ... (1 << 28):
- // PGOGEN: store {{.*}} @[[BSC]], i64 0, i64 14
+ // PGOGEN: store {{.*}} @[[BSC]], i64 0, i64 12
// PGOUSE: br {{.*}} !prof ![[BS8:[0-9]+]]
if (i) {}
break;
// The branch for the large case range above appears after the case body
// PGOUSE: br {{.*}} !prof ![[BS9:[0-9]+]]
- // PGOGEN: store {{.*}} @[[BSC]], i64 0, i64 15
+ // PGOGEN: store {{.*}} @[[BSC]], i64 0, i64 13
case (1 << 29) ... ((1 << 29) + 1):
- // PGOGEN: store {{.*}} @[[BSC]], i64 0, i64 16
+ // PGOGEN: store {{.*}} @[[BSC]], i64 0, i64 14
// PGOUSE: br {{.*}} !prof ![[BS10:[0-9]+]]
if (i) {}
break;
- // PGOGEN: store {{.*}} @[[BSC]], i64 0, i64 17
+ // PGOGEN: store {{.*}} @[[BSC]], i64 0, i64 15
default:
- // PGOGEN: store {{.*}} @[[BSC]], i64 0, i64 18
+ // PGOGEN: store {{.*}} @[[BSC]], i64 0, i64 16
// PGOUSE: br {{.*}} !prof ![[BS11:[0-9]+]]
if (i) {}
break;
}
- // PGOGEN: store {{.*}} @[[BSC]], i64 0, i64 4
+ // PGOGEN: store {{.*}} @[[BSC]], i64 0, i64 2
}
// PGOGEN-NOT: store {{.*}} @[[BSC]],
// PGOGEN: store {{.*}} @[[BOC]], i64 0, i64 1
// PGOUSE: br {{.*}} !prof ![[BO1:[0-9]+]]
for (int i = 0; i < 100; ++i) {
- // PGOGEN: store {{.*}} @[[BOC]], i64 0, i64 4
+ // PGOGEN: store {{.*}} @[[BOC]], i64 0, i64 2
// PGOUSE: br {{.*}} !prof ![[BO2:[0-9]+]]
v = i % 3 || i;
- // PGOGEN: store {{.*}} @[[BOC]], i64 0, i64 5
+ // PGOGEN: store {{.*}} @[[BOC]], i64 0, i64 3
// PGOUSE: br {{.*}} !prof ![[BO3:[0-9]+]]
v = i % 3 && i;
- // PGOGEN: store {{.*}} @[[BOC]], i64 0, i64 7
- // PGOGEN: store {{.*}} @[[BOC]], i64 0, i64 6
+ // PGOGEN: store {{.*}} @[[BOC]], i64 0, i64 5
+ // PGOGEN: store {{.*}} @[[BOC]], i64 0, i64 4
// PGOUSE: br {{.*}} !prof ![[BO4:[0-9]+]]
// PGOUSE: br {{.*}} !prof ![[BO5:[0-9]+]]
v = i % 3 || i % 2 || i;
- // PGOGEN: store {{.*}} @[[BOC]], i64 0, i64 9
- // PGOGEN: store {{.*}} @[[BOC]], i64 0, i64 8
+ // PGOGEN: store {{.*}} @[[BOC]], i64 0, i64 7
+ // PGOGEN: store {{.*}} @[[BOC]], i64 0, i64 6
// PGOUSE: br {{.*}} !prof ![[BO6:[0-9]+]]
// PGOUSE: br {{.*}} !prof ![[BO7:[0-9]+]]
v = i % 2 && i % 3 && i;
}
- // PGOGEN-NOT: store {{.*}} @[BOC]],
+ // PGOGEN-NOT: store {{.*}} @[[BOC]],
+ // PGOUSE-NOT: br {{.*}} !prof ![0-9]+
+}
+
+// PGOGEN-LABEL: @boolop_loops()
+// PGOUSE-LABEL: @boolop_loops()
+// PGOGEN: store {{.*}} @[[BLC]], i64 0, i64 0
+void boolop_loops() {
+ int i = 100;
+
+ // PGOGEN: store {{.*}} @[[BLC]], i64 0, i64 2
+ // PGOGEN: store {{.*}} @[[BLC]], i64 0, i64 1
+ // PGOUSE: br {{.*}} !prof ![[BL1:[0-9]+]]
+ // PGOUSE: br {{.*}} !prof ![[BL2:[0-9]+]]
+ while (i && i > 50)
+ i--;
+
+ // PGOGEN: store {{.*}} @[[BLC]], i64 0, i64 4
+ // PGOGEN: store {{.*}} @[[BLC]], i64 0, i64 3
+ // PGOUSE: br {{.*}} !prof ![[BL3:[0-9]+]]
+ // PGOUSE: br {{.*}} !prof ![[BL4:[0-9]+]]
+ while ((i % 2) || (i > 0))
+ i--;
+
+ // PGOGEN: store {{.*}} @[[BLC]], i64 0, i64 6
+ // PGOGEN: store {{.*}} @[[BLC]], i64 0, i64 5
+ // PGOUSE: br {{.*}} !prof ![[BL5:[0-9]+]]
+ // PGOUSE: br {{.*}} !prof ![[BL6:[0-9]+]]
+ for (i = 100; i && i > 50; --i);
+
+ // PGOGEN: store {{.*}} @[[BLC]], i64 0, i64 8
+ // PGOGEN: store {{.*}} @[[BLC]], i64 0, i64 7
+ // PGOUSE: br {{.*}} !prof ![[BL7:[0-9]+]]
+ // PGOUSE: br {{.*}} !prof ![[BL8:[0-9]+]]
+ for (; (i % 2) || (i > 0); --i);
+
+ // PGOGEN-NOT: store {{.*}} @[[BLC]],
// PGOUSE-NOT: br {{.*}} !prof ![0-9]+
}
// PGOUSE-DAG: ![[BO5]] = metadata !{metadata !"branch_weights", i32 18, i32 18}
// PGOUSE-DAG: ![[BO6]] = metadata !{metadata !"branch_weights", i32 51, i32 51}
// PGOUSE-DAG: ![[BO7]] = metadata !{metadata !"branch_weights", i32 34, i32 18}
-
+// PGOUSE-DAG: ![[BL1]] = metadata !{metadata !"branch_weights", i32 52, i32 1}
+// PGOUSE-DAG: ![[BL2]] = metadata !{metadata !"branch_weights", i32 51, i32 2}
+// PGOUSE-DAG: ![[BL3]] = metadata !{metadata !"branch_weights", i32 26, i32 27}
+// PGOUSE-DAG: ![[BL4]] = metadata !{metadata !"branch_weights", i32 51, i32 2}
+// PGOUSE-DAG: ![[BL5]] = metadata !{metadata !"branch_weights", i32 52, i32 1}
+// PGOUSE-DAG: ![[BL6]] = metadata !{metadata !"branch_weights", i32 51, i32 2}
+// PGOUSE-DAG: ![[BL7]] = metadata !{metadata !"branch_weights", i32 26, i32 27}
+// PGOUSE-DAG: ![[BL8]] = metadata !{metadata !"branch_weights", i32 51, i32 2}
int main(int argc, const char *argv[]) {
simple_loops();
switches();
big_switch();
boolean_operators();
+ boolop_loops();
no_usable_data();
return 0;
}
-_Z6throwsv 11
+_Z6throwsv 9
1
100
-0
-0
100
66
33
// RUN: %clang %s -o - -emit-llvm -S -fprofile-instr-use=%S/Inputs/instr-profile-throws.pgodata -target %itanium_abi_triple | FileCheck -check-prefix=PGOUSE %s
// RUN: %clang %s -o - -emit-llvm -S -fprofile-instr-use=%S/Inputs/instr-profile-throws.pgodata -target %itanium_abi_triple | FileCheck -check-prefix=PGOUSE-EXC %s
-// PGOGEN: @[[THC:__llvm_pgo_ctr[0-9]*]] = private global [11 x i64] zeroinitializer
-// PGOGEN-EXC: @[[THC:__llvm_pgo_ctr[0-9]*]] = private global [11 x i64] zeroinitializer
+// PGOGEN: @[[THC:__llvm_pgo_ctr[0-9]*]] = private global [9 x i64] zeroinitializer
+// PGOGEN-EXC: @[[THC:__llvm_pgo_ctr[0-9]*]] = private global [9 x i64] zeroinitializer
// PGOGEN-LABEL: @_Z6throwsv()
// PGOUSE-LABEL: @_Z6throwsv()
// PGOUSE: br {{.*}} !prof ![[TH1:[0-9]+]]
for (int i = 0; i < 100; ++i) {
try {
- // PGOGEN: store {{.*}} @[[THC]], i64 0, i64 5
+ // PGOGEN: store {{.*}} @[[THC]], i64 0, i64 3
// PGOUSE: br {{.*}} !prof ![[TH2:[0-9]+]]
if (i % 3) {
- // PGOGEN: store {{.*}} @[[THC]], i64 0, i64 6
+ // PGOGEN: store {{.*}} @[[THC]], i64 0, i64 4
// PGOUSE: br {{.*}} !prof ![[TH3:[0-9]+]]
if (i < 50)
throw 1;
// PGOUSE: if.else{{.*}}:
// PGOGEN: if.else{{.*}}:
- // PGOGEN: store {{.*}} @[[THC]], i64 0, i64 7
+ // PGOGEN: store {{.*}} @[[THC]], i64 0, i64 5
// PGOUSE: br {{.*}} !prof ![[TH4:[0-9]+]]
if (i >= 50)
throw 0;
// PGOUSE-EXC: catch{{.*}}:
// PGOGEN-EXC: catch{{.*}}:
- // PGOGEN-EXC: store {{.*}} @[[THC]], i64 0, i64 8
- // PGOGEN-EXC: store {{.*}} @[[THC]], i64 0, i64 9
+ // PGOGEN-EXC: store {{.*}} @[[THC]], i64 0, i64 6
+ // PGOGEN-EXC: store {{.*}} @[[THC]], i64 0, i64 7
// PGOUSE-EXC: br {{.*}} !prof ![[TH5:[0-9]+]]
if (e) {}
}
- // PGOGEN: store {{.*}} @[[THC]], i64 0, i64 4
+ // PGOGEN: store {{.*}} @[[THC]], i64 0, i64 2
- // PGOGEN: store {{.*}} @[[THC]], i64 0, i64 10
+ // PGOGEN: store {{.*}} @[[THC]], i64 0, i64 8
// PGOUSE: br {{.*}} !prof ![[TH6:[0-9]+]]
if (i < 100) {}
}