[compiler-rt] [llvm] [MC/DC][Coverage] Enable profile correlation for MC/DC (PR #136437)

Ellis Hoag via llvm-commits llvm-commits at lists.llvm.org
Wed Dec 3 15:54:32 PST 2025


================
@@ -342,106 +358,199 @@ bool DwarfInstrProfCorrelator<IntPtrT>::isDIEOfProbe(const DWARFDie &Die) {
   if (!Die.hasChildren())
     return false;
   if (const char *Name = Die.getName(DINameKind::ShortName))
-    return StringRef(Name).starts_with(getInstrProfCountersVarPrefix());
+    return StringRef(Name).starts_with(Prefix);
   return false;
 }
 
 template <class IntPtrT>
 void DwarfInstrProfCorrelator<IntPtrT>::correlateProfileDataImpl(
     int MaxWarnings, InstrProfCorrelator::CorrelationData *Data) {
+  using RawProfData = RawInstrProf::ProfileData<IntPtrT>;
   bool UnlimitedWarnings = (MaxWarnings == 0);
   // -N suppressed warnings means we can emit up to N (unsuppressed) warnings
   int NumSuppressedWarnings = -MaxWarnings;
-  auto maybeAddProbe = [&](DWARFDie Die) {
-    if (!isDIEOfProbe(Die))
+  auto maybeAddProbe = [&](DWARFDie Die, const StringRef &Prefix) {
+    if (!isDIEOfProbe(Die, Prefix))
       return;
-    std::optional<const char *> FunctionName;
-    std::optional<uint64_t> CFGHash;
-    std::optional<uint64_t> CounterPtr = getLocation(Die);
-    auto FnDie = Die.getParent();
-    auto FunctionPtr = dwarf::toAddress(FnDie.find(dwarf::DW_AT_low_pc));
-    std::optional<uint64_t> NumCounters;
-    for (const DWARFDie &Child : Die.children()) {
-      if (Child.getTag() != dwarf::DW_TAG_LLVM_annotation)
-        continue;
-      auto AnnotationFormName = Child.find(dwarf::DW_AT_name);
-      auto AnnotationFormValue = Child.find(dwarf::DW_AT_const_value);
-      if (!AnnotationFormName || !AnnotationFormValue)
-        continue;
-      auto AnnotationNameOrErr = AnnotationFormName->getAsCString();
-      if (auto Err = AnnotationNameOrErr.takeError()) {
-        consumeError(std::move(Err));
-        continue;
+    if (Prefix == getInstrProfCountersVarPrefix()) {
+      std::optional<const char *> FunctionName;
+      std::optional<uint64_t> CFGHash;
+      std::optional<uint64_t> CounterPtr = getLocation(Die);
+      auto FnDie = Die.getParent();
+      auto FunctionPtr = dwarf::toAddress(FnDie.find(dwarf::DW_AT_low_pc));
+      std::optional<uint64_t> NumCounters;
+      for (const DWARFDie &Child : Die.children()) {
+        if (Child.getTag() != dwarf::DW_TAG_LLVM_annotation)
+          continue;
+        auto AnnotationFormName = Child.find(dwarf::DW_AT_name);
+        auto AnnotationFormValue = Child.find(dwarf::DW_AT_const_value);
+        if (!AnnotationFormName || !AnnotationFormValue)
+          continue;
+        auto AnnotationNameOrErr = AnnotationFormName->getAsCString();
+        if (auto Err = AnnotationNameOrErr.takeError()) {
+          consumeError(std::move(Err));
+          continue;
+        }
+        StringRef AnnotationName = *AnnotationNameOrErr;
+        if (AnnotationName == InstrProfCorrelator::FunctionNameAttributeName) {
+          if (auto EC =
+                  AnnotationFormValue->getAsCString().moveInto(FunctionName))
+            consumeError(std::move(EC));
+        } else if (AnnotationName ==
+                   InstrProfCorrelator::CFGHashAttributeName) {
+          CFGHash = AnnotationFormValue->getAsUnsignedConstant();
+        } else if (AnnotationName ==
+                   InstrProfCorrelator::NumCountersAttributeName) {
+          NumCounters = AnnotationFormValue->getAsUnsignedConstant();
+        }
       }
-      StringRef AnnotationName = *AnnotationNameOrErr;
-      if (AnnotationName == InstrProfCorrelator::FunctionNameAttributeName) {
-        if (auto EC =
-                AnnotationFormValue->getAsCString().moveInto(FunctionName))
-          consumeError(std::move(EC));
-      } else if (AnnotationName == InstrProfCorrelator::CFGHashAttributeName) {
-        CFGHash = AnnotationFormValue->getAsUnsignedConstant();
-      } else if (AnnotationName ==
-                 InstrProfCorrelator::NumCountersAttributeName) {
-        NumCounters = AnnotationFormValue->getAsUnsignedConstant();
+      if (!FunctionName || !CFGHash || !CounterPtr || !NumCounters) {
+        if (UnlimitedWarnings || ++NumSuppressedWarnings < 1) {
+          WithColor::warning()
+              << "Incomplete DIE for function " << FunctionName
+              << ": CFGHash=" << CFGHash << "  CounterPtr=" << CounterPtr
+              << "  NumCounters=" << NumCounters << "\n";
+          LLVM_DEBUG(Die.dump(dbgs()));
+        }
+        return;
       }
-    }
-    if (!FunctionName || !CFGHash || !CounterPtr || !NumCounters) {
-      if (UnlimitedWarnings || ++NumSuppressedWarnings < 1) {
-        WithColor::warning()
-            << "Incomplete DIE for function " << FunctionName
-            << ": CFGHash=" << CFGHash << "  CounterPtr=" << CounterPtr
-            << "  NumCounters=" << NumCounters << "\n";
-        LLVM_DEBUG(Die.dump(dbgs()));
+      uint64_t CountersStart = this->Ctx->CountersSectionStart;
+      uint64_t CountersEnd = this->Ctx->CountersSectionEnd;
+      if (*CounterPtr < CountersStart || *CounterPtr >= CountersEnd) {
+        if (UnlimitedWarnings || ++NumSuppressedWarnings < 1) {
+          WithColor::warning()
+              << format("CounterPtr out of range for function %s: Actual=0x%x "
+                        "Expected=[0x%x, 0x%x)\n",
+                        *FunctionName, *CounterPtr, CountersStart, CountersEnd);
+          LLVM_DEBUG(Die.dump(dbgs()));
+        }
+        return;
       }
-      return;
-    }
-    uint64_t CountersStart = this->Ctx->CountersSectionStart;
-    uint64_t CountersEnd = this->Ctx->CountersSectionEnd;
-    if (*CounterPtr < CountersStart || *CounterPtr >= CountersEnd) {
-      if (UnlimitedWarnings || ++NumSuppressedWarnings < 1) {
+      if (!FunctionPtr && (UnlimitedWarnings || ++NumSuppressedWarnings < 1)) {
         WithColor::warning()
-            << format("CounterPtr out of range for function %s: Actual=0x%x "
-                      "Expected=[0x%x, 0x%x)\n",
-                      *FunctionName, *CounterPtr, CountersStart, CountersEnd);
+            << format("Could not find address of function %s\n", *FunctionName);
         LLVM_DEBUG(Die.dump(dbgs()));
       }
-      return;
-    }
-    if (!FunctionPtr && (UnlimitedWarnings || ++NumSuppressedWarnings < 1)) {
-      WithColor::warning() << format("Could not find address of function %s\n",
-                                     *FunctionName);
-      LLVM_DEBUG(Die.dump(dbgs()));
-    }
-    // In debug info correlation mode, the CounterPtr is an absolute address of
-    // the counter, but it's expected to be relative later when iterating Data.
-    IntPtrT CounterOffset = *CounterPtr - CountersStart;
-    if (Data) {
-      InstrProfCorrelator::Probe P;
-      P.FunctionName = *FunctionName;
-      if (auto Name = FnDie.getName(DINameKind::LinkageName))
-        P.LinkageName = Name;
-      P.CFGHash = *CFGHash;
-      P.CounterOffset = CounterOffset;
-      P.NumCounters = *NumCounters;
-      auto FilePath = FnDie.getDeclFile(
-          DILineInfoSpecifier::FileLineInfoKind::RelativeFilePath);
-      if (!FilePath.empty())
-        P.FilePath = FilePath;
-      if (auto LineNumber = FnDie.getDeclLine())
-        P.LineNumber = LineNumber;
-      Data->Probes.push_back(P);
-    } else {
-      this->addDataProbe(IndexedInstrProf::ComputeHash(*FunctionName), *CFGHash,
-                         CounterOffset, FunctionPtr.value_or(0), *NumCounters);
-      this->NamesVec.push_back(*FunctionName);
+      // In debug info correlation mode, the CounterPtr is an absolute address
+      // of the counter, but it's expected to be relative later when iterating
+      // Data.
+      IntPtrT CounterOffset = *CounterPtr - CountersStart;
+      if (Data) {
+        InstrProfCorrelator::Probe P;
+        P.FunctionName = *FunctionName;
+        if (auto Name = FnDie.getName(DINameKind::LinkageName))
+          P.LinkageName = Name;
+        P.CFGHash = *CFGHash;
+        P.CounterOffset = CounterOffset;
+        P.NumCounters = *NumCounters;
+        auto FilePath = FnDie.getDeclFile(
+            DILineInfoSpecifier::FileLineInfoKind::RelativeFilePath);
+        if (!FilePath.empty())
+          P.FilePath = FilePath;
+        if (auto LineNumber = FnDie.getDeclLine())
+          P.LineNumber = LineNumber;
+        Data->Probes.push_back(P);
+      } else {
+        this->addDataProbe(IndexedInstrProf::ComputeHash(*FunctionName),
+                           *CFGHash, CounterOffset, 0, FunctionPtr.value_or(0),
+                           *NumCounters, 0);
+        this->NamesVec.push_back(*FunctionName);
+      }
+    } else if (Prefix == getInstrProfBitmapVarPrefix()) {
+      std::optional<const char *> FunctionName;
+      std::optional<uint64_t> BitmapPtr = getLocation(Die);
+      uint64_t NumBitmapBytes;
+      for (const DWARFDie &Child : Die.children()) {
+        if (Child.getTag() != dwarf::DW_TAG_LLVM_annotation)
+          continue;
+        auto AnnotationFormName = Child.find(dwarf::DW_AT_name);
+        auto AnnotationFormValue = Child.find(dwarf::DW_AT_const_value);
+        if (!AnnotationFormName || !AnnotationFormValue)
+          continue;
+        auto AnnotationNameOrErr = AnnotationFormName->getAsCString();
+        if (auto Err = AnnotationNameOrErr.takeError()) {
+          consumeError(std::move(Err));
+          continue;
+        }
+        StringRef AnnotationName = *AnnotationNameOrErr;
+        if (AnnotationName == InstrProfCorrelator::FunctionNameAttributeName) {
+          if (auto EC =
+                  AnnotationFormValue->getAsCString().moveInto(FunctionName))
+            consumeError(std::move(EC));
+        } else if (AnnotationName ==
+                   InstrProfCorrelator::NumBitmapBitsAttributeName) {
+          std::optional<uint64_t> NumBitmapBits =
+              AnnotationFormValue->getAsUnsignedConstant();
+          NumBitmapBytes = alignTo(*NumBitmapBits, CHAR_BIT) / CHAR_BIT;
+        }
+      }
+      if (!FunctionName || !BitmapPtr || !NumBitmapBytes) {
+        if (UnlimitedWarnings || ++NumSuppressedWarnings < 1) {
+          WithColor::warning() << "Incomplete DIE for function " << FunctionName
+                               << "  BitmapPtr=" << BitmapPtr
+                               << "  NumBitmapBytes=" << NumBitmapBytes << "\n";
+          LLVM_DEBUG(Die.dump(dbgs()));
+        }
+        return;
+      }
+      uint64_t BitmapStart = this->Ctx->BitmapSectionStart;
+      uint64_t BitmapEnd = this->Ctx->BitmapSectionEnd;
+      if (!BitmapStart && !BitmapEnd && NumBitmapBytes) {
+        auto E = make_error<InstrProfError>(
+            instrprof_error::unable_to_correlate_profile,
+            "could not find profile bitmap section in correlated file");
+        return;
+      }
+      if (*BitmapPtr < BitmapStart ||
+          (*BitmapPtr >= BitmapEnd && NumBitmapBytes)) {
+        if (UnlimitedWarnings || ++NumSuppressedWarnings < 1) {
+          WithColor::warning()
+              << format("BitmapPtr out of range for function %s: Actual=0x%x "
+                        "Expected=[0x%x, 0x%x)\n",
+                        *FunctionName, *BitmapPtr, BitmapStart, BitmapEnd);
+          LLVM_DEBUG(Die.dump(dbgs()));
+        }
+        return;
+      }
+      // In debug info correlation mode, the BitmapPtr is an absolute address of
+      // the bitmap, but it's expected to be relative later when iterating Data.
+      IntPtrT BitmapOffset = *BitmapPtr - BitmapStart;
+      // Add bitmap information to the corresponding profile data entry.
+      if (Data) {
+        for (auto P : Data->Probes) {
+          if (P.FunctionName == *FunctionName) {
+            P.BitmapOffset = BitmapOffset;
+            P.NumBitmapBytes = NumBitmapBytes;
+            return;
+          }
+        }
+      } else {
+        for (const RawProfData &I : this->Data) {
+          if (I.NameRef == IndexedInstrProf::ComputeHash(*FunctionName)) {
+            const_cast<IntPtrT &>(I.BitmapPtr) = BitmapOffset;
+            const_cast<uint32_t &>(I.NumBitmapBytes) = NumBitmapBytes;
+            return;
+          }
+        }
+      }
+      WithColor::warning() << format(
+          "Could not find Counters for function %s\n", *FunctionName);
     }
   };
-  for (auto &CU : DICtx->normal_units())
+  for (auto &CU : DICtx->normal_units()) {
     for (const auto &Entry : CU->dies())
-      maybeAddProbe(DWARFDie(CU.get(), &Entry));
-  for (auto &CU : DICtx->dwo_units())
+      maybeAddProbe(DWARFDie(CU.get(), &Entry),
+                    getInstrProfCountersVarPrefix());
     for (const auto &Entry : CU->dies())
-      maybeAddProbe(DWARFDie(CU.get(), &Entry));
+      maybeAddProbe(DWARFDie(CU.get(), &Entry), getInstrProfBitmapVarPrefix());
----------------
ellishg wrote:

Can we fold these two loops into one? And also put `DWARFDie(CU.get(), &Entry)` into a variable so it can be reused?

https://github.com/llvm/llvm-project/pull/136437


More information about the llvm-commits mailing list