[llvm] Introduce CovMap in ObjectYAML (PR #127432)
James Henderson via llvm-commits
llvm-commits at lists.llvm.org
Mon Feb 24 01:23:33 PST 2025
================
@@ -0,0 +1,984 @@
+//===- CovMap.cpp - ObjectYAML Interface for coverage map -----------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Implementations of CovMap, encoder, decoder.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ObjectYAML/CovMap.h"
+#include "llvm/ADT/MapVector.h"
+#include "llvm/ObjectYAML/ELFYAML.h"
+#include "llvm/ProfileData/Coverage/CoverageMapping.h"
+#include "llvm/ProfileData/Coverage/CoverageMappingReader.h"
+#include "llvm/ProfileData/Coverage/CoverageMappingWriter.h"
+#include "llvm/ProfileData/InstrProf.h"
+#include "llvm/Support/Alignment.h"
+#include "llvm/Support/DataExtractor.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/LEB128.h"
+#include "llvm/Support/MD5.h"
+#include "llvm/Support/YAMLTraits.h"
+#include <cstdint>
+
+#define COVMAP_V3
+
+using namespace llvm;
+using namespace llvm::coverage::yaml;
+using namespace llvm::covmap;
+
+bool Decoder::enabled;
+
+// DataExtractor w/ single Cursor
+struct coverage::yaml::DecoderContext : DataExtractor,
+ DataExtractor::Cursor,
+ DecoderParam {
+ uint64_t LineStart = 0;
+
+ DecoderContext(const ArrayRef<uint8_t> Content, const DecoderParam &Param,
+ bool IsLE)
+ : DataExtractor(Content, IsLE, /*AddressSize=*/0),
+ DataExtractor::Cursor(0), DecoderParam(Param) {}
+
+ bool eof() { return DataExtractor::eof(*this); }
+ uint32_t getU32() { return DataExtractor::getU32(*this); }
+ uint64_t getU64() { return DataExtractor::getU64(*this); }
+ Expected<uint64_t> getULEB128() {
+ uint64_t Result = DataExtractor::getULEB128(*this);
+ if (!*this)
+ return takeError();
+ return Result;
+ }
+ StringRef getBytes(size_t sz) { return DataExtractor::getBytes(*this, sz); }
+};
+
+void CounterTy::encode(raw_ostream &OS) const {
+ std::pair<unsigned, uint64_t> C;
+ if (RefOpt)
+ C = {Ref, *RefOpt};
+ else if (SubOpt)
+ C = {Sub, *SubOpt};
+ else if (AddOpt)
+ C = {Add, *AddOpt};
+ else if (Tag && *Tag == Zero)
+ C = {Zero, 0u};
+ else if (Tag && Val)
+ C = {*Tag, *Val};
+ else
+ llvm_unreachable("Null value cannot be met");
+
+ encodeULEB128(C.first | (C.second << 2), OS);
+}
+
+Error CounterTy::decodeOrTag(DecoderContext &Data) {
+ auto COrErr = Data.getULEB128();
+ if (!COrErr)
+ return COrErr.takeError();
+ auto T = static_cast<TagTy>(*COrErr & 0x03);
+ auto V = (*COrErr >> 2);
+ if (T == Zero) {
+ if (V == 0)
+ Tag = Zero; // w/o Val
+ else
+ Val = V; // w/o Tag
+ } else {
+ if (Data.Raw) {
+ Tag = T;
+ Val = V;
+ } else {
+ switch (T) {
+ case Zero:
+ llvm_unreachable("Zero should be handled in advance");
+ case Ref:
+ RefOpt = V;
+ break;
+ case Sub:
+ SubOpt = V;
+ break;
+ case Add:
+ AddOpt = V;
+ break;
+ }
+ }
+ }
+
+ return Error::success();
+}
+
+Error CounterTy::decode(DecoderContext &Data) {
+ if (auto E = decodeOrTag(Data))
+ return E;
+ if (!this->Tag && this->Val)
+ return make_error<CoverageMapError>(
+ coveragemap_error::malformed,
+ "Counter::Zero shouldn't have the Val: 0x" +
+ Twine::utohexstr(*this->Val));
+ return Error::success();
+}
+
+void DecisionTy::encode(raw_ostream &OS) const {
+ encodeULEB128(BIdx, OS);
+ encodeULEB128(NC, OS);
+}
+
+Error DecisionTy::decode(DecoderContext &Data) {
+ auto BIdxOrErr = Data.getULEB128();
+ if (!BIdxOrErr)
+ return BIdxOrErr.takeError();
+ BIdx = *BIdxOrErr;
+
+ auto NCOrErr = Data.getULEB128();
+ if (!NCOrErr)
+ return NCOrErr.takeError();
+ NC = *NCOrErr;
+
+ return Error::success();
+}
+
+void RecTy::encode(uint64_t &StartLoc, raw_ostream &OS) const {
+ if (Expansion) {
+ encodeULEB128(4 + (*Expansion << 3), OS);
+ } else if (ExtTag && *ExtTag == Skip) {
+ encodeULEB128(2 << 3, OS);
+ } else if (DecisionOpt) {
+ assert(!ExtTag || *ExtTag == Decision);
+ encodeULEB128(5 << 3, OS);
+ DecisionOpt->encode(OS);
+ } else if (MCDC) {
+ assert(!ExtTag || *ExtTag == MCDCBranch);
+ assert(BranchOpt);
+ encodeULEB128(6 << 3, OS);
+ (*BranchOpt)[0].encode(OS);
+ (*BranchOpt)[1].encode(OS);
+ encodeULEB128((*MCDC)[0], OS);
+ encodeULEB128((*MCDC)[1], OS);
+ encodeULEB128((*MCDC)[2], OS);
+ } else if (BranchOpt) {
+ assert(!ExtTag || *ExtTag == Branch);
+ encodeULEB128(4 << 3, OS);
+ (*BranchOpt)[0].encode(OS);
+ (*BranchOpt)[1].encode(OS);
+ } else {
+ // Non-tag CounterTy
+ CounterTy::encode(OS);
+ }
+
+ assert((!isGap || *isGap) && "Don't set isGap=false");
+ uint32_t Gap = (isGap ? (1u << 31) : 0u);
+ if (Loc) {
+ encodeULEB128((*Loc)[0] - StartLoc, OS);
+ encodeULEB128((*Loc)[1], OS);
+ encodeULEB128((*Loc)[2] - (*Loc)[0], OS);
+ encodeULEB128((*Loc)[3] | Gap, OS);
+ StartLoc = (*Loc)[0];
+ } else {
+ encodeULEB128((*dLoc)[0], OS);
+ encodeULEB128((*dLoc)[1], OS);
+ encodeULEB128((*dLoc)[2], OS);
+ encodeULEB128((*dLoc)[3] | Gap, OS);
+ }
+}
+
+Error RecTy::decode(DecoderContext &Data) {
+ auto getU16 = [&]() -> Expected<uint16_t> {
+ auto ValOrErr = Data.getULEB128();
+ if (!ValOrErr)
+ return ValOrErr.takeError();
+ if (*ValOrErr > 0x7FFF + 1)
+ return make_error<CoverageMapError>(coveragemap_error::malformed,
+ "MC/DC index is out of range: 0x" +
+ Twine::utohexstr(*ValOrErr));
+ return static_cast<uint16_t>(*ValOrErr);
+ };
+
+ auto decodeBranch = [&]() -> Error {
+ auto &B = BranchOpt.emplace();
+ if (auto E = B[0].decode(Data))
+ return E;
+ if (auto E = B[1].decode(Data))
+ return E;
+ return Error::success();
+ };
+
+ // Decode tagged CounterTy
+ if (auto E = CounterTy::decodeOrTag(Data))
+ return E;
+ if (!this->Val || this->Tag) {
+ // Compatible to CounterTy
+ } else if (*this->Val & 1u) {
+ Expansion = (*this->Val >> 1);
+ this->Val.reset();
+ } else {
+ auto Tag = *this->Val >> 1;
+ this->Val.reset();
+ switch (Tag) {
+ case Skip:
+ ExtTag = Skip; // w/o Val
+ break;
+ case Decision:
+ if (auto E = DecisionOpt.emplace().decode(Data))
+ return E;
+ if (Data.Raw)
+ ExtTag = Decision;
+ break;
+ case Branch:
+ if (auto E = decodeBranch())
+ return E;
+ if (Data.Raw)
+ ExtTag = Branch;
+ break;
+ case MCDCBranch: {
+ if (auto E = decodeBranch())
+ return E;
+ auto I0OrErr = getU16();
+ if (!I0OrErr)
+ return I0OrErr.takeError();
+ auto I1OrErr = getU16();
+ if (!I1OrErr)
+ return I1OrErr.takeError();
+ auto I2OrErr = getU16();
+ if (!I2OrErr)
+ return I2OrErr.takeError();
+ MCDC = {*I0OrErr, *I1OrErr, *I2OrErr};
+ if (Data.Raw)
+ ExtTag = MCDCBranch;
+ break;
+ }
+ default:
+ return make_error<CoverageMapError>(
+ coveragemap_error::malformed,
+ "Record doesn't have an valid Tag: 0x" + Twine::utohexstr(Tag));
----------------
jh7370 wrote:
```suggestion
"Record doesn't have a valid Tag: 0x" + Twine::utohexstr(Tag));
```
https://github.com/llvm/llvm-project/pull/127432
More information about the llvm-commits
mailing list