File indexing completed on 2026-05-10 08:43:22
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030 #ifndef LLVM_BITCODE_BITCODECONVENIENCE_H
0031 #define LLVM_BITCODE_BITCODECONVENIENCE_H
0032
0033 #include "llvm/Bitstream/BitCodes.h"
0034 #include "llvm/Bitstream/BitstreamWriter.h"
0035 #include <cstdint>
0036 #include <optional>
0037
0038 namespace llvm {
0039 namespace detail {
0040
0041
0042
0043 template <bool Compound = false> class BCField {
0044 public:
0045 static const bool IsCompound = Compound;
0046
0047
0048 template <typename T> static void assertValid(const T &data) {}
0049
0050
0051
0052 template <typename T> static T convert(T rawValue) { return rawValue; }
0053 };
0054 }
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064 template <uint64_t Value> class BCLiteral : public detail::BCField<> {
0065 public:
0066 static void emitOp(llvm::BitCodeAbbrev &abbrev) {
0067 abbrev.Add(llvm::BitCodeAbbrevOp(Value));
0068 }
0069
0070 template <typename T> static void assertValid(const T &data) {
0071 assert(data == Value && "data value does not match declared literal value");
0072 }
0073 };
0074
0075
0076
0077
0078 template <unsigned Width> class BCFixed : public detail::BCField<> {
0079 public:
0080 static_assert(Width <= 64, "fixed-width field is too large");
0081
0082 static void emitOp(llvm::BitCodeAbbrev &abbrev) {
0083 abbrev.Add(llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Fixed, Width));
0084 }
0085
0086 static void assertValid(const bool &data) {
0087 assert(llvm::isUInt<Width>(data) &&
0088 "data value does not fit in the given bit width");
0089 }
0090
0091 template <typename T> static void assertValid(const T &data) {
0092 assert(data >= 0 && "cannot encode signed integers");
0093 assert(llvm::isUInt<Width>(data) &&
0094 "data value does not fit in the given bit width");
0095 }
0096 };
0097
0098
0099
0100
0101
0102
0103 template <unsigned Width> class BCVBR : public detail::BCField<> {
0104 static_assert(Width >= 2, "width does not have room for continuation bit");
0105
0106 public:
0107 static void emitOp(llvm::BitCodeAbbrev &abbrev) {
0108 abbrev.Add(llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::VBR, Width));
0109 }
0110
0111 template <typename T> static void assertValid(const T &data) {
0112 assert(data >= 0 && "cannot encode signed integers");
0113 }
0114 };
0115
0116
0117
0118
0119
0120
0121
0122 class BCChar6 : public detail::BCField<> {
0123 public:
0124 static void emitOp(llvm::BitCodeAbbrev &abbrev) {
0125 abbrev.Add(llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Char6));
0126 }
0127
0128 template <typename T> static void assertValid(const T &data) {
0129 assert(llvm::BitCodeAbbrevOp::isChar6(data) && "invalid Char6 data");
0130 }
0131
0132 template <typename T> char convert(T rawValue) {
0133 return static_cast<char>(rawValue);
0134 }
0135 };
0136
0137
0138
0139
0140 class BCBlob : public detail::BCField<true> {
0141 public:
0142 static void emitOp(llvm::BitCodeAbbrev &abbrev) {
0143 abbrev.Add(llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Blob));
0144 }
0145 };
0146
0147
0148
0149
0150 template <typename ElementTy> class BCArray : public detail::BCField<true> {
0151 static_assert(!ElementTy::IsCompound, "arrays can only contain scalar types");
0152
0153 public:
0154 static void emitOp(llvm::BitCodeAbbrev &abbrev) {
0155 abbrev.Add(llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Array));
0156 ElementTy::emitOp(abbrev);
0157 }
0158 };
0159
0160 namespace detail {
0161
0162
0163
0164
0165
0166 template <typename FieldTy> static void emitOps(llvm::BitCodeAbbrev &abbrev) {
0167 FieldTy::emitOp(abbrev);
0168 }
0169
0170
0171
0172
0173
0174
0175 template <typename FieldTy, typename Next, typename... Rest>
0176 static void emitOps(llvm::BitCodeAbbrev &abbrev) {
0177 static_assert(!FieldTy::IsCompound,
0178 "arrays and blobs may not appear in the middle of a record");
0179 FieldTy::emitOp(abbrev);
0180 emitOps<Next, Rest...>(abbrev);
0181 }
0182
0183
0184
0185
0186 template <typename ElementTy, typename... Fields> class BCRecordCoding {
0187 public:
0188 template <typename BufferTy, typename ElementDataTy, typename... DataTy>
0189 static void emit(llvm::BitstreamWriter &Stream, BufferTy &buffer,
0190 unsigned code, ElementDataTy element, DataTy &&...data) {
0191 static_assert(!ElementTy::IsCompound,
0192 "arrays and blobs may not appear in the middle of a record");
0193 ElementTy::assertValid(element);
0194 buffer.push_back(element);
0195 BCRecordCoding<Fields...>::emit(Stream, buffer, code,
0196 std::forward<DataTy>(data)...);
0197 }
0198
0199 template <typename T, typename ElementDataTy, typename... DataTy>
0200 static void read(ArrayRef<T> buffer, ElementDataTy &element,
0201 DataTy &&...data) {
0202 assert(!buffer.empty() && "too few elements in buffer");
0203 element = ElementTy::convert(buffer.front());
0204 BCRecordCoding<Fields...>::read(buffer.slice(1),
0205 std::forward<DataTy>(data)...);
0206 }
0207
0208 template <typename T, typename... DataTy>
0209 static void read(ArrayRef<T> buffer, std::nullopt_t, DataTy &&...data) {
0210 assert(!buffer.empty() && "too few elements in buffer");
0211 BCRecordCoding<Fields...>::read(buffer.slice(1),
0212 std::forward<DataTy>(data)...);
0213 }
0214 };
0215
0216
0217
0218
0219
0220
0221
0222
0223 template <typename ElementTy> class BCRecordCoding<ElementTy> {
0224 public:
0225 template <typename BufferTy, typename DataTy>
0226 static void emit(llvm::BitstreamWriter &Stream, BufferTy &buffer,
0227 unsigned code, const DataTy &data) {
0228 static_assert(!ElementTy::IsCompound,
0229 "arrays and blobs need special handling");
0230 ElementTy::assertValid(data);
0231 buffer.push_back(data);
0232 Stream.EmitRecordWithAbbrev(code, buffer);
0233 }
0234
0235 template <typename T, typename DataTy>
0236 static void read(ArrayRef<T> buffer, DataTy &data) {
0237 assert(buffer.size() == 1 && "record data does not match layout");
0238 data = ElementTy::convert(buffer.front());
0239 }
0240
0241 template <typename T> static void read(ArrayRef<T> buffer, std::nullopt_t) {
0242 assert(buffer.size() == 1 && "record data does not match layout");
0243 (void)buffer;
0244 }
0245
0246 template <typename T> static void read(ArrayRef<T> buffer) = delete;
0247 };
0248
0249
0250
0251
0252 template <typename ElementTy> class BCRecordCoding<BCArray<ElementTy>> {
0253 public:
0254 template <typename BufferTy>
0255 static void emit(llvm::BitstreamWriter &Stream, BufferTy &buffer,
0256 unsigned code, StringRef data) {
0257
0258 Stream.EmitRecordWithArray(code, buffer, data);
0259 }
0260
0261 template <typename BufferTy, typename ArrayTy>
0262 static void emit(llvm::BitstreamWriter &Stream, BufferTy &buffer,
0263 unsigned code, const ArrayTy &array) {
0264 #ifndef NDEBUG
0265 for (auto &element : array)
0266 ElementTy::assertValid(element);
0267 #endif
0268 buffer.reserve(buffer.size() + std::distance(array.begin(), array.end()));
0269 std::copy(array.begin(), array.end(), std::back_inserter(buffer));
0270 Stream.EmitRecordWithAbbrev(code, buffer);
0271 }
0272
0273 template <typename BufferTy, typename ElementDataTy, typename... DataTy>
0274 static void emit(llvm::BitstreamWriter &Stream, BufferTy &buffer,
0275 unsigned code, ElementDataTy element, DataTy... data) {
0276 std::array<ElementDataTy, 1 + sizeof...(data)> array{{element, data...}};
0277 emit(Stream, buffer, code, array);
0278 }
0279
0280 template <typename BufferTy>
0281 static void emit(llvm::BitstreamWriter &Stream, BufferTy &Buffer,
0282 unsigned code, std::nullopt_t) {
0283 Stream.EmitRecordWithAbbrev(code, Buffer);
0284 }
0285
0286 template <typename T>
0287 static void read(ArrayRef<T> Buffer, ArrayRef<T> &rawData) {
0288 rawData = Buffer;
0289 }
0290
0291 template <typename T, typename ArrayTy>
0292 static void read(ArrayRef<T> buffer, ArrayTy &array) {
0293 array.append(llvm::map_iterator(buffer.begin(), T::convert),
0294 llvm::map_iterator(buffer.end(), T::convert));
0295 }
0296
0297 template <typename T> static void read(ArrayRef<T> buffer, std::nullopt_t) {
0298 (void)buffer;
0299 }
0300
0301 template <typename T> static void read(ArrayRef<T> buffer) = delete;
0302 };
0303
0304
0305
0306
0307 template <> class BCRecordCoding<BCBlob> {
0308 public:
0309 template <typename BufferTy>
0310 static void emit(llvm::BitstreamWriter &Stream, BufferTy &buffer,
0311 unsigned code, StringRef data) {
0312 Stream.EmitRecordWithBlob(code, buffer, data);
0313 }
0314
0315 template <typename T> static void read(ArrayRef<T> buffer) { (void)buffer; }
0316
0317
0318
0319 template <typename T, typename DataTy>
0320 static void read(ArrayRef<T> buffer, DataTy &data) = delete;
0321 };
0322
0323
0324 template <typename Head, typename... Tail> struct last_type {
0325 using type = typename last_type<Tail...>::type;
0326 };
0327
0328 template <typename Head> struct last_type<Head> { using type = Head; };
0329
0330
0331 template <typename... Types>
0332 using has_blob = std::is_same<BCBlob, typename last_type<int, Types...>::type>;
0333
0334
0335
0336 template <typename T> struct is_array {
0337 private:
0338 template <typename E> static bool check(BCArray<E> *);
0339 static int check(...);
0340
0341 public:
0342 typedef bool value_type;
0343 static constexpr bool value = !std::is_same<decltype(check((T *)nullptr)),
0344 decltype(check(false))>::value;
0345 };
0346
0347
0348
0349 template <typename... Types>
0350 using has_array = is_array<typename last_type<int, Types...>::type>;
0351 }
0352
0353
0354
0355
0356
0357 template <typename IDField, typename... Fields> class BCGenericRecordLayout {
0358 llvm::BitstreamWriter &Stream;
0359
0360 public:
0361
0362
0363
0364
0365 const unsigned AbbrevCode;
0366
0367
0368 explicit BCGenericRecordLayout(llvm::BitstreamWriter &Stream)
0369 : Stream(Stream), AbbrevCode(emitAbbrev(Stream)) {}
0370
0371
0372
0373
0374
0375 template <typename BufferTy, typename... Data>
0376 void emit(BufferTy &buffer, unsigned id, Data &&...data) const {
0377 emitRecord(Stream, buffer, AbbrevCode, id, std::forward<Data>(data)...);
0378 }
0379
0380
0381
0382
0383 static unsigned emitAbbrev(llvm::BitstreamWriter &Stream) {
0384 auto Abbrev = std::make_shared<llvm::BitCodeAbbrev>();
0385 detail::emitOps<IDField, Fields...>(*Abbrev);
0386 return Stream.EmitAbbrev(std::move(Abbrev));
0387 }
0388
0389
0390
0391
0392
0393
0394
0395
0396 template <typename BufferTy, typename... Data>
0397 static void emitRecord(llvm::BitstreamWriter &Stream, BufferTy &buffer,
0398 unsigned abbrCode, unsigned recordID, Data &&...data) {
0399 static_assert(sizeof...(data) <= sizeof...(Fields) ||
0400 detail::has_array<Fields...>::value,
0401 "Too many record elements");
0402 static_assert(sizeof...(data) >= sizeof...(Fields),
0403 "Too few record elements");
0404 buffer.clear();
0405 detail::BCRecordCoding<IDField, Fields...>::emit(
0406 Stream, buffer, abbrCode, recordID, std::forward<Data>(data)...);
0407 }
0408
0409
0410
0411
0412
0413
0414 template <typename ElementTy, typename... Data>
0415 static void readRecord(ArrayRef<ElementTy> buffer, Data &&...data) {
0416 static_assert(sizeof...(data) <= sizeof...(Fields),
0417 "Too many record elements");
0418 static_assert(sizeof...(Fields) <=
0419 sizeof...(data) + detail::has_blob<Fields...>::value,
0420 "Too few record elements");
0421 return detail::BCRecordCoding<Fields...>::read(buffer,
0422 std::forward<Data>(data)...);
0423 }
0424
0425
0426
0427
0428
0429
0430 template <typename BufferTy, typename... Data>
0431 static void readRecord(BufferTy &buffer, Data &&...data) {
0432 return readRecord(llvm::ArrayRef(buffer), std::forward<Data>(data)...);
0433 }
0434 };
0435
0436
0437 template <unsigned RecordCode, typename... Fields>
0438 class BCRecordLayout
0439 : public BCGenericRecordLayout<BCLiteral<RecordCode>, Fields...> {
0440 using Base = BCGenericRecordLayout<BCLiteral<RecordCode>, Fields...>;
0441
0442 public:
0443 enum : unsigned {
0444
0445 Code = RecordCode
0446 };
0447
0448
0449 explicit BCRecordLayout(llvm::BitstreamWriter &Stream) : Base(Stream) {}
0450
0451
0452
0453
0454
0455 template <typename BufferTy, typename... Data>
0456 void emit(BufferTy &buffer, Data &&...data) const {
0457 Base::emit(buffer, RecordCode, std::forward<Data>(data)...);
0458 }
0459
0460
0461
0462
0463
0464
0465 template <typename BufferTy, typename... Data>
0466 static void emitRecord(llvm::BitstreamWriter &Stream, BufferTy &buffer,
0467 unsigned abbrCode, Data &&...data) {
0468 Base::emitRecord(Stream, buffer, abbrCode, RecordCode,
0469 std::forward<Data>(data)...);
0470 }
0471 };
0472
0473
0474 class BCBlockRAII {
0475 llvm::BitstreamWriter &Stream;
0476
0477 public:
0478 BCBlockRAII(llvm::BitstreamWriter &Stream, unsigned block, unsigned abbrev)
0479 : Stream(Stream) {
0480 Stream.EnterSubblock(block, abbrev);
0481 }
0482
0483 ~BCBlockRAII() { Stream.ExitBlock(); }
0484 };
0485 }
0486
0487 #endif