-
Notifications
You must be signed in to change notification settings - Fork 10.4k
/
Copy pathBitPatternBuilder.h
170 lines (152 loc) · 5.67 KB
/
BitPatternBuilder.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
//===--- BitPatternBuilder.h - Create masks for composite types -----------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2019 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
#pragma once
#include "swift/Basic/ClusteredBitVector.h"
#include "llvm/ADT/APInt.h"
#include "llvm/ADT/SmallVector.h"
#include <optional>
namespace swift {
namespace irgen {
/// BitPatternBuilder is a class to help with the construction of
/// bit masks for composite types. The class should be constructed
/// using the byte order of the target platform. Elements added
/// to the class must mask an entire element in a composite type.
/// These elements must be byte aligned. For example, if you want
/// to add a 64-bit integer to the bit pattern with the low 32
/// bits set to 1 and the high 32 bits set to 0 then you must create
/// a 64-bit APInt and append it in its entirety rather than calling
/// the appendSetBits and appendClearBits helper functions which
/// would not be portable across architectures using different byte
/// orders.
///
/// Example construction of a mask for a struct:
///
/// // Type T that we are generating a mask for:
/// struct T {
/// uint8_t a;
/// uint8_t b;
/// uint16_t c;
/// };
///
/// // Code to generate the mask:
/// auto mask = BitPatternBuilder(isLittleEndian());
/// mask.appendSetBits(8); // mask T.a with 0xff
/// mask.appendClearBits(8); // mask T.b with 0x00
/// mask.append(APInt(16, 0x1177ULL)); // mask T.c with 0x1177
///
/// // Little-endian result:
/// mask.build(); // 0x117700ff [ ff 00 77 11 ]
///
/// // Big-endian result:
/// mask.build(); // 0xff001177 [ ff 00 11 77 ]
///
class BitPatternBuilder {
using APInt = llvm::APInt;
// An array of masks that, when combined, will form the mask for a
// composite value. Generally these correspond to elements in a
// struct (or class, tuple etc.).
llvm::SmallVector<APInt, 8> Elements;
// Little-endian byte order implies that elements should be
// appended to the most significant bit. If this flag is false
// then elements should be appended to the least signficant
// bit (big-endian byte order).
bool LittleEndian;
// The combined size of the elements added so far in bits.
unsigned Size = 0;
public:
/// Create a new BitPatternBuilder with either a little-endian
/// (true) or big-endian (false) byte order.
BitPatternBuilder(bool littleEndian) : LittleEndian(littleEndian) {}
/// Append the given mask to the bit pattern. The mask should mask
/// an entire element type and be byte aligned.
void append(const APInt &value) {
assert(value.getBitWidth() % 8 == 0);
Size += value.getBitWidth();
Elements.push_back(value);
}
/// Append the given mask to the bit pattern. The mask should mask
/// an entire element type and be byte aligned.
void append(APInt &&value) {
assert(value.getBitWidth() % 8 == 0);
Size += value.getBitWidth();
Elements.push_back(std::move(value));
}
/// Append the given mask to the bit pattern. The mask should mask
/// an entire element type and be byte aligned.
void append(const ClusteredBitVector &value) {
assert(value.size() % 8 == 0);
if (!value.empty()) {
Size += value.size();
Elements.push_back(value.asAPInt());
}
}
/// Append the given number of set (1) bits to the bit pattern. The
/// number of bits must be a multiple of 8 and mask a whole number
/// of element types.
void appendSetBits(unsigned numBits) {
assert(numBits % 8 == 0);
if (numBits) {
Size += numBits;
Elements.push_back(APInt::getAllOnes(numBits));
}
}
/// Append the given number of clear (0) bits to the bit pattern. The
/// number of bits must be a multiple of 8 and mask a whole number
/// of element types.
void appendClearBits(unsigned numBits) {
assert(numBits % 8 == 0);
if (numBits) {
Size += numBits;
Elements.push_back(APInt::getZero(numBits));
}
}
/// Append set (1) bits to the bit pattern until it reaches the
/// given size in bits. The total number of bits must be a
/// multiple of 8.
void padWithSetBitsTo(unsigned totalSizeInBits) {
assert(totalSizeInBits % 8 == 0);
assert(totalSizeInBits >= Size);
appendSetBits(totalSizeInBits - Size);
}
/// Append clear (0) bits to the bit pattern until it reaches the
/// given size in bits. The total number of bits must be a
/// multiple of 8.
void padWithClearBitsTo(unsigned totalSizeInBits) {
assert(totalSizeInBits % 8 == 0);
assert(totalSizeInBits >= Size);
appendClearBits(totalSizeInBits - Size);
}
/// Build the complete mask for the composite type. If the mask has a
/// length of 0 then the optional will not contain a value. Otherwise
/// the option will contain a value that is the combined length of
/// the elements appended to the builder. The mask represents is an
/// integer in the target byte order.
std::optional<APInt> build() const {
if (Size == 0) {
return std::optional<APInt>();
}
auto result = APInt::getZero(Size);
unsigned offset = 0;
for (const auto &e : Elements) {
unsigned index = offset;
if (!LittleEndian) {
index = Size - offset - e.getBitWidth();
}
result.insertBits(e, index);
offset += e.getBitWidth();
}
assert(offset == Size);
return result;
}
};
} // end namespace irgen
} // end namespace swift