Skip to content

Commit 78702d3

Browse files
authored
[InstrProfiling] Ensure data variables are always created for inlined functions (llvm#72069)
Fixes a bug introduced by commit f95b2f1 ("Reland [InstrProf][compiler-rt] Enable MC/DC Support in LLVM Source-based Code Coverage (1/3)") The InstrProfiling pass was refactored when introducing support for MC/DC such that the creation of the data variable was abstracted and called only once per function from ::run(). Because ::run() only iterated over functions there were not fully inlined, and because it only created the data variable for the first intrinsic that it saw, data variables corresponding to functions fully inlined into other instrumented callers would end up without a data variable, resulting in loss of coverage information. This patch does the following: 1.) Move the call of createDataVariable() to getOrCreateRegionCounters() so that the creation of the data variable will happen indirectly either from ::new() or during profile intrinsic lowering when it is needed. This effectively restores the behavior prior to the refactor and ensures that all data variables are created when needed (and not duplicated). 2.) Process all MC/DC bitmap parameter intrinsics in ::run() prior to calling getOrCreateRegionCounters(). This ensures bitmap regions are created for each function including functions that are fully inlined. It also ensures that the bitmap region is created for each function prior to the creation of the data variable because it is referenced by the data variable. Again, duplication is prevented if the same parameter intrinsic is inlined into multiple functions. 3.) No longer pass the MC/DC intrinsic to createDataVariable(). This decouples the creation of the data variable from a specific MC/DC intrinsic. Instead, with #2 above, store the number of bitmap bytes required in the PerFunctionProfileData in the ProfileDataMap along with the function's CounterRegion and BitmapRegion variables. This ties the bitmap information directly to the function to which it belongs, and the data variable created for that function can reference that.
1 parent cc9e19e commit 78702d3

File tree

3 files changed

+58
-16
lines changed

3 files changed

+58
-16
lines changed

llvm/include/llvm/Transforms/Instrumentation/InstrProfiling.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ class InstrProfiling : public PassInfoMixin<InstrProfiling> {
5151
GlobalVariable *RegionCounters = nullptr;
5252
GlobalVariable *DataVar = nullptr;
5353
GlobalVariable *RegionBitmaps = nullptr;
54+
uint32_t NumBitmapBytes = 0;
5455

5556
PerFunctionProfileData() {
5657
memset(NumValueSites, 0, sizeof(uint32_t) * (IPVK_Last + 1));
@@ -156,8 +157,7 @@ class InstrProfiling : public PassInfoMixin<InstrProfiling> {
156157
InstrProfSectKind IPSK);
157158

158159
/// Create INSTR_PROF_DATA variable for counters and bitmaps.
159-
void createDataVariable(InstrProfCntrInstBase *Inc,
160-
InstrProfMCDCBitmapParameters *Update);
160+
void createDataVariable(InstrProfCntrInstBase *Inc);
161161

162162
/// Emit the section with compressed function names.
163163
void emitNameData();

llvm/lib/Transforms/Instrumentation/InstrProfiling.cpp

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -556,7 +556,6 @@ bool InstrProfiling::run(
556556
// target value sites to enter it as field in the profile data variable.
557557
for (Function &F : M) {
558558
InstrProfCntrInstBase *FirstProfInst = nullptr;
559-
InstrProfMCDCBitmapParameters *FirstProfMCDCParams = nullptr;
560559
for (BasicBlock &BB : F) {
561560
for (auto I = BB.begin(), E = BB.end(); I != E; I++) {
562561
if (auto *Ind = dyn_cast<InstrProfValueProfileInst>(I))
@@ -565,22 +564,17 @@ bool InstrProfiling::run(
565564
if (FirstProfInst == nullptr &&
566565
(isa<InstrProfIncrementInst>(I) || isa<InstrProfCoverInst>(I)))
567566
FirstProfInst = dyn_cast<InstrProfCntrInstBase>(I);
568-
if (FirstProfMCDCParams == nullptr)
569-
FirstProfMCDCParams = dyn_cast<InstrProfMCDCBitmapParameters>(I);
567+
// If the MCDCBitmapParameters intrinsic seen, create the bitmaps.
568+
if (const auto &Params = dyn_cast<InstrProfMCDCBitmapParameters>(I))
569+
static_cast<void>(getOrCreateRegionBitmaps(Params));
570570
}
571571
}
572572
}
573573

574-
// If the MCDCBitmapParameters intrinsic was seen, create the bitmaps.
575-
if (FirstProfMCDCParams != nullptr) {
576-
static_cast<void>(getOrCreateRegionBitmaps(FirstProfMCDCParams));
577-
}
578-
579574
// Use a profile intrinsic to create the region counters and data variable.
580575
// Also create the data variable based on the MCDCParams.
581576
if (FirstProfInst != nullptr) {
582577
static_cast<void>(getOrCreateRegionCounters(FirstProfInst));
583-
createDataVariable(FirstProfInst, FirstProfMCDCParams);
584578
}
585579
}
586580

@@ -1162,6 +1156,7 @@ InstrProfiling::getOrCreateRegionBitmaps(InstrProfMCDCBitmapInstBase *Inc) {
11621156
// the corresponding profile section.
11631157
auto *BitmapPtr = setupProfileSection(Inc, IPSK_bitmap);
11641158
PD.RegionBitmaps = BitmapPtr;
1159+
PD.NumBitmapBytes = Inc->getNumBitmapBytes()->getZExtValue();
11651160
return PD.RegionBitmaps;
11661161
}
11671162

@@ -1238,11 +1233,13 @@ InstrProfiling::getOrCreateRegionCounters(InstrProfCntrInstBase *Inc) {
12381233
CompilerUsedVars.push_back(PD.RegionCounters);
12391234
}
12401235

1236+
// Create the data variable (if it doesn't already exist).
1237+
createDataVariable(Inc);
1238+
12411239
return PD.RegionCounters;
12421240
}
12431241

1244-
void InstrProfiling::createDataVariable(InstrProfCntrInstBase *Inc,
1245-
InstrProfMCDCBitmapParameters *Params) {
1242+
void InstrProfiling::createDataVariable(InstrProfCntrInstBase *Inc) {
12461243
// When debug information is correlated to profile data, a data variable
12471244
// is not needed.
12481245
if (DebugInfoCorrelate)
@@ -1305,9 +1302,7 @@ void InstrProfiling::createDataVariable(InstrProfCntrInstBase *Inc,
13051302
uint64_t NumCounters = Inc->getNumCounters()->getZExtValue();
13061303
auto *CounterPtr = PD.RegionCounters;
13071304

1308-
uint64_t NumBitmapBytes = 0;
1309-
if (Params != nullptr)
1310-
NumBitmapBytes = Params->getNumBitmapBytes()->getZExtValue();
1305+
uint64_t NumBitmapBytes = PD.NumBitmapBytes;
13111306

13121307
// Create data variable.
13131308
auto *IntPtrTy = M->getDataLayout().getIntPtrType(M->getContext());
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
;; Check that all data variables are created for instrumented functions even
2+
;; when those functions are fully inlined into their instrumented callers prior
3+
;; to the instrprof pass.
4+
; RUN: opt %s -passes='instrprof' -S | FileCheck %s -check-prefix=NOINLINE
5+
; RUN: opt %s -passes='cgscc(inline),instrprof' -S | FileCheck %s -check-prefix=INLINEFIRST
6+
; RUN: opt %s -passes='instrprof,cgscc(inline)' -S | FileCheck %s -check-prefix=INLINEAFTER
7+
8+
target triple = "x86_64-unknown-linux-gnu"
9+
10+
; INLINEFIRST: @__profd_foo = private global{{.*}}zeroinitializer, i32 21
11+
; INLINEFIRST: @__profd_bar = private global{{.*}}zeroinitializer, i32 23
12+
; INLINEFIRST: @__profd_foobar = private global{{.*}}zeroinitializer, i32 99
13+
14+
; INLINEAFTER: @__profd_foobar = private global{{.*}}zeroinitializer, i32 99
15+
; INLINEAFTER: @__profd_foo = private global{{.*}}zeroinitializer, i32 21
16+
; INLINEAFTER: @__profd_bar = private global{{.*}}zeroinitializer, i32 23
17+
18+
; NOINLINE: @__profd_foobar = private global{{.*}}zeroinitializer, i32 99
19+
; NOINLINE: @__profd_foo = private global{{.*}}zeroinitializer, i32 21
20+
; NOINLINE: @__profd_bar = private global{{.*}}zeroinitializer, i32 23
21+
22+
declare void @llvm.instrprof.increment(ptr %0, i64 %1, i32 %2, i32 %3)
23+
declare void @llvm.instrprof.mcdc.parameters(ptr %0, i64 %1, i32 %2)
24+
@__profn_foobar = private constant [6 x i8] c"foobar"
25+
@__profn_foo = private constant [3 x i8] c"foo"
26+
@__profn_bar = private constant [3 x i8] c"bar"
27+
28+
define internal void @foobar() {
29+
call void @llvm.instrprof.increment(ptr @__profn_foobar, i64 123456, i32 32, i32 0)
30+
call void @llvm.instrprof.mcdc.parameters(ptr @__profn_foobar, i64 123456, i32 99)
31+
32+
ret void
33+
}
34+
35+
define void @foo() {
36+
call void @llvm.instrprof.increment(ptr @__profn_foo, i64 123456, i32 32, i32 0)
37+
call void @llvm.instrprof.mcdc.parameters(ptr @__profn_foo, i64 123456, i32 21)
38+
call void @foobar()
39+
ret void
40+
}
41+
42+
define void @bar() {
43+
call void @llvm.instrprof.increment(ptr @__profn_bar, i64 123456, i32 32, i32 0)
44+
call void @llvm.instrprof.mcdc.parameters(ptr @__profn_bar, i64 123456, i32 23)
45+
call void @foobar()
46+
ret void
47+
}

0 commit comments

Comments
 (0)