diff --git a/clang/lib/CodeGen/CGStmt.cpp b/clang/lib/CodeGen/CGStmt.cpp --- a/clang/lib/CodeGen/CGStmt.cpp +++ b/clang/lib/CodeGen/CGStmt.cpp @@ -40,6 +40,10 @@ // Statement Emission //===----------------------------------------------------------------------===// +namespace llvm { +extern cl::opt EnableBooleanCounters; +} + void CodeGenFunction::EmitStopPoint(const Stmt *S) { if (CGDebugInfo *DI = getDebugInfo()) { SourceLocation Loc; @@ -807,7 +811,10 @@ // Emit the 'then' code. EmitBlock(ThenBlock); - incrementProfileCounter(&S); + if (llvm::EnableBooleanCounters) + incrementProfileCounter(S.getThen()); + else + incrementProfileCounter(&S); { RunCleanupsScope ThenScope(*this); EmitStmt(S.getThen()); @@ -821,6 +828,9 @@ auto NL = ApplyDebugLocation::CreateEmpty(*this); EmitBlock(ElseBlock); } + // When boolean counters are enabled, add a counter to else block. + if (llvm::EnableBooleanCounters) + incrementProfileCounter(Else); { RunCleanupsScope ElseScope(*this); EmitStmt(Else); @@ -834,6 +844,9 @@ // Emit the continuation block for code after the if. EmitBlock(ContBlock, true); + // When there is no else, add a counter to continuation block. + if (llvm::EnableBooleanCounters && !S.getElse()) + incrementProfileCounter(&S); } void CodeGenFunction::EmitWhileStmt(const WhileStmt &S, @@ -910,7 +923,10 @@ { RunCleanupsScope BodyScope(*this); EmitBlock(LoopBody); - incrementProfileCounter(&S); + if (llvm::EnableBooleanCounters) + incrementProfileCounter(S.getBody()); + else + incrementProfileCounter(&S); EmitStmt(S.getBody()); } @@ -932,6 +948,10 @@ // a branch, try to erase it. if (!EmitBoolCondBranch) SimplifyForwardingBlocks(LoopHeader.getBlock()); + + // When boolean counters are enabled, add a counter to continuation block. + if (llvm::EnableBooleanCounters) + incrementProfileCounter(&S); } void CodeGenFunction::EmitDoStmt(const DoStmt &S, @@ -1082,8 +1102,11 @@ // Treat it as a non-zero constant. Don't even create a new block for the // body, just fall into it. } - incrementProfileCounter(&S); + if (llvm::EnableBooleanCounters) + incrementProfileCounter(S.getBody()); + else + incrementProfileCounter(&S); { // Create a separate cleanup scope for the body, in case it is not // a compound statement. @@ -1110,6 +1133,10 @@ // Emit the fall-through block. EmitBlock(LoopExit.getBlock(), true); + + // When boolean counters are enabled, add a counter to continuation block. + if (llvm::EnableBooleanCounters) + incrementProfileCounter(&S); } void diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -548,6 +548,7 @@ checkAliases(); EmitDeferredUnusedCoverageMappings(); CodeGenPGO(*this).setValueProfilingFlag(getModule()); + CodeGenPGO(*this).setProfileVersion(getModule()); if (CoverageMapping) CoverageMapping->emit(); if (CodeGenOpts.SanitizeCfiCrossDso) { diff --git a/clang/lib/CodeGen/CodeGenPGO.h b/clang/lib/CodeGen/CodeGenPGO.h --- a/clang/lib/CodeGen/CodeGenPGO.h +++ b/clang/lib/CodeGen/CodeGenPGO.h @@ -91,6 +91,8 @@ // Set a module flag indicating if value profiling is enabled. void setValueProfilingFlag(llvm::Module &M); + void setProfileVersion(llvm::Module &M); + private: void setFuncName(llvm::Function *Fn); void setFuncName(StringRef Name, llvm::GlobalValue::LinkageTypes Linkage); diff --git a/clang/lib/CodeGen/CodeGenPGO.cpp b/clang/lib/CodeGen/CodeGenPGO.cpp --- a/clang/lib/CodeGen/CodeGenPGO.cpp +++ b/clang/lib/CodeGen/CodeGenPGO.cpp @@ -15,6 +15,7 @@ #include "CoverageMappingGen.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/StmtVisitor.h" +#include "llvm/IR/GlobalVariable.h" #include "llvm/IR/Intrinsics.h" #include "llvm/IR/MDBuilder.h" #include "llvm/Support/CommandLine.h" @@ -22,6 +23,13 @@ #include "llvm/Support/FileSystem.h" #include "llvm/Support/MD5.h" +namespace llvm { +cl::opt EnableBooleanCounters("enable-boolean-counters", + llvm::cl::ZeroOrMore, + llvm::cl::desc("Enable boolean counters"), + llvm::cl::Hidden, llvm::cl::init(false)); +} // namespace llvm + static llvm::cl::opt EnableValueProfiling("enable-value-profiling", llvm::cl::ZeroOrMore, llvm::cl::desc("Enable value profiling"), @@ -234,20 +242,75 @@ return Base::TraverseIfStmt(If); // Otherwise, keep track of which branch we're in while traversing. - VisitStmt(If); + // When boolean counters are enabled and if has an else part, + // do not add a counter for IfStmt, but still include in the function hash. + if (llvm::EnableBooleanCounters && If->getElse()) { + auto Type = getHashType(PGO_HASH_V1, If); + if (Hash.getHashVersion() != PGO_HASH_V1) + Type = getHashType(Hash.getHashVersion(), If); + if (Type != PGOHash::None) + Hash.combine(Type); + } else + VisitStmt(If); + for (Stmt *CS : If->children()) { if (!CS) continue; - if (CS == If->getThen()) + if (CS == If->getThen()) { Hash.combine(PGOHash::IfThenBranch); - else if (CS == If->getElse()) + if (llvm::EnableBooleanCounters) + CounterMap[If->getThen()] = NextCounter++; + } else if (CS == If->getElse()) { Hash.combine(PGOHash::IfElseBranch); + if (llvm::EnableBooleanCounters) + CounterMap[If->getElse()] = NextCounter++; + } TraverseStmt(CS); } Hash.combine(PGOHash::EndOfScope); return true; } + bool TraverseWhileStmt(WhileStmt *While) { + // If we used the V1 hash, use the default traversal. + if (Hash.getHashVersion() == PGO_HASH_V1) + return Base::TraverseWhileStmt(While); + + VisitStmt(While); + for (Stmt *CS : While->children()) { + if (!CS) + continue; + if (llvm::EnableBooleanCounters && CS == While->getBody()) + CounterMap[While->getBody()] = NextCounter++; + TraverseStmt(CS); + } + + if (Hash.getHashVersion() != PGO_HASH_V1) + Hash.combine(PGOHash::EndOfScope); + + return true; + } + + bool TraverseForStmt(ForStmt *For) { + // If we used the V1 hash, use the default traversal. + if (Hash.getHashVersion() == PGO_HASH_V1) + return Base::TraverseForStmt(For); + VisitStmt(For); + for (Stmt *CS : For->children()) { + if (!CS) + continue; + if (CS == For->getBody()) { + if (llvm::EnableBooleanCounters) + CounterMap[For->getBody()] = NextCounter++; + } + TraverseStmt(CS); + } + + if (Hash.getHashVersion() != PGO_HASH_V1) + Hash.combine(PGOHash::EndOfScope); + return true; + } + // If the statement type \p N is nestable, and its nesting impacts profile // stability, define a custom traversal which tracks the end of the statement // in the hash (provided we're not using the V1 hash). @@ -259,9 +322,7 @@ return true; \ } - DEFINE_NESTABLE_TRAVERSAL(WhileStmt) DEFINE_NESTABLE_TRAVERSAL(DoStmt) - DEFINE_NESTABLE_TRAVERSAL(ForStmt) DEFINE_NESTABLE_TRAVERSAL(CXXForRangeStmt) DEFINE_NESTABLE_TRAVERSAL(ObjCForCollectionStmt) DEFINE_NESTABLE_TRAVERSAL(CXXTryStmt) @@ -961,13 +1022,19 @@ Builder.getInt64(FunctionHash), Builder.getInt32(NumRegionCounters), Builder.getInt32(Counter), StepV}; - if (!StepV) - Builder.CreateCall(CGM.getIntrinsic(llvm::Intrinsic::instrprof_increment), + + if (llvm::EnableBooleanCounters) + Builder.CreateCall(CGM.getIntrinsic(llvm::Intrinsic::instrprof_cover), makeArrayRef(Args, 4)); - else - Builder.CreateCall( - CGM.getIntrinsic(llvm::Intrinsic::instrprof_increment_step), - makeArrayRef(Args)); + else { + if (!StepV) + Builder.CreateCall(CGM.getIntrinsic(llvm::Intrinsic::instrprof_increment), + makeArrayRef(Args, 4)); + else + Builder.CreateCall( + CGM.getIntrinsic(llvm::Intrinsic::instrprof_increment_step), + makeArrayRef(Args)); + } } void CodeGenPGO::setValueProfilingFlag(llvm::Module &M) { @@ -976,6 +1043,29 @@ uint32_t(EnableValueProfiling)); } +void CodeGenPGO::setProfileVersion(llvm::Module &M) { + if (CGM.getCodeGenOpts().hasProfileClangInstr() && + llvm::EnableBooleanCounters) { + const StringRef VarName(INSTR_PROF_QUOTE(INSTR_PROF_RAW_VERSION_VAR)); + llvm::Type *IntTy64 = llvm::Type::getInt64Ty(M.getContext()); + uint64_t ProfileVersion = + (INSTR_PROF_RAW_VERSION | VARIANT_MASK_BYTE_COVERAGE); + + auto IRLevelVersionVariable = new llvm::GlobalVariable( + M, IntTy64, true, llvm::GlobalValue::WeakAnyLinkage, + llvm::Constant::getIntegerValue(IntTy64, + llvm::APInt(64, ProfileVersion)), + VarName); + + IRLevelVersionVariable->setVisibility(llvm::GlobalValue::DefaultVisibility); + llvm::Triple TT(M.getTargetTriple()); + if (TT.supportsCOMDAT()) { + IRLevelVersionVariable->setLinkage(llvm::GlobalValue::ExternalLinkage); + IRLevelVersionVariable->setComdat(M.getOrInsertComdat(VarName)); + } + } +} + // This method either inserts a call to the profile run-time during // instrumentation or puts profile data into metadata for PGO use. void CodeGenPGO::valueProfile(CGBuilderTy &Builder, uint32_t ValueKind, diff --git a/clang/lib/CodeGen/CoverageMappingGen.cpp b/clang/lib/CodeGen/CoverageMappingGen.cpp --- a/clang/lib/CodeGen/CoverageMappingGen.cpp +++ b/clang/lib/CodeGen/CoverageMappingGen.cpp @@ -31,6 +31,10 @@ // is textually included. #define COVMAP_V3 +namespace llvm { +extern cl::opt EnableBooleanCounters; +} + static llvm::cl::opt EmptyLineCommentCoverage( "emptyline-comment-coverage", llvm::cl::desc("Emit emptylines and comment lines as skipped regions (only " @@ -564,6 +568,15 @@ return addCounters(addCounters(C1, C2, Simplify), C3, Simplify); } + /// Return a counter for the result of \c LHS or \c RHS. + Counter orCounters(Counter LHS, Counter RHS) { + return Builder.orCounters(LHS, RHS); + } + + Counter orCounters(Counter C1, Counter C2, Counter C3) { + return orCounters(orCounters(C1, C2), C3); + } + /// Return the region counter for the given statement. /// /// This should only be called on statements that have a dedicated counter. @@ -1045,8 +1058,12 @@ void VisitBreakStmt(const BreakStmt *S) { assert(!BreakContinueStack.empty() && "break not in a loop or switch!"); - BreakContinueStack.back().BreakCount = addCounters( - BreakContinueStack.back().BreakCount, getRegion().getCounter()); + if (llvm::EnableBooleanCounters) + BreakContinueStack.back().BreakCount = orCounters( + BreakContinueStack.back().BreakCount, getRegion().getCounter()); + else + BreakContinueStack.back().BreakCount = addCounters( + BreakContinueStack.back().BreakCount, getRegion().getCounter()); // FIXME: a break in a switch should terminate regions for all preceding // case statements, not just the most recent one. terminateRegion(S); @@ -1054,8 +1071,12 @@ void VisitContinueStmt(const ContinueStmt *S) { assert(!BreakContinueStack.empty() && "continue stmt not in a loop!"); - BreakContinueStack.back().ContinueCount = addCounters( - BreakContinueStack.back().ContinueCount, getRegion().getCounter()); + if (llvm::EnableBooleanCounters) + BreakContinueStack.back().ContinueCount = orCounters( + BreakContinueStack.back().ContinueCount, getRegion().getCounter()); + else + BreakContinueStack.back().ContinueCount = addCounters( + BreakContinueStack.back().ContinueCount, getRegion().getCounter()); terminateRegion(S); } @@ -1073,7 +1094,9 @@ extendRegion(S); Counter ParentCount = getRegion().getCounter(); - Counter BodyCount = getRegionCounter(S); + Counter BodyCount = llvm::EnableBooleanCounters + ? getRegionCounter(S->getBody()) + : getRegionCounter(S); // Handle the body first so that we can get the backedge count. BreakContinueStack.push_back(BreakContinue()); @@ -1086,7 +1109,10 @@ // Go back to handle the condition. Counter CondCount = - addCounters(ParentCount, BackedgeCount, BC.ContinueCount); + llvm::EnableBooleanCounters + ? orCounters(ParentCount, BackedgeCount, BC.ContinueCount) + : addCounters(ParentCount, BackedgeCount, BC.ContinueCount); + propagateCounts(CondCount, S->getCond()); adjustForOutOfOrderTraversal(getEnd(S)); @@ -1096,7 +1122,11 @@ fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), BodyCount); Counter OutCount = - addCounters(BC.BreakCount, subtractCounters(CondCount, BodyCount)); + llvm::EnableBooleanCounters + ? getRegionCounter(S) + : addCounters(BC.BreakCount, + subtractCounters(CondCount, BodyCount)); + if (OutCount != ParentCount) { pushRegion(OutCount); GapRegionCounter = OutCount; @@ -1105,8 +1135,9 @@ } // Create Branch Region around condition. - createBranchRegion(S->getCond(), BodyCount, - subtractCounters(CondCount, BodyCount)); + if (!llvm::EnableBooleanCounters) + createBranchRegion(S->getCond(), BodyCount, + subtractCounters(CondCount, BodyCount)); } void VisitDoStmt(const DoStmt *S) { @@ -1148,7 +1179,9 @@ Visit(S->getInit()); Counter ParentCount = getRegion().getCounter(); - Counter BodyCount = getRegionCounter(S); + Counter BodyCount = llvm::EnableBooleanCounters + ? getRegionCounter(S->getBody()) + : getRegionCounter(S); // The loop increment may contain a break or continue. if (S->getInc()) @@ -1167,14 +1200,23 @@ // the count for all the continue statements. BreakContinue IncrementBC; if (const Stmt *Inc = S->getInc()) { - propagateCounts(addCounters(BackedgeCount, BodyBC.ContinueCount), Inc); + if (llvm::EnableBooleanCounters) + propagateCounts(orCounters(BackedgeCount, BodyBC.ContinueCount), Inc); + else + propagateCounts(addCounters(BackedgeCount, BodyBC.ContinueCount), Inc); IncrementBC = BreakContinueStack.pop_back_val(); } // Go back to handle the condition. - Counter CondCount = addCounters( - addCounters(ParentCount, BackedgeCount, BodyBC.ContinueCount), - IncrementBC.ContinueCount); + Counter CondCount = + llvm::EnableBooleanCounters + ? orCounters( + orCounters(ParentCount, BackedgeCount, BodyBC.ContinueCount), + IncrementBC.ContinueCount) + : addCounters( + addCounters(ParentCount, BackedgeCount, BodyBC.ContinueCount), + IncrementBC.ContinueCount); + if (const Expr *Cond = S->getCond()) { propagateCounts(CondCount, Cond); adjustForOutOfOrderTraversal(getEnd(S)); @@ -1185,8 +1227,11 @@ if (Gap) fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), BodyCount); - Counter OutCount = addCounters(BodyBC.BreakCount, IncrementBC.BreakCount, - subtractCounters(CondCount, BodyCount)); + Counter OutCount = + llvm::EnableBooleanCounters + ? getRegionCounter(S) + : addCounters(BodyBC.BreakCount, IncrementBC.BreakCount, + subtractCounters(CondCount, BodyCount)); if (OutCount != ParentCount) { pushRegion(OutCount); GapRegionCounter = OutCount; @@ -1195,8 +1240,9 @@ } // Create Branch Region around condition. - createBranchRegion(S->getCond(), BodyCount, - subtractCounters(CondCount, BodyCount)); + if (!llvm::EnableBooleanCounters) + createBranchRegion(S->getCond(), BodyCount, + subtractCounters(CondCount, BodyCount)); } void VisitCXXForRangeStmt(const CXXForRangeStmt *S) { @@ -1311,6 +1357,11 @@ MostRecentLocation = getStart(S); handleFileExit(ExitLoc); + // Early return so do not create branch regions when boolean counters are + // enabled. + if (llvm::EnableBooleanCounters) + return; + // Create a Branch Region around each Case. Subtract the case's // counter from the Parent counter to track the "False" branch count. Counter CaseCountSum; @@ -1372,7 +1423,9 @@ extendRegion(S->getCond()); Counter ParentCount = getRegion().getCounter(); - Counter ThenCount = getRegionCounter(S); + Counter ThenCount = llvm::EnableBooleanCounters + ? getRegionCounter(S->getThen()) + : getRegionCounter(S); // Emitting a counter for the condition makes it easier to interpret the // counter for the body when looking at the coverage. @@ -1386,7 +1439,13 @@ extendRegion(S->getThen()); Counter OutCount = propagateCounts(ThenCount, S->getThen()); - Counter ElseCount = subtractCounters(ParentCount, ThenCount); + Counter ElseCount; + if (llvm::EnableBooleanCounters) { + if (S->getElse()) + ElseCount = getRegionCounter(S->getElse()); + } else + ElseCount = subtractCounters(ParentCount, ThenCount); + if (const Stmt *Else = S->getElse()) { bool ThenHasTerminateStmt = HasTerminateStmt; HasTerminateStmt = false; @@ -1396,12 +1455,16 @@ if (Gap) fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), ElseCount); extendRegion(Else); - OutCount = addCounters(OutCount, propagateCounts(ElseCount, Else)); + Counter ElseOutCount = propagateCounts(ElseCount, Else); + OutCount = llvm::EnableBooleanCounters + ? orCounters(OutCount, ElseOutCount) + : addCounters(OutCount, ElseOutCount); if (ThenHasTerminateStmt) HasTerminateStmt = true; } else - OutCount = addCounters(OutCount, ElseCount); + OutCount = llvm::EnableBooleanCounters ? getRegionCounter(S) + : addCounters(OutCount, ElseCount); if (OutCount != ParentCount) { pushRegion(OutCount); @@ -1409,8 +1472,9 @@ } // Create Branch Region around condition. - createBranchRegion(S->getCond(), ThenCount, - subtractCounters(ParentCount, ThenCount)); + if (!llvm::EnableBooleanCounters) + createBranchRegion(S->getCond(), ThenCount, + subtractCounters(ParentCount, ThenCount)); } void VisitCXXTryStmt(const CXXTryStmt *S) { diff --git a/clang/test/CoverageMapping/boolean-counters.cpp b/clang/test/CoverageMapping/boolean-counters.cpp new file mode 100644 --- /dev/null +++ b/clang/test/CoverageMapping/boolean-counters.cpp @@ -0,0 +1,112 @@ +// RUN: %clang_cc1 -mllvm -emptyline-comment-coverage=false -mllvm -enable-boolean-counters=true -fprofile-instrument=clang -fcoverage-mapping -dump-coverage-mapping -emit-llvm-only -main-file-name return.c %s | FileCheck %s + +// CHECK: _Z6testIfi +int testIf(int x) { // CHECK-NEXT: File 0, [[@LINE]]:19 -> [[@LINE+10]]:2 = #0 + // CHECK-NEXT: File 0, [[@LINE+5]]:7 -> [[@LINE+5]]:13 = #0 + // CHECK-NEXT: Gap,File 0, [[@LINE+4]]:14 -> [[@LINE+5]]:5 = #2 + // CHECK-NEXT: File 0, [[@LINE+4]]:5 -> [[@LINE+4]]:16 = #2 + // CHECK-NEXT: File 0, [[@LINE+5]]:3 -> [[@LINE+5]]:16 = #1 + int result = 0; + if (x == 0) + result = -1; + + return result; +} + +// CHECK-NEXT: _Z10testIfElsei +int testIfElse(int x) { // CHECK-NEXT: File 0, [[@LINE]]:23 -> [[@LINE+13]]:2 = #0 + // CHECK-NEXT: File 0, [[@LINE+7]]:7 -> [[@LINE+7]]:12 = #0 + // CHECK-NEXT: Gap,File 0, [[@LINE+6]]:13 -> [[@LINE+7]]:5 = #1 + // CHECK-NEXT: File 0, [[@LINE+6]]:5 -> [[@LINE+6]]:15 = #1 + // CHECK-NEXT: Gap,File 0, [[@LINE+5]]:16 -> [[@LINE+7]]:5 = #2 + // CHECK-NEXT: File 0, [[@LINE+6]]:5 -> [[@LINE+6]]:19 = #2 + // CHECK-NEXT: File 0, [[@LINE+6]]:3 -> [[@LINE+6]]:16 = (#1 || #2) + int result = 0; + if (x < 0) + result = 0; + else + result = x * x; + return result; +} + +// CHECK-NEXT: _Z16testIfElseReturni +int testIfElseReturn(int x) { // CHECK-NEXT: File 0, [[@LINE]]:29 -> [[@LINE+14]]:2 = #0 + // CHECK-NEXT: File 0, [[@LINE+8]]:7 -> [[@LINE+8]]:12 = #0 + // CHECK-NEXT: Gap,File 0, [[@LINE+7]]:13 -> [[@LINE+8]]:5 = #1 + // CHECK-NEXT: File 0, [[@LINE+7]]:5 -> [[@LINE+7]]:19 = #1 + // CHECK-NEXT: Gap,File 0, [[@LINE+6]]:20 -> [[@LINE+8]]:5 = #2 + // CHECK-NEXT: File 0, [[@LINE+7]]:5 -> [[@LINE+7]]:13 = #2 + // CHECK-NEXT: Gap,File 0, [[@LINE+6]]:14 -> [[@LINE+7]]:3 = #1 + // CHECK-NEXT: File 0, [[@LINE+6]]:3 -> [[@LINE+6]]:16 = #1 + int result = 0; + if (x > 0) + result = x * x; + else + return 0; + return result; +} + +// CHECK-NEXT: _Z10testSwitchi +int testSwitch(int x) { // CHECK-NEXT: File 0, [[@LINE]]:23 -> [[@LINE+22]]:2 = #0 + // CHECK-NEXT: Gap,File 0, [[@LINE+9]]:14 -> [[@LINE+17]]:15 = 0 + // CHECK-NEXT: File 0, [[@LINE+9]]:3 -> [[@LINE+11]]:10 = #2 + // CHECK-NEXT: Gap,File 0, [[@LINE+10]]:11 -> [[@LINE+11]]:3 = 0 + // CHECK-NEXT: File 0, [[@LINE+10]]:3 -> [[@LINE+12]]:10 = #3 + // CHECK-NEXT: Gap,File 0, [[@LINE+11]]:11 -> [[@LINE+12]]:3 = 0 + // CHECK-NEXT: File 0, [[@LINE+11]]:3 -> [[@LINE+12]]:15 = #4 + // CHECK-NEXT: Gap,File 0, [[@LINE+12]]:4 -> [[@LINE+14]]:3 = #1 + // CHECK-NEXT: File 0, [[@LINE+13]]:3 -> [[@LINE+13]]:16 = #1 + int result; + switch (x) { + case 1: + result = 1; + break; + case 2: + result = 2; + break; + default: + result = 0; + } + + return result; +} + +// CHECK-NEXT: _Z9testWhilei +int testWhile(int x) { // CHECK-NEXT: File 0, [[@LINE]]:22 -> [[@LINE+13]]:2 = #0 + // CHECK-NEXT: File 0, [[@LINE+6]]:10 -> [[@LINE+6]]:16 = #0 + // CHECK-NEXT: Gap,File 0, [[@LINE+5]]:17 -> [[@LINE+5]]:18 = #2 + // CHECK-NEXT: File 0, [[@LINE+4]]:18 -> [[@LINE+7]]:4 = #2 + // CHECK-NEXT: File 0, [[@LINE+8]]:3 -> [[@LINE+8]]:13 = #1 + int i = x; + int sum = 0; + while (i < 10) { + sum += i; + i++; + } + + return sum; +} + +// CHECK-NEXT: _Z12testContinuei +int testContinue(int x) { // CHECK-NEXT: File 0, [[@LINE]]:25 -> [[@LINE+21]]:2 = #0 + // CHECK-NEXT: File 0, [[@LINE+12]]:10 -> [[@LINE+12]]:16 = ((#0 || #3) || #4) + // CHECK-NEXT: Gap,File 0, [[@LINE+11]]:17 -> [[@LINE+11]]:18 = #2 + // CHECK-NEXT: File 0, [[@LINE+10]]:18 -> [[@LINE+15]]:4 = #2 + // CHECK-NEXT: File 0, [[@LINE+10]]:9 -> [[@LINE+10]]:15 = #2 + // CHECK-NEXT: Gap,File 0, [[@LINE+9]]:16 -> [[@LINE+10]]:7 = #4 + // CHECK-NEXT: File 0, [[@LINE+9]]:7 -> [[@LINE+9]]:15 = #4 + // CHECK-NEXT: Gap,File 0, [[@LINE+8]]:16 -> [[@LINE+9]]:5 = #3 + // CHECK-NEXT: File 0, [[@LINE+8]]:5 -> [[@LINE+10]]:4 = #3 + // CHECK-NEXT: Gap,File 0, [[@LINE+9]]:4 -> [[@LINE+11]]:3 = #1 + // CHECK-NEXT: File 0, [[@LINE+10]]:3 -> [[@LINE+10]]:13 = #1 + int i = x; + int sum = 0; + while (i < 10) { + if (i == 4) + continue; + sum += i; + i++; + } + + return sum; +} diff --git a/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h b/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h --- a/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h +++ b/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h @@ -93,8 +93,8 @@ /// The CounterExpression kind (Add or Subtract) is encoded in bit 0 next to /// the CounterKind. This means CounterKind has to leave bit 0 free. enum CounterKind { Zero, CounterValueReference, Expression }; - static const unsigned EncodingTagBits = 2; - static const unsigned EncodingTagMask = 0x3; + static const unsigned EncodingTagBits = 3; + static const unsigned EncodingTagMask = 0x7; static const unsigned EncodingCounterTagAndExpansionRegionTagBits = EncodingTagBits + 1; @@ -147,7 +147,7 @@ /// A Counter expression is a value that represents an arithmetic operation /// with two counters. struct CounterExpression { - enum ExprKind { Subtract, Add }; + enum ExprKind { Subtract, Add, Or }; ExprKind Kind; Counter LHS, RHS; @@ -200,6 +200,9 @@ /// Return a counter that represents the expression that subtracts RHS from /// LHS. Counter subtract(Counter LHS, Counter RHS, bool Simplify = true); + + /// Return a counter that represents the expression RHS || LHS + Counter orCounters(Counter LHS, Counter RHS); }; using LineColPair = std::pair; diff --git a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp --- a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp +++ b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp @@ -134,6 +134,14 @@ return Simplify ? simplify(Cnt) : Cnt; } +Counter CounterExpressionBuilder::orCounters(Counter LHS, Counter RHS) { + if (LHS.getKind() == Counter::Zero) + return Counter::getCounter(RHS.getCounterID()); + if (RHS.getKind() == Counter::Zero) + return Counter::getCounter(LHS.getCounterID()); + return get(CounterExpression(CounterExpression::Or, LHS, RHS)); +} + void CounterMappingContext::dump(const Counter &C, raw_ostream &OS) const { switch (C.getKind()) { case Counter::Zero: @@ -148,7 +156,10 @@ const auto &E = Expressions[C.getExpressionID()]; OS << '('; dump(E.LHS, OS); - OS << (E.Kind == CounterExpression::Subtract ? " - " : " + "); + if (E.Kind == CounterExpression::Or) + OS << " || "; + else + OS << (E.Kind == CounterExpression::Subtract ? " - " : " + "); dump(E.RHS, OS); OS << ')'; break; @@ -182,6 +193,9 @@ Expected RHS = evaluate(E.RHS); if (!RHS) return RHS; + if (E.Kind == CounterExpression::Or) + return *RHS || *LHS; + return E.Kind == CounterExpression::Subtract ? *LHS - *RHS : *LHS + *RHS; } } diff --git a/llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp b/llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp --- a/llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp +++ b/llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp @@ -197,7 +197,8 @@ Tag -= Counter::Expression; switch (Tag) { case CounterExpression::Subtract: - case CounterExpression::Add: { + case CounterExpression::Add: + case CounterExpression::Or: { auto ID = Value >> Counter::EncodingTagBits; if (ID >= Expressions.size()) return make_error(coveragemap_error::malformed);