[SHT_LLVM_BB_ADDR_MAP] Add an option to skip emitting bb entries (#114447)
Sometimes we want to use a `PgoAnalysisMap` feature that doesn't require the BB entries info, e.g. only the `FuncEntryCount`, but the BB entries is emitted by default, so I'm adding an option to skip the info for this case to save the binary size(can save ~90% size of the section). For implementation, it extends a new field(`OmitBBEntries`) in `BBAddrMap::Features` for this and it's controlled by a switch `--basic-block-address-map-skip-bb-entries`. Note that this naturally supports backwards compatibility as the field is zero for the old version, matches the decoding in the new version llvm.
This commit is contained in:
@@ -830,6 +830,7 @@ struct BBAddrMap {
|
||||
bool BBFreq : 1;
|
||||
bool BrProb : 1;
|
||||
bool MultiBBRange : 1;
|
||||
bool OmitBBEntries : 1;
|
||||
|
||||
bool hasPGOAnalysis() const { return FuncEntryCount || BBFreq || BrProb; }
|
||||
|
||||
@@ -840,7 +841,8 @@ struct BBAddrMap {
|
||||
return (static_cast<uint8_t>(FuncEntryCount) << 0) |
|
||||
(static_cast<uint8_t>(BBFreq) << 1) |
|
||||
(static_cast<uint8_t>(BrProb) << 2) |
|
||||
(static_cast<uint8_t>(MultiBBRange) << 3);
|
||||
(static_cast<uint8_t>(MultiBBRange) << 3) |
|
||||
(static_cast<uint8_t>(OmitBBEntries) << 4);
|
||||
}
|
||||
|
||||
// Decodes from minimum bit width representation and validates no
|
||||
@@ -848,7 +850,8 @@ struct BBAddrMap {
|
||||
static Expected<Features> decode(uint8_t Val) {
|
||||
Features Feat{
|
||||
static_cast<bool>(Val & (1 << 0)), static_cast<bool>(Val & (1 << 1)),
|
||||
static_cast<bool>(Val & (1 << 2)), static_cast<bool>(Val & (1 << 3))};
|
||||
static_cast<bool>(Val & (1 << 2)), static_cast<bool>(Val & (1 << 3)),
|
||||
static_cast<bool>(Val & (1 << 4))};
|
||||
if (Feat.encode() != Val)
|
||||
return createStringError(
|
||||
std::error_code(), "invalid encoding for BBAddrMap::Features: 0x%x",
|
||||
@@ -857,9 +860,10 @@ struct BBAddrMap {
|
||||
}
|
||||
|
||||
bool operator==(const Features &Other) const {
|
||||
return std::tie(FuncEntryCount, BBFreq, BrProb, MultiBBRange) ==
|
||||
return std::tie(FuncEntryCount, BBFreq, BrProb, MultiBBRange,
|
||||
OmitBBEntries) ==
|
||||
std::tie(Other.FuncEntryCount, Other.BBFreq, Other.BrProb,
|
||||
Other.MultiBBRange);
|
||||
Other.MultiBBRange, Other.OmitBBEntries);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -161,6 +161,13 @@ static cl::bits<PGOMapFeaturesEnum> PgoAnalysisMapFeatures(
|
||||
"Enable extended information within the SHT_LLVM_BB_ADDR_MAP that is "
|
||||
"extracted from PGO related analysis."));
|
||||
|
||||
static cl::opt<bool> BBAddrMapSkipEmitBBEntries(
|
||||
"basic-block-address-map-skip-bb-entries",
|
||||
cl::desc("Skip emitting basic block entries in the SHT_LLVM_BB_ADDR_MAP "
|
||||
"section. It's used to save binary size when BB entries are "
|
||||
"unnecessary for some PGOAnalysisMap features."),
|
||||
cl::Hidden, cl::init(false));
|
||||
|
||||
static cl::opt<bool> EmitJumpTableSizesSection(
|
||||
"emit-jump-table-sizes-section",
|
||||
cl::desc("Emit a section containing jump table addresses and sizes"),
|
||||
@@ -1411,8 +1418,15 @@ getBBAddrMapFeature(const MachineFunction &MF, int NumMBBSectionRanges) {
|
||||
bool BrProbEnabled =
|
||||
AllFeatures ||
|
||||
(!NoFeatures && PgoAnalysisMapFeatures.isSet(PGOMapFeaturesEnum::BrProb));
|
||||
|
||||
if ((BBFreqEnabled || BrProbEnabled) && BBAddrMapSkipEmitBBEntries) {
|
||||
MF.getFunction().getContext().emitError(
|
||||
"BB entries info is required for BBFreq and BrProb "
|
||||
"features");
|
||||
}
|
||||
return {FuncEntryCountEnabled, BBFreqEnabled, BrProbEnabled,
|
||||
MF.hasBBSections() && NumMBBSectionRanges > 1};
|
||||
MF.hasBBSections() && NumMBBSectionRanges > 1,
|
||||
static_cast<bool>(BBAddrMapSkipEmitBBEntries)};
|
||||
}
|
||||
|
||||
void AsmPrinter::emitBBAddrMapSection(const MachineFunction &MF) {
|
||||
@@ -1469,24 +1483,28 @@ void AsmPrinter::emitBBAddrMapSection(const MachineFunction &MF) {
|
||||
OutStreamer->emitULEB128IntValue(MBBSectionNumBlocks[MBB.getSectionID()]);
|
||||
PrevMBBEndSymbol = MBBSymbol;
|
||||
}
|
||||
// TODO: Remove this check when version 1 is deprecated.
|
||||
if (BBAddrMapVersion > 1) {
|
||||
OutStreamer->AddComment("BB id");
|
||||
// Emit the BB ID for this basic block.
|
||||
// We only emit BaseID since CloneID is unset for
|
||||
// -basic-block-adress-map.
|
||||
// TODO: Emit the full BBID when labels and sections can be mixed
|
||||
// together.
|
||||
OutStreamer->emitULEB128IntValue(MBB.getBBID()->BaseID);
|
||||
|
||||
if (!Features.OmitBBEntries) {
|
||||
// TODO: Remove this check when version 1 is deprecated.
|
||||
if (BBAddrMapVersion > 1) {
|
||||
OutStreamer->AddComment("BB id");
|
||||
// Emit the BB ID for this basic block.
|
||||
// We only emit BaseID since CloneID is unset for
|
||||
// -basic-block-adress-map.
|
||||
// TODO: Emit the full BBID when labels and sections can be mixed
|
||||
// together.
|
||||
OutStreamer->emitULEB128IntValue(MBB.getBBID()->BaseID);
|
||||
}
|
||||
// Emit the basic block offset relative to the end of the previous block.
|
||||
// This is zero unless the block is padded due to alignment.
|
||||
emitLabelDifferenceAsULEB128(MBBSymbol, PrevMBBEndSymbol);
|
||||
// Emit the basic block size. When BBs have alignments, their size cannot
|
||||
// always be computed from their offsets.
|
||||
emitLabelDifferenceAsULEB128(MBB.getEndSymbol(), MBBSymbol);
|
||||
// Emit the Metadata.
|
||||
OutStreamer->emitULEB128IntValue(getBBAddrMapMetadata(MBB));
|
||||
}
|
||||
// Emit the basic block offset relative to the end of the previous block.
|
||||
// This is zero unless the block is padded due to alignment.
|
||||
emitLabelDifferenceAsULEB128(MBBSymbol, PrevMBBEndSymbol);
|
||||
// Emit the basic block size. When BBs have alignments, their size cannot
|
||||
// always be computed from their offsets.
|
||||
emitLabelDifferenceAsULEB128(MBB.getEndSymbol(), MBBSymbol);
|
||||
// Emit the Metadata.
|
||||
OutStreamer->emitULEB128IntValue(getBBAddrMapMetadata(MBB));
|
||||
|
||||
PrevMBBEndSymbol = MBB.getEndSymbol();
|
||||
}
|
||||
|
||||
|
||||
@@ -851,29 +851,31 @@ decodeBBAddrMapImpl(const ELFFile<ELFT> &EF,
|
||||
NumBlocksInBBRange = readULEB128As<uint32_t>(Data, Cur, ULEBSizeErr);
|
||||
}
|
||||
std::vector<BBAddrMap::BBEntry> BBEntries;
|
||||
for (uint32_t BlockIndex = 0; !MetadataDecodeErr && !ULEBSizeErr && Cur &&
|
||||
(BlockIndex < NumBlocksInBBRange);
|
||||
++BlockIndex) {
|
||||
uint32_t ID = Version >= 2
|
||||
? readULEB128As<uint32_t>(Data, Cur, ULEBSizeErr)
|
||||
: BlockIndex;
|
||||
uint32_t Offset = readULEB128As<uint32_t>(Data, Cur, ULEBSizeErr);
|
||||
uint32_t Size = readULEB128As<uint32_t>(Data, Cur, ULEBSizeErr);
|
||||
uint32_t MD = readULEB128As<uint32_t>(Data, Cur, ULEBSizeErr);
|
||||
if (Version >= 1) {
|
||||
// Offset is calculated relative to the end of the previous BB.
|
||||
Offset += PrevBBEndOffset;
|
||||
PrevBBEndOffset = Offset + Size;
|
||||
if (!FeatEnable.OmitBBEntries) {
|
||||
for (uint32_t BlockIndex = 0; !MetadataDecodeErr && !ULEBSizeErr &&
|
||||
Cur && (BlockIndex < NumBlocksInBBRange);
|
||||
++BlockIndex) {
|
||||
uint32_t ID = Version >= 2
|
||||
? readULEB128As<uint32_t>(Data, Cur, ULEBSizeErr)
|
||||
: BlockIndex;
|
||||
uint32_t Offset = readULEB128As<uint32_t>(Data, Cur, ULEBSizeErr);
|
||||
uint32_t Size = readULEB128As<uint32_t>(Data, Cur, ULEBSizeErr);
|
||||
uint32_t MD = readULEB128As<uint32_t>(Data, Cur, ULEBSizeErr);
|
||||
if (Version >= 1) {
|
||||
// Offset is calculated relative to the end of the previous BB.
|
||||
Offset += PrevBBEndOffset;
|
||||
PrevBBEndOffset = Offset + Size;
|
||||
}
|
||||
Expected<BBAddrMap::BBEntry::Metadata> MetadataOrErr =
|
||||
BBAddrMap::BBEntry::Metadata::decode(MD);
|
||||
if (!MetadataOrErr) {
|
||||
MetadataDecodeErr = MetadataOrErr.takeError();
|
||||
break;
|
||||
}
|
||||
BBEntries.push_back({ID, Offset, Size, *MetadataOrErr});
|
||||
}
|
||||
Expected<BBAddrMap::BBEntry::Metadata> MetadataOrErr =
|
||||
BBAddrMap::BBEntry::Metadata::decode(MD);
|
||||
if (!MetadataOrErr) {
|
||||
MetadataDecodeErr = MetadataOrErr.takeError();
|
||||
break;
|
||||
}
|
||||
BBEntries.push_back({ID, Offset, Size, *MetadataOrErr});
|
||||
TotalNumBlocks += BBEntries.size();
|
||||
}
|
||||
TotalNumBlocks += BBEntries.size();
|
||||
BBRangeEntries.push_back({RangeBaseAddress, std::move(BBEntries)});
|
||||
}
|
||||
FunctionEntries.push_back({std::move(BBRangeEntries)});
|
||||
|
||||
@@ -1497,7 +1497,7 @@ void ELFState<ELFT>::writeSectionContent(
|
||||
BBR.NumBlocks.value_or(BBR.BBEntries ? BBR.BBEntries->size() : 0);
|
||||
SHeader.sh_size += sizeof(uintX_t) + CBA.writeULEB128(NumBlocks);
|
||||
// Write all BBEntries in this BBRange.
|
||||
if (!BBR.BBEntries)
|
||||
if (!BBR.BBEntries || FeatureOrErr->OmitBBEntries)
|
||||
continue;
|
||||
for (const ELFYAML::BBAddrMapEntry::BBEntry &BBE : *BBR.BBEntries) {
|
||||
++TotalNumBlocks;
|
||||
|
||||
@@ -11,6 +11,10 @@
|
||||
; RUN: llc < %s -mtriple=x86_64 -function-sections -unique-section-names=true -basic-block-address-map -pgo-analysis-map=bb-freq | FileCheck %s --check-prefixes=CHECK,PGO-BBF,BBF-ONLY
|
||||
; RUN: llc < %s -mtriple=x86_64 -function-sections -unique-section-names=true -basic-block-address-map -pgo-analysis-map=br-prob | FileCheck %s --check-prefixes=CHECK,PGO-BRP,BRP-ONLY
|
||||
|
||||
; RUN: llc < %s -mtriple=x86_64 -function-sections -unique-section-names=true -basic-block-address-map -pgo-analysis-map=func-entry-count -basic-block-address-map-skip-bb-entries | FileCheck %s --check-prefixes=SKIP-BB-ENTRIES
|
||||
; RUN: not llc < %s -mtriple=x86_64 -function-sections -unique-section-names=true -basic-block-address-map -pgo-analysis-map=bb-freq -basic-block-address-map-skip-bb-entries 2>&1 | FileCheck %s --check-prefixes=SKIP-BB-ENTRIES-ERROR
|
||||
; RUN: not llc < %s -mtriple=x86_64 -function-sections -unique-section-names=true -basic-block-address-map -pgo-analysis-map=br-prob -basic-block-address-map-skip-bb-entries 2>&1 | FileCheck %s --check-prefixes=SKIP-BB-ENTRIES-ERROR
|
||||
|
||||
;; Verify that we emit an error if we try and specify values in addition to all/none
|
||||
; RUN: not llc < %s -mtriple=x86_64 -basic-block-address-map -pgo-analysis-map=all,bb-freq
|
||||
; RUN: not llc < %s -mtriple=x86_64 -basic-block-address-map -pgo-analysis-map=none,bb-freq
|
||||
@@ -134,3 +138,10 @@ declare i32 @__gxx_personality_v0(...)
|
||||
; PGO-BRP-NEXT: .byte 5 # successor BB ID
|
||||
; PGO-BRP-NEXT: .ascii "\200\200\200\200\b" # successor branch probability
|
||||
|
||||
; SKIP-BB-ENTRIES: .byte 17 # feature
|
||||
; SKIP-BB-ENTRIES-NEXT: .quad .Lfunc_begin0 # function address
|
||||
; SKIP-BB-ENTRIES-NEXT: .byte 6 # number of basic blocks
|
||||
; SKIP-BB-ENTRIES-NEXT: .byte 100 # function entry count
|
||||
; SKIP-BB-ENTRIES-NOT: # BB id
|
||||
|
||||
; SKIP-BB-ENTRIES-ERROR: error: BB entries info is required for BBFreq and BrProb features
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
## This test checks how llvm-readobj prints skipped BB entries (-basic-block-address-map-skip-emit-bb-entries).
|
||||
|
||||
## Check 64-bit:
|
||||
# RUN: yaml2obj %s -DBITS=64 -o %t1.x64.o
|
||||
# RUN: llvm-readobj %t1.x64.o --bb-addr-map 2>&1 | FileCheck --match-full-lines %s -DFILE=%t1.x64.o
|
||||
|
||||
## Check 32-bit:
|
||||
# RUN: yaml2obj %s -DBITS=32 -o %t1.x32.o
|
||||
# RUN: llvm-readobj %t1.x32.o --bb-addr-map 2>&1 | FileCheck --match-full-lines %s -DFILE=%t1.x32.o
|
||||
|
||||
# CHECK: BBAddrMap [
|
||||
# CHECK-NEXT: Function {
|
||||
# CHECK-NEXT: At: 0x11111
|
||||
# CHECK-NEXT: Name: foo
|
||||
# CHECK-NEXT: BB Ranges [
|
||||
# CHECK-NEXT: {
|
||||
# CHECK-NEXT: Base Address: 0x11111
|
||||
# CHECK-NEXT: BB Entries [
|
||||
# CHECK-NEXT: ]
|
||||
# CHECK-NEXT: }
|
||||
# CHECK-NEXT: ]
|
||||
# CHECK-NEXT: PGO analyses {
|
||||
# CHECK-NEXT: FuncEntryCount: 100
|
||||
# CHECK-NEXT: PGO BB entries [
|
||||
# CHECK-NEXT: ]
|
||||
# CHECK-NEXT: }
|
||||
# CHECK-NEXT: }
|
||||
# CHECK-NEXT:]
|
||||
# CHECK-NEXT:BBAddrMap [
|
||||
# CHECK-NEXT: Function {
|
||||
# CHECK-NEXT: At: 0x33333
|
||||
# CHECK-NEXT: Name: bar
|
||||
# CHECK-NEXT: BB Ranges [
|
||||
# CHECK-NEXT: {
|
||||
# CHECK-NEXT: Base Address: 0x33333
|
||||
# CHECK-NEXT: BB Entries [
|
||||
# CHECK-NEXT: ]
|
||||
# CHECK-NEXT: }
|
||||
# CHECK-NEXT: ]
|
||||
# CHECK-NEXT: PGO analyses {
|
||||
# CHECK-NEXT: FuncEntryCount: 89
|
||||
# CHECK-NEXT: PGO BB entries [
|
||||
# CHECK-NEXT: ]
|
||||
# CHECK-NEXT: }
|
||||
# CHECK-NEXT: }
|
||||
# CHECK-NEXT:]
|
||||
|
||||
--- !ELF
|
||||
FileHeader:
|
||||
Class: ELFCLASS[[BITS]]
|
||||
Data: ELFDATA2LSB
|
||||
Type: ET_EXEC
|
||||
Sections:
|
||||
- Name: .text
|
||||
Type: SHT_PROGBITS
|
||||
Flags: [SHF_ALLOC]
|
||||
- Name: .text.bar
|
||||
Type: SHT_PROGBITS
|
||||
Flags: [SHF_ALLOC]
|
||||
- Name: .llvm_bb_addr_map
|
||||
Type: SHT_LLVM_BB_ADDR_MAP
|
||||
ShSize: [[SIZE=<none>]]
|
||||
Link: .text
|
||||
Entries:
|
||||
- Version: 2
|
||||
Feature: 0x17
|
||||
BBRanges:
|
||||
- BaseAddress: 0x11111
|
||||
PGOAnalyses:
|
||||
- FuncEntryCount: 100
|
||||
- Name: '.llvm_bb_addr_map2'
|
||||
Type: SHT_LLVM_BB_ADDR_MAP
|
||||
Link: .text.bar
|
||||
Entries:
|
||||
- Version: 2
|
||||
Feature: 0x17
|
||||
BBRanges:
|
||||
- BaseAddress: 0x33333
|
||||
PGOAnalyses:
|
||||
- FuncEntryCount: 89
|
||||
Symbols:
|
||||
- Name: foo
|
||||
Section: .text
|
||||
Type: STT_FUNC
|
||||
Value: 0x11111
|
||||
- Name: bar
|
||||
Section: .text.bar
|
||||
Type: STT_FUNC
|
||||
Value: 0x33333
|
||||
@@ -66,7 +66,7 @@ Sections:
|
||||
|
||||
## Check that yaml2obj generates a warning when we use unsupported feature.
|
||||
# RUN: yaml2obj --docnum=2 %s 2>&1 | FileCheck %s --check-prefix=INVALID-FEATURE
|
||||
# INVALID-FEATURE: warning: invalid encoding for BBAddrMap::Features: 0xff
|
||||
# INVALID-FEATURE: warning: invalid encoding for BBAddrMap::Features: 0xf0
|
||||
|
||||
--- !ELF
|
||||
FileHeader:
|
||||
@@ -79,5 +79,4 @@ Sections:
|
||||
Entries:
|
||||
- Version: 2
|
||||
## Specify unsupported feature
|
||||
Feature: 0xFF
|
||||
|
||||
Feature: 0xF0
|
||||
|
||||
@@ -1148,11 +1148,11 @@ Sections:
|
||||
|
||||
BBAddrMap E1 = {
|
||||
{{0x11111, {{1, 0x0, 0x1, {false, true, false, false, false}}}}}};
|
||||
PGOAnalysisMap P1 = {892, {}, {true, false, false, false}};
|
||||
PGOAnalysisMap P1 = {892, {}, {true, false, false, false, false}};
|
||||
BBAddrMap E2 = {
|
||||
{{0x22222, {{2, 0x0, 0x2, {false, false, true, false, false}}}}}};
|
||||
PGOAnalysisMap P2 = {
|
||||
{}, {{BlockFrequency(343), {}}}, {false, true, false, false}};
|
||||
{}, {{BlockFrequency(343), {}}}, {false, true, false, false, false}};
|
||||
BBAddrMap E3 = {{{0x33333,
|
||||
{{0, 0x0, 0x3, {false, true, true, false, false}},
|
||||
{1, 0x3, 0x3, {false, false, true, false, false}},
|
||||
@@ -1163,7 +1163,7 @@ Sections:
|
||||
{2, BranchProbability::getRaw(0xeeee'eeee)}}},
|
||||
{{}, {{2, BranchProbability::getRaw(0xffff'ffff)}}},
|
||||
{{}, {}}},
|
||||
{false, false, true, false}};
|
||||
{false, false, true, false, false}};
|
||||
BBAddrMap E4 = {{{0x44444,
|
||||
{{0, 0x0, 0x4, {false, false, false, true, true}},
|
||||
{1, 0x4, 0x4, {false, false, false, false, false}},
|
||||
@@ -1180,10 +1180,10 @@ Sections:
|
||||
{3, BranchProbability::getRaw(0xeeee'eeee)}}},
|
||||
{BlockFrequency(18), {{3, BranchProbability::getRaw(0xffff'ffff)}}},
|
||||
{BlockFrequency(1000), {}}},
|
||||
{true, true, true, false}};
|
||||
{true, true, true, false, false}};
|
||||
BBAddrMap E5 = {
|
||||
{{0x55555, {{2, 0x0, 0x2, {false, false, true, false, false}}}}}};
|
||||
PGOAnalysisMap P5 = {{}, {}, {false, false, false, false}};
|
||||
PGOAnalysisMap P5 = {{}, {}, {false, false, false, false, false}};
|
||||
BBAddrMap E6 = {
|
||||
{{0x66666,
|
||||
{{0, 0x0, 0x6, {false, true, true, false, false}},
|
||||
@@ -1195,7 +1195,7 @@ Sections:
|
||||
{2, BranchProbability::getRaw(0xcccc'cccc)}}},
|
||||
{{}, {{2, BranchProbability::getRaw(0x8888'8888)}}},
|
||||
{{}, {}}},
|
||||
{false, false, true, true}};
|
||||
{false, false, true, true, false}};
|
||||
|
||||
std::vector<BBAddrMap> Section0BBAddrMaps = {E4, E5, E6};
|
||||
std::vector<BBAddrMap> Section1BBAddrMaps = {E3};
|
||||
|
||||
@@ -102,15 +102,15 @@ static_assert(
|
||||
|
||||
TEST(ELFTypesTest, BBAddrMapFeaturesEncodingTest) {
|
||||
const std::array<BBAddrMap::Features, 9> Decoded = {
|
||||
{{false, false, false, false},
|
||||
{true, false, false, false},
|
||||
{false, true, false, false},
|
||||
{false, false, true, false},
|
||||
{false, false, false, true},
|
||||
{true, true, false, false},
|
||||
{false, true, true, false},
|
||||
{false, true, true, true},
|
||||
{true, true, true, true}}};
|
||||
{{false, false, false, false, false},
|
||||
{true, false, false, false, false},
|
||||
{false, true, false, false, false},
|
||||
{false, false, true, false, false},
|
||||
{false, false, false, true, false},
|
||||
{true, true, false, false, false},
|
||||
{false, true, true, false, false},
|
||||
{false, true, true, true, false},
|
||||
{true, true, true, true, false}}};
|
||||
const std::array<uint8_t, 9> Encoded = {
|
||||
{0b0000, 0b0001, 0b0010, 0b0100, 0b1000, 0b0011, 0b0110, 0b1110, 0b1111}};
|
||||
for (const auto &[Feat, EncodedVal] : llvm::zip(Decoded, Encoded))
|
||||
@@ -125,9 +125,9 @@ TEST(ELFTypesTest, BBAddrMapFeaturesEncodingTest) {
|
||||
|
||||
TEST(ELFTypesTest, BBAddrMapFeaturesInvalidEncodingTest) {
|
||||
const std::array<std::string, 2> Errors = {
|
||||
"invalid encoding for BBAddrMap::Features: 0x10",
|
||||
"invalid encoding for BBAddrMap::Features: 0xff"};
|
||||
const std::array<uint8_t, 2> Values = {{0b10000, 0b1111'1111}};
|
||||
"invalid encoding for BBAddrMap::Features: 0x20",
|
||||
"invalid encoding for BBAddrMap::Features: 0xf0"};
|
||||
const std::array<uint8_t, 2> Values = {{0b10'0000, 0b1111'0000}};
|
||||
for (const auto &[Val, Error] : llvm::zip(Values, Errors)) {
|
||||
EXPECT_THAT_ERROR(BBAddrMap::Features::decode(Val).takeError(),
|
||||
FailedWithMessage(Error));
|
||||
|
||||
Reference in New Issue
Block a user