https://github.com/gulfemsavrun updated https://github.com/llvm/llvm-project/pull/75425
>From ee88c6e666759c27587f900c99a4aba23c0d4cf4 Mon Sep 17 00:00:00 2001 From: Gulfem Savrun Yeniceri <gul...@google.com> Date: Thu, 14 Dec 2023 03:40:57 +0000 Subject: [PATCH] [InstrProf] Single byte counters in coverage This patch inserts 1-byte counters instead of an 8-byte counters into llvm profiles for source-based code coverage. The origial idea was proposed as block-cov for PGO, and this patch repurposes that idea for coverage. The current 8-byte counters mechanism add counters to minimal regions, and infer the counters in the remaining regions via adding or subtracting counters. For example, it infers the counter in the if.else region by subtracting the counters between if.entry and if.then regions in an if statement. Whenever there is a control-flow merge, it adds the counters from all the incoming regions. However, we are not going to be able to infer counters by subtracting two execution counts when using single-byte counters. Therefore, this patch conservatively inserts additional counters for the cases where we need to add or subtract counters. RFC: https://discourse.llvm.org/t/rfc-single-byte-counters-for-source-based-code-coverage/75685 --- clang/lib/CodeGen/CGExprAgg.cpp | 13 +- clang/lib/CodeGen/CGExprComplex.cpp | 14 +- clang/lib/CodeGen/CGExprScalar.cpp | 32 ++- clang/lib/CodeGen/CGStmt.cpp | 73 ++++++- clang/lib/CodeGen/CodeGenFunction.cpp | 9 +- clang/lib/CodeGen/CodeGenFunction.h | 2 +- clang/lib/CodeGen/CodeGenModule.cpp | 1 + clang/lib/CodeGen/CodeGenPGO.cpp | 150 ++++++++++++- clang/lib/CodeGen/CodeGenPGO.h | 6 +- clang/lib/CodeGen/CoverageMappingGen.cpp | 206 +++++++++++++----- .../CoverageMapping/single-byte-counters.cpp | 169 ++++++++++++++ compiler-rt/lib/profile/InstrProfiling.h | 3 +- .../ProfileData/Coverage/CoverageMapping.h | 20 +- .../llvm/ProfileData/InstrProfWriter.h | 4 + .../ProfileData/Coverage/CoverageMapping.cpp | 13 +- 15 files changed, 623 insertions(+), 92 deletions(-) create mode 100644 clang/test/CoverageMapping/single-byte-counters.cpp diff --git a/clang/lib/CodeGen/CGExprAgg.cpp b/clang/lib/CodeGen/CGExprAgg.cpp index 22f55fe9aac904..377bf413c857cb 100644 --- a/clang/lib/CodeGen/CGExprAgg.cpp +++ b/clang/lib/CodeGen/CGExprAgg.cpp @@ -33,6 +33,10 @@ using namespace CodeGen; // Aggregate Expression Emitter //===----------------------------------------------------------------------===// +namespace llvm { +extern cl::opt<bool> EnableSingleByteCoverage; +} // namespace llvm + namespace { class AggExprEmitter : public StmtVisitor<AggExprEmitter> { CodeGenFunction &CGF; @@ -1278,7 +1282,10 @@ VisitAbstractConditionalOperator(const AbstractConditionalOperator *E) { eval.begin(CGF); CGF.EmitBlock(LHSBlock); - CGF.incrementProfileCounter(E); + if (llvm::EnableSingleByteCoverage) + CGF.incrementProfileCounter(E->getTrueExpr()); + else + CGF.incrementProfileCounter(E); Visit(E->getTrueExpr()); eval.end(CGF); @@ -1293,6 +1300,8 @@ VisitAbstractConditionalOperator(const AbstractConditionalOperator *E) { eval.begin(CGF); CGF.EmitBlock(RHSBlock); + if (llvm::EnableSingleByteCoverage) + CGF.incrementProfileCounter(E->getFalseExpr()); Visit(E->getFalseExpr()); eval.end(CGF); @@ -1301,6 +1310,8 @@ VisitAbstractConditionalOperator(const AbstractConditionalOperator *E) { E->getType()); CGF.EmitBlock(ContBlock); + if (llvm::EnableSingleByteCoverage) + CGF.incrementProfileCounter(E); } void AggExprEmitter::VisitChooseExpr(const ChooseExpr *CE) { diff --git a/clang/lib/CodeGen/CGExprComplex.cpp b/clang/lib/CodeGen/CGExprComplex.cpp index 9ddf0e763f139b..683097eea5e76a 100644 --- a/clang/lib/CodeGen/CGExprComplex.cpp +++ b/clang/lib/CodeGen/CGExprComplex.cpp @@ -28,6 +28,10 @@ using namespace CodeGen; // Complex Expression Emitter //===----------------------------------------------------------------------===// +namespace llvm { +extern cl::opt<bool> EnableSingleByteCoverage; +} // namespace llvm + typedef CodeGenFunction::ComplexPairTy ComplexPairTy; /// Return the complex type that we are meant to emit. @@ -1329,7 +1333,11 @@ VisitAbstractConditionalOperator(const AbstractConditionalOperator *E) { eval.begin(CGF); CGF.EmitBlock(LHSBlock); - CGF.incrementProfileCounter(E); + if (llvm::EnableSingleByteCoverage) + CGF.incrementProfileCounter(E->getTrueExpr()); + else + CGF.incrementProfileCounter(E); + ComplexPairTy LHS = Visit(E->getTrueExpr()); LHSBlock = Builder.GetInsertBlock(); CGF.EmitBranch(ContBlock); @@ -1337,9 +1345,13 @@ VisitAbstractConditionalOperator(const AbstractConditionalOperator *E) { eval.begin(CGF); CGF.EmitBlock(RHSBlock); + if (llvm::EnableSingleByteCoverage) + CGF.incrementProfileCounter(E->getFalseExpr()); ComplexPairTy RHS = Visit(E->getFalseExpr()); RHSBlock = Builder.GetInsertBlock(); CGF.EmitBlock(ContBlock); + if (llvm::EnableSingleByteCoverage) + CGF.incrementProfileCounter(E); eval.end(CGF); // Create a PHI node for the real part. diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp index df8f71cf1d9008..0c897c8d232c1c 100644 --- a/clang/lib/CodeGen/CGExprScalar.cpp +++ b/clang/lib/CodeGen/CGExprScalar.cpp @@ -52,6 +52,10 @@ using llvm::Value; // Scalar Expression Emitter //===----------------------------------------------------------------------===// +namespace llvm { +extern cl::opt<bool> EnableSingleByteCoverage; +} // namespace llvm + namespace { /// Determine whether the given binary operation may overflow. @@ -4866,8 +4870,13 @@ VisitAbstractConditionalOperator(const AbstractConditionalOperator *E) { // If the dead side doesn't have labels we need, just emit the Live part. if (!CGF.ContainsLabel(dead)) { - if (CondExprBool) + if (CondExprBool) { + if (llvm::EnableSingleByteCoverage) { + CGF.incrementProfileCounter(lhsExpr); + CGF.incrementProfileCounter(rhsExpr); + } CGF.incrementProfileCounter(E); + } Value *Result = Visit(live); // If the live part is a throw expression, it acts like it has a void @@ -4946,7 +4955,12 @@ VisitAbstractConditionalOperator(const AbstractConditionalOperator *E) { llvm::Value *CondV = CGF.EvaluateExprAsBool(condExpr); llvm::Value *StepV = Builder.CreateZExtOrBitCast(CondV, CGF.Int64Ty); - CGF.incrementProfileCounter(E, StepV); + if (llvm::EnableSingleByteCoverage) { + CGF.incrementProfileCounter(lhsExpr); + CGF.incrementProfileCounter(rhsExpr); + CGF.incrementProfileCounter(E); + } else + CGF.incrementProfileCounter(E, StepV); llvm::Value *LHS = Visit(lhsExpr); llvm::Value *RHS = Visit(rhsExpr); @@ -4978,7 +4992,11 @@ VisitAbstractConditionalOperator(const AbstractConditionalOperator *E) { if (CGF.MCDCLogOpStack.empty()) CGF.maybeUpdateMCDCTestVectorBitmap(condExpr); - CGF.incrementProfileCounter(E); + if (llvm::EnableSingleByteCoverage) + CGF.incrementProfileCounter(lhsExpr); + else + CGF.incrementProfileCounter(E); + eval.begin(CGF); Value *LHS = Visit(lhsExpr); eval.end(CGF); @@ -4994,6 +5012,9 @@ VisitAbstractConditionalOperator(const AbstractConditionalOperator *E) { if (CGF.MCDCLogOpStack.empty()) CGF.maybeUpdateMCDCTestVectorBitmap(condExpr); + if (llvm::EnableSingleByteCoverage) + CGF.incrementProfileCounter(rhsExpr); + eval.begin(CGF); Value *RHS = Visit(rhsExpr); eval.end(CGF); @@ -5012,6 +5033,11 @@ VisitAbstractConditionalOperator(const AbstractConditionalOperator *E) { PN->addIncoming(LHS, LHSBlock); PN->addIncoming(RHS, RHSBlock); + // When single byte coverage mode is enabled, add a counter to continuation + // block. + if (llvm::EnableSingleByteCoverage) + CGF.incrementProfileCounter(E); + return PN; } diff --git a/clang/lib/CodeGen/CGStmt.cpp b/clang/lib/CodeGen/CGStmt.cpp index beff0ad9da2709..c9f8acae11a1af 100644 --- a/clang/lib/CodeGen/CGStmt.cpp +++ b/clang/lib/CodeGen/CGStmt.cpp @@ -43,6 +43,10 @@ using namespace CodeGen; // Statement Emission //===----------------------------------------------------------------------===// +namespace llvm { +extern cl::opt<bool> EnableSingleByteCoverage; +} // namespace llvm + void CodeGenFunction::EmitStopPoint(const Stmt *S) { if (CGDebugInfo *DI = getDebugInfo()) { SourceLocation Loc; @@ -853,7 +857,10 @@ void CodeGenFunction::EmitIfStmt(const IfStmt &S) { // Emit the 'then' code. EmitBlock(ThenBlock); - incrementProfileCounter(&S); + if (llvm::EnableSingleByteCoverage) + incrementProfileCounter(S.getThen()); + else + incrementProfileCounter(&S); { RunCleanupsScope ThenScope(*this); EmitStmt(S.getThen()); @@ -867,6 +874,9 @@ void CodeGenFunction::EmitIfStmt(const IfStmt &S) { auto NL = ApplyDebugLocation::CreateEmpty(*this); EmitBlock(ElseBlock); } + // When single byte coverage mode is enabled, add a counter to else block. + if (llvm::EnableSingleByteCoverage) + incrementProfileCounter(Else); { RunCleanupsScope ElseScope(*this); EmitStmt(Else); @@ -880,6 +890,11 @@ void CodeGenFunction::EmitIfStmt(const IfStmt &S) { // Emit the continuation block for code after the if. EmitBlock(ContBlock, true); + + // When single byte coverage mode is enabled, add a counter to continuation + // block. + if (llvm::EnableSingleByteCoverage) + incrementProfileCounter(&S); } void CodeGenFunction::EmitWhileStmt(const WhileStmt &S, @@ -924,6 +939,10 @@ void CodeGenFunction::EmitWhileStmt(const WhileStmt &S, SourceLocToDebugLoc(R.getEnd()), checkIfLoopMustProgress(CondIsConstInt)); + // When single byte coverage mode is enabled, add a counter to loop condition. + if (llvm::EnableSingleByteCoverage) + incrementProfileCounter(S.getCond()); + // As long as the condition is true, go to the loop body. llvm::BasicBlock *LoopBody = createBasicBlock("while.body"); if (EmitBoolCondBranch) { @@ -956,7 +975,11 @@ void CodeGenFunction::EmitWhileStmt(const WhileStmt &S, { RunCleanupsScope BodyScope(*this); EmitBlock(LoopBody); - incrementProfileCounter(&S); + // When single byte coverage mode is enabled, add a counter to the body. + if (llvm::EnableSingleByteCoverage) + incrementProfileCounter(S.getBody()); + else + incrementProfileCounter(&S); EmitStmt(S.getBody()); } @@ -978,6 +1001,11 @@ void CodeGenFunction::EmitWhileStmt(const WhileStmt &S, // a branch, try to erase it. if (!EmitBoolCondBranch) SimplifyForwardingBlocks(LoopHeader.getBlock()); + + // When single byte coverage mode is enabled, add a counter to continuation + // block. + if (llvm::EnableSingleByteCoverage) + incrementProfileCounter(&S); } void CodeGenFunction::EmitDoStmt(const DoStmt &S, @@ -993,13 +1021,19 @@ void CodeGenFunction::EmitDoStmt(const DoStmt &S, // Emit the body of the loop. llvm::BasicBlock *LoopBody = createBasicBlock("do.body"); - EmitBlockWithFallThrough(LoopBody, &S); + if (llvm::EnableSingleByteCoverage) + EmitBlockWithFallThrough(LoopBody, S.getBody()); + else + EmitBlockWithFallThrough(LoopBody, &S); { RunCleanupsScope BodyScope(*this); EmitStmt(S.getBody()); } EmitBlock(LoopCond.getBlock()); + // When single byte coverage mode is enabled, add a counter to loop condition. + if (llvm::EnableSingleByteCoverage) + incrementProfileCounter(S.getCond()); // C99 6.8.5.2: "The evaluation of the controlling expression takes place // after each execution of the loop body." @@ -1040,6 +1074,11 @@ void CodeGenFunction::EmitDoStmt(const DoStmt &S, // emitting a branch, try to erase it. if (!EmitBoolCondBranch) SimplifyForwardingBlocks(LoopCond.getBlock()); + + // When single byte coverage mode is enabled, add a counter to continuation + // block. + if (llvm::EnableSingleByteCoverage) + incrementProfileCounter(&S); } void CodeGenFunction::EmitForStmt(const ForStmt &S, @@ -1098,6 +1137,11 @@ void CodeGenFunction::EmitForStmt(const ForStmt &S, BreakContinueStack.back().ContinueBlock = Continue; } + // When single byte coverage mode is enabled, add a counter to loop + // condition. + if (llvm::EnableSingleByteCoverage) + incrementProfileCounter(S.getCond()); + llvm::BasicBlock *ExitBlock = LoopExit.getBlock(); // If there are any cleanups between here and the loop-exit scope, // create a block to stage a loop exit along. @@ -1128,8 +1172,12 @@ 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); + // When single byte coverage mode is enabled, add a counter to the body. + if (llvm::EnableSingleByteCoverage) + incrementProfileCounter(S.getBody()); + else + incrementProfileCounter(&S); { // Create a separate cleanup scope for the body, in case it is not // a compound statement. @@ -1141,6 +1189,8 @@ void CodeGenFunction::EmitForStmt(const ForStmt &S, if (S.getInc()) { EmitBlock(Continue.getBlock()); EmitStmt(S.getInc()); + if (llvm::EnableSingleByteCoverage) + incrementProfileCounter(S.getInc()); } BreakContinueStack.pop_back(); @@ -1156,6 +1206,11 @@ void CodeGenFunction::EmitForStmt(const ForStmt &S, // Emit the fall-through block. EmitBlock(LoopExit.getBlock(), true); + + // When single byte coverage mode is enabled, add a counter to continuation + // block. + if (llvm::EnableSingleByteCoverage) + incrementProfileCounter(&S); } void @@ -1208,7 +1263,10 @@ CodeGenFunction::EmitCXXForRangeStmt(const CXXForRangeStmt &S, } EmitBlock(ForBody); - incrementProfileCounter(&S); + if (llvm::EnableSingleByteCoverage) + incrementProfileCounter(S.getBody()); + else + incrementProfileCounter(&S); // Create a block for the increment. In case of a 'continue', we jump there. JumpDest Continue = getJumpDestInCurrentScope("for.inc"); @@ -1238,6 +1296,11 @@ CodeGenFunction::EmitCXXForRangeStmt(const CXXForRangeStmt &S, // Emit the fall-through block. EmitBlock(LoopExit.getBlock(), true); + + // When single byte coverage mode is enabled, add a counter to continuation + // block. + if (llvm::EnableSingleByteCoverage) + incrementProfileCounter(&S); } void CodeGenFunction::EmitReturnOfRValue(RValue RV, QualType Ty) { diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp index 1ad905078d349c..b87fc86f4e635f 100644 --- a/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/clang/lib/CodeGen/CodeGenFunction.cpp @@ -52,6 +52,10 @@ using namespace clang; using namespace CodeGen; +namespace llvm { +extern cl::opt<bool> EnableSingleByteCoverage; +} // namespace llvm + /// shouldEmitLifetimeMarkers - Decide whether we need emit the life-time /// markers. static bool shouldEmitLifetimeMarkers(const CodeGenOptions &CGOpts, @@ -1270,7 +1274,10 @@ void CodeGenFunction::EmitFunctionBody(const Stmt *Body) { void CodeGenFunction::EmitBlockWithFallThrough(llvm::BasicBlock *BB, const Stmt *S) { llvm::BasicBlock *SkipCountBB = nullptr; - if (HaveInsertPoint() && CGM.getCodeGenOpts().hasProfileClangInstr()) { + // Do not skip over the instrumentation when single byte coverage mode is + // enabled. + if (HaveInsertPoint() && CGM.getCodeGenOpts().hasProfileClangInstr() && + !llvm::EnableSingleByteCoverage) { // When instrumenting for profiling, the fallthrough to certain // statements needs to skip over the instrumentation code so that we // get an accurate count. diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h index 143ad64e8816b1..d34c0233ea8f50 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -1541,7 +1541,7 @@ class CodeGenFunction : public CodeGenTypeCache { if (CGM.getCodeGenOpts().hasProfileClangInstr() && !CurFn->hasFnAttribute(llvm::Attribute::NoProfile) && !CurFn->hasFnAttribute(llvm::Attribute::SkipProfile)) - PGO.emitCounterIncrement(Builder, S, StepV); + PGO.emitCounterSetOrIncrement(Builder, S, StepV); PGO.setCurrentStmt(S); } diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index 36b63d78b06f83..1fed1032409d70 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -860,6 +860,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 5d7c3847745762..31658e049e9560 100644 --- a/clang/lib/CodeGen/CodeGenPGO.cpp +++ b/clang/lib/CodeGen/CodeGenPGO.cpp @@ -23,6 +23,10 @@ #include "llvm/Support/MD5.h" #include <optional> +namespace llvm { +extern cl::opt<bool> EnableSingleByteCoverage; +} // namespace llvm + static llvm::cl::opt<bool> EnableValueProfiling("enable-value-profiling", llvm::cl::desc("Enable value profiling"), @@ -343,6 +347,14 @@ struct MapRegionCounters : public RecursiveASTVisitor<MapRegionCounters> { return Base::VisitBinaryOperator(S); } + bool VisitConditionalOperator(ConditionalOperator *S) { + if (llvm::EnableSingleByteCoverage && S->getTrueExpr()) + CounterMap[S->getTrueExpr()] = NextCounter++; + if (llvm::EnableSingleByteCoverage && S->getFalseExpr()) + CounterMap[S->getFalseExpr()] = NextCounter++; + return Base::VisitConditionalOperator(S); + } + /// Include \p S in the function hash. bool VisitStmt(Stmt *S) { auto Type = updateCounterMappings(S); @@ -358,8 +370,21 @@ struct MapRegionCounters : public RecursiveASTVisitor<MapRegionCounters> { if (Hash.getHashVersion() == PGO_HASH_V1) return Base::TraverseIfStmt(If); + // When single byte coverage mode is enabled, add a counter to then and + // else. + bool NoSingleByteCoverage = !llvm::EnableSingleByteCoverage; + for (Stmt *CS : If->children()) { + if (!CS || NoSingleByteCoverage) + continue; + if (CS == If->getThen()) + CounterMap[If->getThen()] = NextCounter++; + else if (CS == If->getElse()) + CounterMap[If->getElse()] = NextCounter++; + } + // Otherwise, keep track of which branch we're in while traversing. VisitStmt(If); + for (Stmt *CS : If->children()) { if (!CS) continue; @@ -373,6 +398,81 @@ struct MapRegionCounters : public RecursiveASTVisitor<MapRegionCounters> { return true; } + bool TraverseWhileStmt(WhileStmt *While) { + // When single byte coverage mode is enabled, add a counter to condition and + // body. + bool NoSingleByteCoverage = !llvm::EnableSingleByteCoverage; + for (Stmt *CS : While->children()) { + if (!CS || NoSingleByteCoverage) + continue; + if (CS == While->getCond()) + CounterMap[While->getCond()] = NextCounter++; + else if (CS == While->getBody()) + CounterMap[While->getBody()] = NextCounter++; + } + + Base::TraverseWhileStmt(While); + if (Hash.getHashVersion() != PGO_HASH_V1) + Hash.combine(PGOHash::EndOfScope); + return true; + } + + bool TraverseDoStmt(DoStmt *Do) { + // When single byte coverage mode is enabled, add a counter to condition and + // body. + bool NoSingleByteCoverage = !llvm::EnableSingleByteCoverage; + for (Stmt *CS : Do->children()) { + if (!CS || NoSingleByteCoverage) + continue; + if (CS == Do->getCond()) + CounterMap[Do->getCond()] = NextCounter++; + else if (CS == Do->getBody()) + CounterMap[Do->getBody()] = NextCounter++; + } + + Base::TraverseDoStmt(Do); + if (Hash.getHashVersion() != PGO_HASH_V1) + Hash.combine(PGOHash::EndOfScope); + return true; + } + + bool TraverseForStmt(ForStmt *For) { + // When single byte coverage mode is enabled, add a counter to condition, + // increment and body. + bool NoSingleByteCoverage = !llvm::EnableSingleByteCoverage; + for (Stmt *CS : For->children()) { + if (!CS || NoSingleByteCoverage) + continue; + if (CS == For->getCond()) + CounterMap[For->getCond()] = NextCounter++; + else if (CS == For->getInc()) + CounterMap[For->getInc()] = NextCounter++; + else if (CS == For->getBody()) + CounterMap[For->getBody()] = NextCounter++; + } + + Base::TraverseForStmt(For); + if (Hash.getHashVersion() != PGO_HASH_V1) + Hash.combine(PGOHash::EndOfScope); + return true; + } + + bool TraverseCXXForRangeStmt(CXXForRangeStmt *ForRange) { + // When single byte coverage mode is enabled, add a counter to body. + bool NoSingleByteCoverage = !llvm::EnableSingleByteCoverage; + for (Stmt *CS : ForRange->children()) { + if (!CS || NoSingleByteCoverage) + continue; + if (CS == ForRange->getBody()) + CounterMap[ForRange->getBody()] = NextCounter++; + } + + Base::TraverseCXXForRangeStmt(ForRange); + 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). @@ -384,10 +484,6 @@ 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) DEFINE_NESTABLE_TRAVERSAL(CXXCatchStmt) @@ -1093,8 +1189,8 @@ CodeGenPGO::applyFunctionAttributes(llvm::IndexedInstrProfReader *PGOReader, Fn->setEntryCount(FunctionCount); } -void CodeGenPGO::emitCounterIncrement(CGBuilderTy &Builder, const Stmt *S, - llvm::Value *StepV) { +void CodeGenPGO::emitCounterSetOrIncrement(CGBuilderTy &Builder, const Stmt *S, + llvm::Value *StepV) { if (!RegionCounterMap || !Builder.GetInsertBlock()) return; @@ -1104,13 +1200,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::EnableSingleByteCoverage) + Builder.CreateCall(CGM.getIntrinsic(llvm::Intrinsic::instrprof_cover), ArrayRef(Args, 4)); - else - Builder.CreateCall( - CGM.getIntrinsic(llvm::Intrinsic::instrprof_increment_step), - ArrayRef(Args)); + else { + if (!StepV) + Builder.CreateCall(CGM.getIntrinsic(llvm::Intrinsic::instrprof_increment), + ArrayRef(Args, 4)); + else + Builder.CreateCall( + CGM.getIntrinsic(llvm::Intrinsic::instrprof_increment_step), + ArrayRef(Args)); + } } bool CodeGenPGO::canEmitMCDCCoverage(const CGBuilderTy &Builder) { @@ -1221,6 +1323,30 @@ void CodeGenPGO::setValueProfilingFlag(llvm::Module &M) { uint32_t(EnableValueProfiling)); } +void CodeGenPGO::setProfileVersion(llvm::Module &M) { + if (CGM.getCodeGenOpts().hasProfileClangInstr() && + llvm::EnableSingleByteCoverage) { + 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)); + } + IRLevelVersionVariable->setDSOLocal(true); + } +} + // 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 6596b6c3527764..38e242a45d7a8f 100644 --- a/clang/lib/CodeGen/CodeGenPGO.h +++ b/clang/lib/CodeGen/CodeGenPGO.h @@ -96,6 +96,8 @@ class CodeGenPGO { // 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); @@ -110,8 +112,8 @@ class CodeGenPGO { bool canEmitMCDCCoverage(const CGBuilderTy &Builder); public: - void emitCounterIncrement(CGBuilderTy &Builder, const Stmt *S, - llvm::Value *StepV); + void emitCounterSetOrIncrement(CGBuilderTy &Builder, const Stmt *S, + llvm::Value *StepV); void emitMCDCTestVectorBitmapUpdate(CGBuilderTy &Builder, const Expr *S, Address MCDCCondBitmapAddr); void emitMCDCParameters(CGBuilderTy &Builder); diff --git a/clang/lib/CodeGen/CoverageMappingGen.cpp b/clang/lib/CodeGen/CoverageMappingGen.cpp index 0c43317642bca4..1b26c4b8c2329a 100644 --- a/clang/lib/CodeGen/CoverageMappingGen.cpp +++ b/clang/lib/CodeGen/CoverageMappingGen.cpp @@ -31,6 +31,14 @@ // is textually included. #define COVMAP_V3 +namespace llvm { +cl::opt<bool> + EnableSingleByteCoverage("enable-single-byte-coverage", + llvm::cl::ZeroOrMore, + llvm::cl::desc("Enable single byte coverage"), + llvm::cl::Hidden, llvm::cl::init(false)); +} // namespace llvm + static llvm::cl::opt<bool> EmptyLineCommentCoverage( "emptyline-comment-coverage", llvm::cl::desc("Emit emptylines and comment lines as skipped regions (only " @@ -835,16 +843,22 @@ struct CounterCoverageMappingBuilder /// Return a counter for the subtraction of \c RHS from \c LHS Counter subtractCounters(Counter LHS, Counter RHS, bool Simplify = true) { + assert(!llvm::EnableSingleByteCoverage && + "cannot add counters when single byte coverage mode is enabled"); return Builder.subtract(LHS, RHS, Simplify); } /// Return a counter for the sum of \c LHS and \c RHS. Counter addCounters(Counter LHS, Counter RHS, bool Simplify = true) { + assert(!llvm::EnableSingleByteCoverage && + "cannot add counters when single byte coverage mode is enabled"); return Builder.add(LHS, RHS, Simplify); } Counter addCounters(Counter C1, Counter C2, Counter C3, bool Simplify = true) { + assert(!llvm::EnableSingleByteCoverage && + "cannot add counters when single byte coverage mode is enabled"); return addCounters(addCounters(C1, C2, Simplify), C3, Simplify); } @@ -1459,8 +1473,9 @@ 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::EnableSingleByteCoverage) + 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); @@ -1468,8 +1483,9 @@ 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::EnableSingleByteCoverage) + BreakContinueStack.back().ContinueCount = addCounters( + BreakContinueStack.back().ContinueCount, getRegion().getCounter()); terminateRegion(S); } @@ -1487,7 +1503,9 @@ struct CounterCoverageMappingBuilder extendRegion(S); Counter ParentCount = getRegion().getCounter(); - Counter BodyCount = getRegionCounter(S); + Counter BodyCount = llvm::EnableSingleByteCoverage + ? getRegionCounter(S->getBody()) + : getRegionCounter(S); // Handle the body first so that we can get the backedge count. BreakContinueStack.push_back(BreakContinue()); @@ -1500,7 +1518,9 @@ struct CounterCoverageMappingBuilder // Go back to handle the condition. Counter CondCount = - addCounters(ParentCount, BackedgeCount, BC.ContinueCount); + llvm::EnableSingleByteCoverage + ? getRegionCounter(S->getCond()) + : addCounters(ParentCount, BackedgeCount, BC.ContinueCount); propagateCounts(CondCount, S->getCond()); adjustForOutOfOrderTraversal(getEnd(S)); @@ -1510,7 +1530,11 @@ struct CounterCoverageMappingBuilder fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), BodyCount); Counter OutCount = - addCounters(BC.BreakCount, subtractCounters(CondCount, BodyCount)); + llvm::EnableSingleByteCoverage + ? getRegionCounter(S) + : addCounters(BC.BreakCount, + subtractCounters(CondCount, BodyCount)); + if (OutCount != ParentCount) { pushRegion(OutCount); GapRegionCounter = OutCount; @@ -1519,38 +1543,53 @@ struct CounterCoverageMappingBuilder } // Create Branch Region around condition. - createBranchRegion(S->getCond(), BodyCount, - subtractCounters(CondCount, BodyCount)); + if (!llvm::EnableSingleByteCoverage) + createBranchRegion(S->getCond(), BodyCount, + subtractCounters(CondCount, BodyCount)); } void VisitDoStmt(const DoStmt *S) { extendRegion(S); Counter ParentCount = getRegion().getCounter(); - Counter BodyCount = getRegionCounter(S); + Counter BodyCount = llvm::EnableSingleByteCoverage + ? getRegionCounter(S->getBody()) + : getRegionCounter(S); BreakContinueStack.push_back(BreakContinue()); extendRegion(S->getBody()); - Counter BackedgeCount = - propagateCounts(addCounters(ParentCount, BodyCount), S->getBody()); + + Counter BackedgeCount; + if (llvm::EnableSingleByteCoverage) + propagateCounts(BodyCount, S->getBody()); + else + BackedgeCount = + propagateCounts(addCounters(ParentCount, BodyCount), S->getBody()); + BreakContinue BC = BreakContinueStack.pop_back_val(); bool BodyHasTerminateStmt = HasTerminateStmt; HasTerminateStmt = false; - Counter CondCount = addCounters(BackedgeCount, BC.ContinueCount); + Counter CondCount = llvm::EnableSingleByteCoverage + ? getRegionCounter(S->getCond()) + : addCounters(BackedgeCount, BC.ContinueCount); propagateCounts(CondCount, S->getCond()); Counter OutCount = - addCounters(BC.BreakCount, subtractCounters(CondCount, BodyCount)); + llvm::EnableSingleByteCoverage + ? getRegionCounter(S) + : addCounters(BC.BreakCount, + subtractCounters(CondCount, BodyCount)); if (OutCount != ParentCount) { pushRegion(OutCount); GapRegionCounter = OutCount; } // Create Branch Region around condition. - createBranchRegion(S->getCond(), BodyCount, - subtractCounters(CondCount, BodyCount)); + if (!llvm::EnableSingleByteCoverage) + createBranchRegion(S->getCond(), BodyCount, + subtractCounters(CondCount, BodyCount)); if (BodyHasTerminateStmt) HasTerminateStmt = true; @@ -1562,7 +1601,9 @@ struct CounterCoverageMappingBuilder Visit(S->getInit()); Counter ParentCount = getRegion().getCounter(); - Counter BodyCount = getRegionCounter(S); + Counter BodyCount = llvm::EnableSingleByteCoverage + ? getRegionCounter(S->getBody()) + : getRegionCounter(S); // The loop increment may contain a break or continue. if (S->getInc()) @@ -1581,14 +1622,23 @@ struct CounterCoverageMappingBuilder // the count for all the continue statements. BreakContinue IncrementBC; if (const Stmt *Inc = S->getInc()) { - propagateCounts(addCounters(BackedgeCount, BodyBC.ContinueCount), Inc); + Counter IncCount; + if (llvm::EnableSingleByteCoverage) + IncCount = getRegionCounter(S->getInc()); + else + IncCount = addCounters(BackedgeCount, BodyBC.ContinueCount); + propagateCounts(IncCount, 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::EnableSingleByteCoverage + ? getRegionCounter(S->getCond()) + : addCounters( + addCounters(ParentCount, BackedgeCount, BodyBC.ContinueCount), + IncrementBC.ContinueCount); + if (const Expr *Cond = S->getCond()) { propagateCounts(CondCount, Cond); adjustForOutOfOrderTraversal(getEnd(S)); @@ -1599,8 +1649,11 @@ struct CounterCoverageMappingBuilder if (Gap) fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), BodyCount); - Counter OutCount = addCounters(BodyBC.BreakCount, IncrementBC.BreakCount, - subtractCounters(CondCount, BodyCount)); + Counter OutCount = + llvm::EnableSingleByteCoverage + ? getRegionCounter(S) + : addCounters(BodyBC.BreakCount, IncrementBC.BreakCount, + subtractCounters(CondCount, BodyCount)); if (OutCount != ParentCount) { pushRegion(OutCount); GapRegionCounter = OutCount; @@ -1609,8 +1662,9 @@ struct CounterCoverageMappingBuilder } // Create Branch Region around condition. - createBranchRegion(S->getCond(), BodyCount, - subtractCounters(CondCount, BodyCount)); + if (!llvm::EnableSingleByteCoverage) + createBranchRegion(S->getCond(), BodyCount, + subtractCounters(CondCount, BodyCount)); } void VisitCXXForRangeStmt(const CXXForRangeStmt *S) { @@ -1621,7 +1675,9 @@ struct CounterCoverageMappingBuilder Visit(S->getRangeStmt()); Counter ParentCount = getRegion().getCounter(); - Counter BodyCount = getRegionCounter(S); + Counter BodyCount = llvm::EnableSingleByteCoverage + ? getRegionCounter(S->getBody()) + : getRegionCounter(S); BreakContinueStack.push_back(BreakContinue()); extendRegion(S->getBody()); @@ -1636,10 +1692,15 @@ struct CounterCoverageMappingBuilder if (Gap) fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), BodyCount); - Counter LoopCount = - addCounters(ParentCount, BackedgeCount, BC.ContinueCount); - Counter OutCount = - addCounters(BC.BreakCount, subtractCounters(LoopCount, BodyCount)); + Counter OutCount; + Counter LoopCount; + if (llvm::EnableSingleByteCoverage) + OutCount = getRegionCounter(S); + else { + LoopCount = addCounters(ParentCount, BackedgeCount, BC.ContinueCount); + OutCount = + addCounters(BC.BreakCount, subtractCounters(LoopCount, BodyCount)); + } if (OutCount != ParentCount) { pushRegion(OutCount); GapRegionCounter = OutCount; @@ -1648,8 +1709,9 @@ struct CounterCoverageMappingBuilder } // Create Branch Region around condition. - createBranchRegion(S->getCond(), BodyCount, - subtractCounters(LoopCount, BodyCount)); + if (!llvm::EnableSingleByteCoverage) + createBranchRegion(S->getCond(), BodyCount, + subtractCounters(LoopCount, BodyCount)); } void VisitObjCForCollectionStmt(const ObjCForCollectionStmt *S) { @@ -1710,7 +1772,7 @@ struct CounterCoverageMappingBuilder propagateCounts(Counter::getZero(), Body); BreakContinue BC = BreakContinueStack.pop_back_val(); - if (!BreakContinueStack.empty()) + if (!BreakContinueStack.empty() && !llvm::EnableSingleByteCoverage) BreakContinueStack.back().ContinueCount = addCounters( BreakContinueStack.back().ContinueCount, BC.ContinueCount); @@ -1725,6 +1787,11 @@ struct CounterCoverageMappingBuilder MostRecentLocation = getStart(S); handleFileExit(ExitLoc); + // When single byte coverage mode is enabled, do not create branch region by + // early returning. + if (llvm::EnableSingleByteCoverage) + 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; @@ -1757,8 +1824,10 @@ struct CounterCoverageMappingBuilder extendRegion(S); SourceMappingRegion &Parent = getRegion(); + Counter Count = llvm::EnableSingleByteCoverage + ? getRegionCounter(S) + : addCounters(Parent.getCounter(), getRegionCounter(S)); - Counter Count = addCounters(Parent.getCounter(), getRegionCounter(S)); // Reuse the existing region if it starts at our label. This is typical of // the first case in a switch. if (Parent.hasStartLoc() && Parent.getBeginLoc() == getStart(S)) @@ -1876,7 +1945,9 @@ struct CounterCoverageMappingBuilder extendRegion(S->getCond()); Counter ParentCount = getRegion().getCounter(); - Counter ThenCount = getRegionCounter(S); + Counter ThenCount = llvm::EnableSingleByteCoverage + ? 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. @@ -1890,7 +1961,12 @@ struct CounterCoverageMappingBuilder extendRegion(S->getThen()); Counter OutCount = propagateCounts(ThenCount, S->getThen()); - Counter ElseCount = subtractCounters(ParentCount, ThenCount); + + Counter ElseCount; + if (!llvm::EnableSingleByteCoverage) + ElseCount = subtractCounters(ParentCount, ThenCount); + else if (S->getElse()) + ElseCount = getRegionCounter(S->getElse()); if (const Stmt *Else = S->getElse()) { bool ThenHasTerminateStmt = HasTerminateStmt; @@ -1901,21 +1977,28 @@ struct CounterCoverageMappingBuilder if (Gap) fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), ElseCount); extendRegion(Else); - OutCount = addCounters(OutCount, propagateCounts(ElseCount, Else)); + + Counter ElseOutCount = propagateCounts(ElseCount, Else); + if (!llvm::EnableSingleByteCoverage) + OutCount = addCounters(OutCount, ElseOutCount); if (ThenHasTerminateStmt) HasTerminateStmt = true; - } else + } else if (!llvm::EnableSingleByteCoverage) OutCount = addCounters(OutCount, ElseCount); + if (llvm::EnableSingleByteCoverage) + OutCount = getRegionCounter(S); + if (OutCount != ParentCount) { pushRegion(OutCount); GapRegionCounter = OutCount; } - // Create Branch Region around condition. - createBranchRegion(S->getCond(), ThenCount, - subtractCounters(ParentCount, ThenCount)); + if (!S->isConsteval() && !llvm::EnableSingleByteCoverage) + // Create Branch Region around condition. + createBranchRegion(S->getCond(), ThenCount, + subtractCounters(ParentCount, ThenCount)); } void VisitCXXTryStmt(const CXXTryStmt *S) { @@ -1941,7 +2024,9 @@ struct CounterCoverageMappingBuilder extendRegion(E); Counter ParentCount = getRegion().getCounter(); - Counter TrueCount = getRegionCounter(E); + Counter TrueCount = llvm::EnableSingleByteCoverage + ? getRegionCounter(E->getTrueExpr()) + : getRegionCounter(E); propagateCounts(ParentCount, E->getCond()); Counter OutCount; @@ -1958,9 +2043,15 @@ struct CounterCoverageMappingBuilder } extendRegion(E->getFalseExpr()); - OutCount = addCounters( - OutCount, propagateCounts(subtractCounters(ParentCount, TrueCount), - E->getFalseExpr())); + Counter FalseCount = llvm::EnableSingleByteCoverage + ? getRegionCounter(E->getFalseExpr()) + : subtractCounters(ParentCount, TrueCount); + + Counter FalseOutCount = propagateCounts(FalseCount, E->getFalseExpr()); + if (llvm::EnableSingleByteCoverage) + OutCount = getRegionCounter(E); + else + OutCount = addCounters(OutCount, FalseOutCount); if (OutCount != ParentCount) { pushRegion(OutCount); @@ -1968,8 +2059,9 @@ struct CounterCoverageMappingBuilder } // Create Branch Region around condition. - createBranchRegion(E->getCond(), TrueCount, - subtractCounters(ParentCount, TrueCount)); + if (!llvm::EnableSingleByteCoverage) + createBranchRegion(E->getCond(), TrueCount, + subtractCounters(ParentCount, TrueCount)); } void VisitBinLAnd(const BinaryOperator *E) { @@ -2007,12 +2099,14 @@ struct CounterCoverageMappingBuilder Counter ParentCnt = getRegion().getCounter(); // Create Branch Region around LHS condition. - createBranchRegion(E->getLHS(), RHSExecCnt, - subtractCounters(ParentCnt, RHSExecCnt), DecisionLHS); + if (!llvm::EnableSingleByteCoverage) + createBranchRegion(E->getLHS(), RHSExecCnt, + subtractCounters(ParentCnt, RHSExecCnt), DecisionLHS); // Create Branch Region around RHS condition. - createBranchRegion(E->getRHS(), RHSTrueCnt, - subtractCounters(RHSExecCnt, RHSTrueCnt), DecisionRHS); + if (!llvm::EnableSingleByteCoverage) + createBranchRegion(E->getRHS(), RHSTrueCnt, + subtractCounters(RHSExecCnt, RHSTrueCnt), DecisionRHS); } // Determine whether the right side of OR operation need to be visited. @@ -2064,12 +2158,14 @@ struct CounterCoverageMappingBuilder Counter ParentCnt = getRegion().getCounter(); // Create Branch Region around LHS condition. - createBranchRegion(E->getLHS(), subtractCounters(ParentCnt, RHSExecCnt), - RHSExecCnt, DecisionLHS); + if (!llvm::EnableSingleByteCoverage) + createBranchRegion(E->getLHS(), subtractCounters(ParentCnt, RHSExecCnt), + RHSExecCnt, DecisionLHS); // Create Branch Region around RHS condition. - createBranchRegion(E->getRHS(), subtractCounters(RHSExecCnt, RHSFalseCnt), - RHSFalseCnt, DecisionRHS); + if (!llvm::EnableSingleByteCoverage) + createBranchRegion(E->getRHS(), subtractCounters(RHSExecCnt, RHSFalseCnt), + RHSFalseCnt, DecisionRHS); } void VisitLambdaExpr(const LambdaExpr *LE) { diff --git a/clang/test/CoverageMapping/single-byte-counters.cpp b/clang/test/CoverageMapping/single-byte-counters.cpp new file mode 100644 index 00000000000000..8e9b613dcc68f7 --- /dev/null +++ b/clang/test/CoverageMapping/single-byte-counters.cpp @@ -0,0 +1,169 @@ +// RUN: %clang_cc1 -mllvm -emptyline-comment-coverage=false -mllvm -enable-single-byte-coverage=true -fprofile-instrument=clang -fcoverage-mapping -dump-coverage-mapping -emit-llvm-only -main-file-name single-byte-counters.cpp %s | FileCheck %s + +// CHECK: testIf +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 = #1 + // CHECK-NEXT: File 0, [[@LINE+4]]:5 -> [[@LINE+4]]:16 = #1 + // CHECK-NEXT: File 0, [[@LINE+5]]:3 -> [[@LINE+5]]:16 = #2 + int result = 0; + if (x == 0) + result = -1; + + return result; +} + +// CHECK-NEXT: testIfElse +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 = #3 + int result = 0; + if (x < 0) + result = 0; + else + result = x * x; + return result; +} + +// CHECK-NEXT: testIfElseReturn +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 = #3 + // CHECK-NEXT: File 0, [[@LINE+6]]:3 -> [[@LINE+6]]:16 = #3 + int result = 0; + if (x > 0) + result = x * x; + else + return 0; + return result; +} + +// CHECK-NEXT: testSwitch +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: testWhile +int testWhile() { // CHECK-NEXT: File 0, [[@LINE]]:17 -> [[@LINE+13]]:2 = #0 + // CHECK-NEXT: File 0, [[@LINE+6]]:10 -> [[@LINE+6]]:16 = #1 + // 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 = #3 + int i = 0; + int sum = 0; + while (i < 10) { + sum += i; + i++; + } + + return sum; +} + +// CHECK-NEXT: testContinue +int testContinue() { // CHECK-NEXT: File 0, [[@LINE]]:20 -> [[@LINE+21]]:2 = #0 + // CHECK-NEXT: File 0, [[@LINE+12]]:10 -> [[@LINE+12]]:16 = #1 + // 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 = #5 + // CHECK-NEXT: File 0, [[@LINE+8]]:5 -> [[@LINE+10]]:4 = #5 + // CHECK-NEXT: Gap,File 0, [[@LINE+9]]:4 -> [[@LINE+11]]:3 = #3 + // CHECK-NEXT: File 0, [[@LINE+10]]:3 -> [[@LINE+10]]:13 = #3 + int i = 0; + int sum = 0; + while (i < 10) { + if (i == 4) + continue; + sum += i; + i++; + } + + return sum; +} + +// CHECK-NEXT: testFor +int testFor() { // CHECK-NEXT: File 0, [[@LINE]]:15 -> [[@LINE+13]]:2 = #0 + // CHECK-NEXT: File 0, [[@LINE+7]]:19 -> [[@LINE+7]]:25 = #1 + // CHECK-NEXT: File 0, [[@LINE+6]]:27 -> [[@LINE+6]]:30 = #2 + // CHECK-NEXT: Gap,File 0, [[@LINE+5]]:31 -> [[@LINE+5]]:32 = #3 + // CHECK-NEXT: File 0, [[@LINE+4]]:32 -> [[@LINE+6]]:4 = #3 + // CHECK-NEXT: File 0, [[@LINE+7]]:3 -> [[@LINE+7]]:13 = #4 + int i; + int sum = 0; + for (int i = 0; i < 10; i++) { + sum += i; + } + + return sum; +} + +// CHECK-NEXT: testForRange +int testForRange() { // CHECK-NEXT: File 0, [[@LINE]]:20 -> [[@LINE+12]]:2 = #0 + // CHECK-NEXT: Gap,File 0, [[@LINE+6]]:28 -> [[@LINE+6]]:29 = #1 + // CHECK-NEXT: File 0, [[@LINE+5]]:29 -> [[@LINE+7]]:4 = #1 + // CHECK-NEXT: File 0, [[@LINE+8]]:3 -> [[@LINE+8]]:13 = #2 + int sum = 0; + int array[] = {1, 2, 3, 4, 5}; + + for (int element : array) { + sum += element; + } + + return sum; +} + +// CHECK-NEXT: testDo +int testDo() { // CHECK-NEXT: File 0, [[@LINE]]:14 -> [[@LINE+12]]:2 = #0 + // CHECK-NEXT: File 0, [[@LINE+5]]:6 -> [[@LINE+8]]:4 = #1 + // CHECK-NEXT: File 0, [[@LINE+7]]:12 -> [[@LINE+7]]:17 = #2 + // CHECK-NEXT: File 0, [[@LINE+8]]:3 -> [[@LINE+8]]:13 = #3 + int i = 0; + int sum = 0; + do { + sum += i; + i++; + } while (i < 5); + + return sum; +} + +// CHECK-NEXT: testConditional +int testConditional(int x) { // CHECK-NEXT: File 0, [[@LINE]]:28 -> [[@LINE+8]]:2 = #0 + // CHECK-NEXT: File 0, [[@LINE+5]]:15 -> [[@LINE+5]]:22 = #0 + // CHECK-NEXT: Gap,File 0, [[@LINE+4]]:24 -> [[@LINE+4]]:25 = #2 + // CHECK-NEXT: File 0, [[@LINE+3]]:25 -> [[@LINE+3]]:26 = #2 + // CHECK-NEXT: File 0, [[@LINE+2]]:29 -> [[@LINE+2]]:31 = #3 + // CHECK-NEXT: File 0, [[@LINE+2]]:2 -> [[@LINE+2]]:15 = #1 + int result = (x > 0) ? 1 : -1; + return result; +} diff --git a/compiler-rt/lib/profile/InstrProfiling.h b/compiler-rt/lib/profile/InstrProfiling.h index 01239083369187..705b54fddcd7bf 100644 --- a/compiler-rt/lib/profile/InstrProfiling.h +++ b/compiler-rt/lib/profile/InstrProfiling.h @@ -294,7 +294,8 @@ COMPILER_RT_VISIBILITY extern int INSTR_PROF_PROFILE_RUNTIME_VAR; * variable is defined as weak so that compiler can emit an overriding * definition depending on user option. */ -extern uint64_t INSTR_PROF_RAW_VERSION_VAR; /* __llvm_profile_raw_version */ +COMPILER_RT_VISIBILITY extern uint64_t + INSTR_PROF_RAW_VERSION_VAR; /* __llvm_profile_raw_version */ /*! * This variable is a weak symbol defined in InstrProfiling.c. It allows diff --git a/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h b/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h index 88ec60c7aa33c6..b4d6cb1055feb6 100644 --- a/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h +++ b/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h @@ -369,15 +369,19 @@ struct CountedRegion : public CounterMappingRegion { uint64_t ExecutionCount; uint64_t FalseExecutionCount; bool Folded; + bool HasSingleByteCoverage; - CountedRegion(const CounterMappingRegion &R, uint64_t ExecutionCount) + CountedRegion(const CounterMappingRegion &R, uint64_t ExecutionCount, + bool HasSingleByteCoverage) : CounterMappingRegion(R), ExecutionCount(ExecutionCount), - FalseExecutionCount(0), Folded(false) {} + FalseExecutionCount(0), Folded(false), + HasSingleByteCoverage(HasSingleByteCoverage) {} CountedRegion(const CounterMappingRegion &R, uint64_t ExecutionCount, - uint64_t FalseExecutionCount) + uint64_t FalseExecutionCount, bool HasSingleByteCoverage) : CounterMappingRegion(R), ExecutionCount(ExecutionCount), - FalseExecutionCount(FalseExecutionCount), Folded(false) {} + FalseExecutionCount(FalseExecutionCount), Folded(false), + HasSingleByteCoverage(HasSingleByteCoverage) {} }; /// MCDC Record grouping all information together. @@ -617,10 +621,11 @@ struct FunctionRecord { void pushMCDCRecord(MCDCRecord Record) { MCDCRecords.push_back(Record); } void pushRegion(CounterMappingRegion Region, uint64_t Count, - uint64_t FalseCount) { + uint64_t FalseCount, bool HasSingleByteCoverage) { if (Region.Kind == CounterMappingRegion::BranchRegion || Region.Kind == CounterMappingRegion::MCDCBranchRegion) { - CountedBranchRegions.emplace_back(Region, Count, FalseCount); + CountedBranchRegions.emplace_back(Region, Count, FalseCount, + HasSingleByteCoverage); // If both counters are hard-coded to zero, then this region represents a // constant-folded branch. if (Region.Count.isZero() && Region.FalseCount.isZero()) @@ -629,7 +634,8 @@ struct FunctionRecord { } if (CountedRegions.empty()) ExecutionCount = Count; - CountedRegions.emplace_back(Region, Count, FalseCount); + CountedRegions.emplace_back(Region, Count, FalseCount, + HasSingleByteCoverage); } }; diff --git a/llvm/include/llvm/ProfileData/InstrProfWriter.h b/llvm/include/llvm/ProfileData/InstrProfWriter.h index 047b14f223bd94..7a806fd7fcf345 100644 --- a/llvm/include/llvm/ProfileData/InstrProfWriter.h +++ b/llvm/include/llvm/ProfileData/InstrProfWriter.h @@ -168,6 +168,10 @@ class InstrProfWriter { InstrProfKind getProfileKind() const { return ProfileKind; } + bool hasSingleByteCoverage() const { + return static_cast<bool>(ProfileKind & InstrProfKind::SingleByteCoverage); + } + // Internal interface for testing purpose only. void setValueProfDataEndianness(llvm::endianness Endianness); void setOutputSparse(bool Sparse); diff --git a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp index 6b189c31463283..2322d6fe5b836e 100644 --- a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp +++ b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp @@ -740,7 +740,8 @@ Error CoverageMapping::loadFunctionRecord( consumeError(std::move(E)); return Error::success(); } - Function.pushRegion(Region, *ExecutionCount, *AltExecutionCount); + Function.pushRegion(Region, *ExecutionCount, *AltExecutionCount, + ProfileReader.hasSingleByteCoverage()); // Record ExpansionRegion. if (Region.Kind == CounterMappingRegion::ExpansionRegion) { @@ -1162,8 +1163,14 @@ class SegmentBuilder { // value for that area. // We add counts of the regions of the same kind as the active region // to handle the both situations. - if (I->Kind == Active->Kind) - Active->ExecutionCount += I->ExecutionCount; + if (I->Kind == Active->Kind) { + assert(I->HasSingleByteCoverage == Active->HasSingleByteCoverage && + "Regions are generated in different coverage modes"); + if (I->HasSingleByteCoverage) + Active->ExecutionCount = Active->ExecutionCount || I->ExecutionCount; + else + Active->ExecutionCount += I->ExecutionCount; + } } return Regions.drop_back(std::distance(++Active, End)); } _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits