1 | //===----------------------- ELFTypesTest.cpp -----------------------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | #include "llvm/Object/ELFTypes.h" |
9 | #include "llvm/Testing/Support/Error.h" |
10 | #include "gtest/gtest.h" |
11 | #include <iostream> |
12 | |
13 | using namespace llvm; |
14 | using namespace llvm::object; |
15 | |
16 | template <typename ELFT> using Elf_Note = typename ELFT::Note; |
17 | |
18 | template <class ELFT> struct NoteTestData { |
19 | std::vector<uint8_t> Data; |
20 | |
21 | const Elf_Note_Impl<ELFT> getElfNote(StringRef Name, uint32_t Type, |
22 | ArrayRef<uint8_t> Desc) { |
23 | constexpr uint64_t Align = 4; |
24 | Data.resize(new_size: alignTo(Value: sizeof(Elf_Nhdr_Impl<ELFT>) + Name.size(), Align) + |
25 | alignTo(Value: Desc.size(), Align), |
26 | x: 0); |
27 | |
28 | Elf_Nhdr_Impl<ELFT> *Nhdr = |
29 | reinterpret_cast<Elf_Nhdr_Impl<ELFT> *>(Data.data()); |
30 | Nhdr->n_namesz = (Name == "" ) ? 0 : Name.size() + 1; |
31 | Nhdr->n_descsz = Desc.size(); |
32 | Nhdr->n_type = Type; |
33 | |
34 | auto NameOffset = Data.begin() + sizeof(*Nhdr); |
35 | std::copy(first: Name.begin(), last: Name.end(), result: NameOffset); |
36 | |
37 | auto DescOffset = |
38 | Data.begin() + alignTo(sizeof(*Nhdr) + Nhdr->n_namesz, Align); |
39 | std::copy(Desc.begin(), Desc.end(), DescOffset); |
40 | |
41 | return Elf_Note_Impl<ELFT>(*Nhdr); |
42 | } |
43 | }; |
44 | |
45 | TEST(ELFTypesTest, NoteTest) { |
46 | static const uint8_t Random[] = {1, 2, 3, 4, 5, 6, 7, 8, 9}; |
47 | ArrayRef<uint8_t> RandomData = ArrayRef(Random); |
48 | NoteTestData<ELF64LE> TestData; |
49 | |
50 | auto Note1 = TestData.getElfNote(Name: StringRef("AMD" ), Type: ELF::NT_AMDGPU_METADATA, |
51 | Desc: RandomData); |
52 | EXPECT_EQ(Note1.getName(), "AMD" ); |
53 | EXPECT_EQ(Note1.getType(), ELF::NT_AMDGPU_METADATA); |
54 | EXPECT_EQ(Note1.getDesc(4), RandomData); |
55 | EXPECT_EQ(Note1.getDescAsStringRef(4), |
56 | StringRef(reinterpret_cast<const char *>(Random), sizeof(Random))); |
57 | |
58 | auto Note2 = TestData.getElfNote(Name: "" , Type: ELF::NT_AMDGPU_METADATA, Desc: RandomData); |
59 | EXPECT_EQ(Note2.getName(), "" ); |
60 | |
61 | auto Note3 = |
62 | TestData.getElfNote(Name: "AMD" , Type: ELF::NT_AMDGPU_METADATA, Desc: ArrayRef<uint8_t>()); |
63 | EXPECT_EQ(Note3.getDescAsStringRef(4), StringRef("" )); |
64 | } |
65 | |
66 | TEST(ELFTypesTest, BBEntryMetadataEncodingTest) { |
67 | const std::array<BBAddrMap::BBEntry::Metadata, 7> Decoded = { |
68 | ._M_elems: {{.HasReturn: false, .HasTailCall: false, .IsEHPad: false, .CanFallThrough: false, .HasIndirectBranch: false}, |
69 | {.HasReturn: true, .HasTailCall: false, .IsEHPad: false, .CanFallThrough: false, .HasIndirectBranch: false}, |
70 | {.HasReturn: false, .HasTailCall: true, .IsEHPad: false, .CanFallThrough: false, .HasIndirectBranch: false}, |
71 | {.HasReturn: false, .HasTailCall: false, .IsEHPad: true, .CanFallThrough: false, .HasIndirectBranch: false}, |
72 | {.HasReturn: false, .HasTailCall: false, .IsEHPad: false, .CanFallThrough: true, .HasIndirectBranch: false}, |
73 | {.HasReturn: false, .HasTailCall: false, .IsEHPad: false, .CanFallThrough: false, .HasIndirectBranch: true}, |
74 | {.HasReturn: true, .HasTailCall: true, .IsEHPad: true, .CanFallThrough: true, .HasIndirectBranch: true}}}; |
75 | const std::array<uint32_t, 7> Encoded = {._M_elems: {0, 1, 2, 4, 8, 16, 31}}; |
76 | for (size_t i = 0; i < Decoded.size(); ++i) |
77 | EXPECT_EQ(Decoded[i].encode(), Encoded[i]); |
78 | for (size_t i = 0; i < Encoded.size(); ++i) { |
79 | Expected<BBAddrMap::BBEntry::Metadata> MetadataOrError = |
80 | BBAddrMap::BBEntry::Metadata::decode(V: Encoded[i]); |
81 | ASSERT_THAT_EXPECTED(MetadataOrError, Succeeded()); |
82 | EXPECT_EQ(*MetadataOrError, Decoded[i]); |
83 | } |
84 | } |
85 | |
86 | TEST(ELFTypesTest, BBEntryMetadataInvalidEncodingTest) { |
87 | const std::array<std::string, 2> Errors = { |
88 | "invalid encoding for BBEntry::Metadata: 0xffff" , |
89 | "invalid encoding for BBEntry::Metadata: 0x100001" }; |
90 | const std::array<uint32_t, 2> Values = {._M_elems: {0xFFFF, 0x100001}}; |
91 | for (size_t i = 0; i < Values.size(); ++i) { |
92 | EXPECT_THAT_ERROR( |
93 | BBAddrMap::BBEntry::Metadata::decode(Values[i]).takeError(), |
94 | FailedWithMessage(Errors[i])); |
95 | } |
96 | } |
97 | |
98 | static_assert( |
99 | std::is_same_v<decltype(PGOAnalysisMap::PGOBBEntry::SuccessorEntry::ID), |
100 | decltype(BBAddrMap::BBEntry::ID)>, |
101 | "PGOAnalysisMap should use the same type for basic block ID as BBAddrMap" ); |
102 | |
103 | TEST(ELFTypesTest, BBAddrMapFeaturesEncodingTest) { |
104 | const std::array<BBAddrMap::Features, 9> Decoded = { |
105 | ._M_elems: {{.FuncEntryCount: false, .BBFreq: false, .BrProb: false, .MultiBBRange: false}, |
106 | {.FuncEntryCount: true, .BBFreq: false, .BrProb: false, .MultiBBRange: false}, |
107 | {.FuncEntryCount: false, .BBFreq: true, .BrProb: false, .MultiBBRange: false}, |
108 | {.FuncEntryCount: false, .BBFreq: false, .BrProb: true, .MultiBBRange: false}, |
109 | {.FuncEntryCount: false, .BBFreq: false, .BrProb: false, .MultiBBRange: true}, |
110 | {.FuncEntryCount: true, .BBFreq: true, .BrProb: false, .MultiBBRange: false}, |
111 | {.FuncEntryCount: false, .BBFreq: true, .BrProb: true, .MultiBBRange: false}, |
112 | {.FuncEntryCount: false, .BBFreq: true, .BrProb: true, .MultiBBRange: true}, |
113 | {.FuncEntryCount: true, .BBFreq: true, .BrProb: true, .MultiBBRange: true}}}; |
114 | const std::array<uint8_t, 9> Encoded = { |
115 | ._M_elems: {0b0000, 0b0001, 0b0010, 0b0100, 0b1000, 0b0011, 0b0110, 0b1110, 0b1111}}; |
116 | for (const auto &[Feat, EncodedVal] : llvm::zip(t: Decoded, u: Encoded)) |
117 | EXPECT_EQ(Feat.encode(), EncodedVal); |
118 | for (const auto &[Feat, EncodedVal] : llvm::zip(t: Decoded, u: Encoded)) { |
119 | Expected<BBAddrMap::Features> FeatEnableOrError = |
120 | BBAddrMap::Features::decode(Val: EncodedVal); |
121 | ASSERT_THAT_EXPECTED(FeatEnableOrError, Succeeded()); |
122 | EXPECT_EQ(*FeatEnableOrError, Feat); |
123 | } |
124 | } |
125 | |
126 | TEST(ELFTypesTest, BBAddrMapFeaturesInvalidEncodingTest) { |
127 | const std::array<std::string, 2> Errors = { |
128 | "invalid encoding for BBAddrMap::Features: 0x10" , |
129 | "invalid encoding for BBAddrMap::Features: 0xff" }; |
130 | const std::array<uint8_t, 2> Values = {._M_elems: {0b10000, 0b1111'1111}}; |
131 | for (const auto &[Val, Error] : llvm::zip(t: Values, u: Errors)) { |
132 | EXPECT_THAT_ERROR(BBAddrMap::Features::decode(Val).takeError(), |
133 | FailedWithMessage(Error)); |
134 | } |
135 | } |
136 | |