Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/llvm/llvm-project.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--clang/lib/CodeGen/CGStmt.cpp33
-rw-r--r--clang/lib/CodeGen/CodeGenModule.cpp1
-rw-r--r--clang/lib/CodeGen/CodeGenPGO.cpp112
-rw-r--r--clang/lib/CodeGen/CodeGenPGO.h2
-rw-r--r--clang/lib/CodeGen/CoverageMappingGen.cpp112
-rw-r--r--clang/test/CoverageMapping/boolean-counters.cpp112
-rw-r--r--llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h9
-rw-r--r--llvm/lib/ProfileData/Coverage/CoverageMapping.cpp16
-rw-r--r--llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp3
9 files changed, 357 insertions, 43 deletions
diff --git a/clang/lib/CodeGen/CGStmt.cpp b/clang/lib/CodeGen/CGStmt.cpp
index 05ab16668743..ea91807d8495 100644
--- a/clang/lib/CodeGen/CGStmt.cpp
+++ b/clang/lib/CodeGen/CGStmt.cpp
@@ -40,6 +40,10 @@ using namespace CodeGen;
// Statement Emission
//===----------------------------------------------------------------------===//
+namespace llvm {
+extern cl::opt<bool> EnableBooleanCounters;
+}
+
void CodeGenFunction::EmitStopPoint(const Stmt *S) {
if (CGDebugInfo *DI = getDebugInfo()) {
SourceLocation Loc;
@@ -823,7 +827,10 @@ void CodeGenFunction::EmitIfStmt(const IfStmt &S) {
// Emit the 'then' code.
EmitBlock(ThenBlock);
- incrementProfileCounter(&S);
+ if (llvm::EnableBooleanCounters)
+ incrementProfileCounter(S.getThen());
+ else
+ incrementProfileCounter(&S);
{
RunCleanupsScope ThenScope(*this);
EmitStmt(S.getThen());
@@ -837,6 +844,9 @@ void CodeGenFunction::EmitIfStmt(const IfStmt &S) {
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);
@@ -850,6 +860,9 @@ void CodeGenFunction::EmitIfStmt(const IfStmt &S) {
// 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,
@@ -926,7 +939,10 @@ void CodeGenFunction::EmitWhileStmt(const WhileStmt &S,
{
RunCleanupsScope BodyScope(*this);
EmitBlock(LoopBody);
- incrementProfileCounter(&S);
+ if (llvm::EnableBooleanCounters)
+ incrementProfileCounter(S.getBody());
+ else
+ incrementProfileCounter(&S);
EmitStmt(S.getBody());
}
@@ -948,6 +964,10 @@ void CodeGenFunction::EmitWhileStmt(const WhileStmt &S,
// 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,
@@ -1098,8 +1118,11 @@ void CodeGenFunction::EmitForStmt(const ForStmt &S,
// 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.
@@ -1126,6 +1149,10 @@ void CodeGenFunction::EmitForStmt(const ForStmt &S,
// 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
index 579ebba7736d..58a5448315b3 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -567,6 +567,7 @@ void CodeGenModule::Release() {
checkAliases();
EmitDeferredUnusedCoverageMappings();
CodeGenPGO(*this).setValueProfilingFlag(getModule());
+ CodeGenPGO(*this).setProfileVersion(getModule());
if (CoverageMapping)
CoverageMapping->emit();
if (CodeGenOpts.SanitizeCfiCrossDso) {
diff --git a/clang/lib/CodeGen/CodeGenPGO.cpp b/clang/lib/CodeGen/CodeGenPGO.cpp
index 587bcef78ee5..dae3a0570220 100644
--- 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<bool> 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<bool>
EnableValueProfiling("enable-value-profiling",
llvm::cl::desc("Enable value profiling"),
@@ -234,20 +242,75 @@ struct MapRegionCounters : public RecursiveASTVisitor<MapRegionCounters> {
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 @@ struct MapRegionCounters : public RecursiveASTVisitor<MapRegionCounters> {
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 @@ void CodeGenPGO::emitCounterIncrement(CGBuilderTy &Builder, const Stmt *S,
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 @@ void CodeGenPGO::setValueProfilingFlag(llvm::Module &M) {
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/CodeGenPGO.h b/clang/lib/CodeGen/CodeGenPGO.h
index f740692ac205..693004479a64 100644
--- a/clang/lib/CodeGen/CodeGenPGO.h
+++ b/clang/lib/CodeGen/CodeGenPGO.h
@@ -91,6 +91,8 @@ public:
// 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/CoverageMappingGen.cpp b/clang/lib/CodeGen/CoverageMappingGen.cpp
index 0fe084b628da..f47ab58096bb 100644
--- 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<bool> EnableBooleanCounters;
+}
+
static llvm::cl::opt<bool> EmptyLineCommentCoverage(
"emptyline-comment-coverage",
llvm::cl::desc("Emit emptylines and comment lines as skipped regions (only "
@@ -572,6 +576,15 @@ struct CounterCoverageMappingBuilder
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.
@@ -1053,8 +1066,12 @@ struct CounterCoverageMappingBuilder
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);
@@ -1062,8 +1079,12 @@ struct CounterCoverageMappingBuilder
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);
}
@@ -1081,7 +1102,9 @@ struct CounterCoverageMappingBuilder
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());
@@ -1094,7 +1117,10 @@ struct CounterCoverageMappingBuilder
// 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));
@@ -1104,7 +1130,11 @@ struct CounterCoverageMappingBuilder
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;
@@ -1113,8 +1143,9 @@ struct CounterCoverageMappingBuilder
}
// 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) {
@@ -1156,7 +1187,9 @@ struct CounterCoverageMappingBuilder
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())
@@ -1175,14 +1208,23 @@ struct CounterCoverageMappingBuilder
// 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));
@@ -1193,8 +1235,11 @@ struct CounterCoverageMappingBuilder
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;
@@ -1203,8 +1248,9 @@ struct CounterCoverageMappingBuilder
}
// 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) {
@@ -1319,6 +1365,11 @@ struct CounterCoverageMappingBuilder
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;
@@ -1380,7 +1431,9 @@ struct CounterCoverageMappingBuilder
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.
@@ -1394,7 +1447,13 @@ struct CounterCoverageMappingBuilder
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;
@@ -1404,12 +1463,16 @@ struct CounterCoverageMappingBuilder
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);
@@ -1417,8 +1480,9 @@ struct CounterCoverageMappingBuilder
}
// 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
index 000000000000..ed5c11f15964
--- /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
index e35751512245..a5e9876c7e1f 100644
--- a/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
+++ b/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
@@ -93,8 +93,8 @@ struct Counter {
/// 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 @@ public:
/// 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 @@ public:
/// 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<unsigned, unsigned>;
diff --git a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
index 8c1eadbe8271..e8c700327fdf 100644
--- a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
+++ b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
@@ -133,6 +133,14 @@ Counter CounterExpressionBuilder::subtract(Counter LHS, Counter RHS,
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:
@@ -147,7 +155,10 @@ void CounterMappingContext::dump(const Counter &C, raw_ostream &OS) const {
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;
@@ -181,6 +192,9 @@ Expected<int64_t> CounterMappingContext::evaluate(const Counter &C) const {
Expected<int64_t> 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
index 552140a52ad4..982a7a400d74 100644
--- a/llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp
+++ b/llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp
@@ -198,7 +198,8 @@ Error RawCoverageMappingReader::decodeCounter(unsigned Value, Counter &C) {
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<CoverageMapError>(coveragemap_error::malformed);