BitcodeConvenience.h 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498
  1. #pragma once
  2. #ifdef __GNUC__
  3. #pragma GCC diagnostic push
  4. #pragma GCC diagnostic ignored "-Wunused-parameter"
  5. #endif
  6. //===- llvm/Bitcode/BitcodeConvenience.h - Convenience Wrappers -*- C++ -*-===//
  7. //
  8. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  9. // See https://llvm.org/LICENSE.txt for license information.
  10. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  11. //
  12. //===----------------------------------------------------------------------===//
  13. ///
  14. /// \file Convenience wrappers for the LLVM bitcode format and bitstream APIs.
  15. ///
  16. /// This allows you to use a sort of DSL to declare and use bitcode
  17. /// abbreviations and records. Example:
  18. ///
  19. /// \code
  20. /// using Metadata = BCRecordLayout<
  21. /// METADATA_ID, // ID
  22. /// BCFixed<16>, // Module format major version
  23. /// BCFixed<16>, // Module format minor version
  24. /// BCBlob // misc. version information
  25. /// >;
  26. /// Metadata metadata(Out);
  27. /// metadata.emit(ScratchRecord, VERSION_MAJOR, VERSION_MINOR, Data);
  28. /// \endcode
  29. ///
  30. /// For details on the bitcode format, see
  31. /// http://llvm.org/docs/BitCodeFormat.html
  32. ///
  33. //===----------------------------------------------------------------------===//
  34. #ifndef LLVM_BITCODE_BITCODECONVENIENCE_H
  35. #define LLVM_BITCODE_BITCODECONVENIENCE_H
  36. #include "llvm/Bitstream/BitCodes.h"
  37. #include "llvm/Bitstream/BitstreamWriter.h"
  38. #include <cstdint>
  39. #include <optional>
  40. namespace llvm {
  41. namespace detail {
  42. /// Convenience base for all kinds of bitcode abbreviation fields.
  43. ///
  44. /// This just defines common properties queried by the metaprogramming.
  45. template <bool Compound = false> class BCField {
  46. public:
  47. static const bool IsCompound = Compound;
  48. /// Asserts that the given data is a valid value for this field.
  49. template <typename T> static void assertValid(const T &data) {}
  50. /// Converts a raw numeric representation of this value to its preferred
  51. /// type.
  52. template <typename T> static T convert(T rawValue) { return rawValue; }
  53. };
  54. } // namespace detail
  55. /// Represents a literal operand in a bitcode record.
  56. ///
  57. /// The value of a literal operand is the same for all instances of the record,
  58. /// so it is only emitted in the abbreviation definition.
  59. ///
  60. /// Note that because this uses a compile-time template, you cannot have a
  61. /// literal operand that is fixed at run-time without dropping down to the
  62. /// raw LLVM APIs.
  63. template <uint64_t Value> class BCLiteral : public detail::BCField<> {
  64. public:
  65. static void emitOp(llvm::BitCodeAbbrev &abbrev) {
  66. abbrev.Add(llvm::BitCodeAbbrevOp(Value));
  67. }
  68. template <typename T> static void assertValid(const T &data) {
  69. assert(data == Value && "data value does not match declared literal value");
  70. }
  71. };
  72. /// Represents a fixed-width value in a bitcode record.
  73. ///
  74. /// Note that the LLVM bitcode format only supports unsigned values.
  75. template <unsigned Width> class BCFixed : public detail::BCField<> {
  76. public:
  77. static_assert(Width <= 64, "fixed-width field is too large");
  78. static void emitOp(llvm::BitCodeAbbrev &abbrev) {
  79. abbrev.Add(llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Fixed, Width));
  80. }
  81. static void assertValid(const bool &data) {
  82. assert(llvm::isUInt<Width>(data) &&
  83. "data value does not fit in the given bit width");
  84. }
  85. template <typename T> static void assertValid(const T &data) {
  86. assert(data >= 0 && "cannot encode signed integers");
  87. assert(llvm::isUInt<Width>(data) &&
  88. "data value does not fit in the given bit width");
  89. }
  90. };
  91. /// Represents a variable-width value in a bitcode record.
  92. ///
  93. /// The \p Width parameter should include the continuation bit.
  94. ///
  95. /// Note that the LLVM bitcode format only supports unsigned values.
  96. template <unsigned Width> class BCVBR : public detail::BCField<> {
  97. static_assert(Width >= 2, "width does not have room for continuation bit");
  98. public:
  99. static void emitOp(llvm::BitCodeAbbrev &abbrev) {
  100. abbrev.Add(llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::VBR, Width));
  101. }
  102. template <typename T> static void assertValid(const T &data) {
  103. assert(data >= 0 && "cannot encode signed integers");
  104. }
  105. };
  106. /// Represents a character encoded in LLVM's Char6 encoding.
  107. ///
  108. /// This format is suitable for encoding decimal numbers (without signs or
  109. /// exponents) and C identifiers (without dollar signs), but not much else.
  110. ///
  111. /// \sa http://llvm.org/docs/BitCodeFormat.html#char6-encoded-value
  112. class BCChar6 : public detail::BCField<> {
  113. public:
  114. static void emitOp(llvm::BitCodeAbbrev &abbrev) {
  115. abbrev.Add(llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Char6));
  116. }
  117. template <typename T> static void assertValid(const T &data) {
  118. assert(llvm::BitCodeAbbrevOp::isChar6(data) && "invalid Char6 data");
  119. }
  120. template <typename T> char convert(T rawValue) {
  121. return static_cast<char>(rawValue);
  122. }
  123. };
  124. /// Represents an untyped blob of bytes.
  125. ///
  126. /// If present, this must be the last field in a record.
  127. class BCBlob : public detail::BCField<true> {
  128. public:
  129. static void emitOp(llvm::BitCodeAbbrev &abbrev) {
  130. abbrev.Add(llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Blob));
  131. }
  132. };
  133. /// Represents an array of some other type.
  134. ///
  135. /// If present, this must be the last field in a record.
  136. template <typename ElementTy> class BCArray : public detail::BCField<true> {
  137. static_assert(!ElementTy::IsCompound, "arrays can only contain scalar types");
  138. public:
  139. static void emitOp(llvm::BitCodeAbbrev &abbrev) {
  140. abbrev.Add(llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Array));
  141. ElementTy::emitOp(abbrev);
  142. }
  143. };
  144. namespace detail {
  145. /// Attaches the last field to an abbreviation.
  146. ///
  147. /// This is the base case for \c emitOps.
  148. ///
  149. /// \sa BCRecordLayout::emitAbbrev
  150. template <typename FieldTy> static void emitOps(llvm::BitCodeAbbrev &abbrev) {
  151. FieldTy::emitOp(abbrev);
  152. }
  153. /// Attaches fields to an abbreviation.
  154. ///
  155. /// This is the recursive case for \c emitOps.
  156. ///
  157. /// \sa BCRecordLayout::emitAbbrev
  158. template <typename FieldTy, typename Next, typename... Rest>
  159. static void emitOps(llvm::BitCodeAbbrev &abbrev) {
  160. static_assert(!FieldTy::IsCompound,
  161. "arrays and blobs may not appear in the middle of a record");
  162. FieldTy::emitOp(abbrev);
  163. emitOps<Next, Rest...>(abbrev);
  164. }
  165. /// Helper class for dealing with a scalar element in the middle of a record.
  166. ///
  167. /// \sa BCRecordLayout
  168. template <typename ElementTy, typename... Fields> class BCRecordCoding {
  169. public:
  170. template <typename BufferTy, typename ElementDataTy, typename... DataTy>
  171. static void emit(llvm::BitstreamWriter &Stream, BufferTy &buffer,
  172. unsigned code, ElementDataTy element, DataTy &&...data) {
  173. static_assert(!ElementTy::IsCompound,
  174. "arrays and blobs may not appear in the middle of a record");
  175. ElementTy::assertValid(element);
  176. buffer.push_back(element);
  177. BCRecordCoding<Fields...>::emit(Stream, buffer, code,
  178. std::forward<DataTy>(data)...);
  179. }
  180. template <typename T, typename ElementDataTy, typename... DataTy>
  181. static void read(ArrayRef<T> buffer, ElementDataTy &element,
  182. DataTy &&...data) {
  183. assert(!buffer.empty() && "too few elements in buffer");
  184. element = ElementTy::convert(buffer.front());
  185. BCRecordCoding<Fields...>::read(buffer.slice(1),
  186. std::forward<DataTy>(data)...);
  187. }
  188. template <typename T, typename... DataTy>
  189. static void read(ArrayRef<T> buffer, std::nullopt_t, DataTy &&...data) {
  190. assert(!buffer.empty() && "too few elements in buffer");
  191. BCRecordCoding<Fields...>::read(buffer.slice(1),
  192. std::forward<DataTy>(data)...);
  193. }
  194. };
  195. /// Helper class for dealing with a scalar element at the end of a record.
  196. ///
  197. /// This has a separate implementation because up until now we've only been
  198. /// \em building the record (into a data buffer), and now we need to hand it
  199. /// off to the BitstreamWriter to be emitted.
  200. ///
  201. /// \sa BCRecordLayout
  202. template <typename ElementTy> class BCRecordCoding<ElementTy> {
  203. public:
  204. template <typename BufferTy, typename DataTy>
  205. static void emit(llvm::BitstreamWriter &Stream, BufferTy &buffer,
  206. unsigned code, const DataTy &data) {
  207. static_assert(!ElementTy::IsCompound,
  208. "arrays and blobs need special handling");
  209. ElementTy::assertValid(data);
  210. buffer.push_back(data);
  211. Stream.EmitRecordWithAbbrev(code, buffer);
  212. }
  213. template <typename T, typename DataTy>
  214. static void read(ArrayRef<T> buffer, DataTy &data) {
  215. assert(buffer.size() == 1 && "record data does not match layout");
  216. data = ElementTy::convert(buffer.front());
  217. }
  218. template <typename T> static void read(ArrayRef<T> buffer, std::nullopt_t) {
  219. assert(buffer.size() == 1 && "record data does not match layout");
  220. (void)buffer;
  221. }
  222. template <typename T> static void read(ArrayRef<T> buffer) = delete;
  223. };
  224. /// Helper class for dealing with an array at the end of a record.
  225. ///
  226. /// \sa BCRecordLayout::emitRecord
  227. template <typename ElementTy> class BCRecordCoding<BCArray<ElementTy>> {
  228. public:
  229. template <typename BufferTy>
  230. static void emit(llvm::BitstreamWriter &Stream, BufferTy &buffer,
  231. unsigned code, StringRef data) {
  232. // TODO: validate array data.
  233. Stream.EmitRecordWithArray(code, buffer, data);
  234. }
  235. template <typename BufferTy, typename ArrayTy>
  236. static void emit(llvm::BitstreamWriter &Stream, BufferTy &buffer,
  237. unsigned code, const ArrayTy &array) {
  238. #ifndef NDEBUG
  239. for (auto &element : array)
  240. ElementTy::assertValid(element);
  241. #endif
  242. buffer.reserve(buffer.size() + std::distance(array.begin(), array.end()));
  243. std::copy(array.begin(), array.end(), std::back_inserter(buffer));
  244. Stream.EmitRecordWithAbbrev(code, buffer);
  245. }
  246. template <typename BufferTy, typename ElementDataTy, typename... DataTy>
  247. static void emit(llvm::BitstreamWriter &Stream, BufferTy &buffer,
  248. unsigned code, ElementDataTy element, DataTy... data) {
  249. std::array<ElementDataTy, 1 + sizeof...(data)> array{{element, data...}};
  250. emit(Stream, buffer, code, array);
  251. }
  252. template <typename BufferTy>
  253. static void emit(llvm::BitstreamWriter &Stream, BufferTy &Buffer,
  254. unsigned code, std::nullopt_t) {
  255. Stream.EmitRecordWithAbbrev(code, Buffer);
  256. }
  257. template <typename T>
  258. static void read(ArrayRef<T> Buffer, ArrayRef<T> &rawData) {
  259. rawData = Buffer;
  260. }
  261. template <typename T, typename ArrayTy>
  262. static void read(ArrayRef<T> buffer, ArrayTy &array) {
  263. array.append(llvm::map_iterator(buffer.begin(), T::convert),
  264. llvm::map_iterator(buffer.end(), T::convert));
  265. }
  266. template <typename T> static void read(ArrayRef<T> buffer, std::nullopt_t) {
  267. (void)buffer;
  268. }
  269. template <typename T> static void read(ArrayRef<T> buffer) = delete;
  270. };
  271. /// Helper class for dealing with a blob at the end of a record.
  272. ///
  273. /// \sa BCRecordLayout
  274. template <> class BCRecordCoding<BCBlob> {
  275. public:
  276. template <typename BufferTy>
  277. static void emit(llvm::BitstreamWriter &Stream, BufferTy &buffer,
  278. unsigned code, StringRef data) {
  279. Stream.EmitRecordWithBlob(code, buffer, data);
  280. }
  281. template <typename T> static void read(ArrayRef<T> buffer) { (void)buffer; }
  282. /// Blob data is not stored in the buffer if you are using the correct
  283. /// accessor; this method should not be used.
  284. template <typename T, typename DataTy>
  285. static void read(ArrayRef<T> buffer, DataTy &data) = delete;
  286. };
  287. /// A type trait whose \c type field is the last of its template parameters.
  288. template <typename Head, typename... Tail> struct last_type {
  289. using type = typename last_type<Tail...>::type;
  290. };
  291. template <typename Head> struct last_type<Head> { using type = Head; };
  292. /// A type trait whose \c value field is \c true if the last type is BCBlob.
  293. template <typename... Types>
  294. using has_blob = std::is_same<BCBlob, typename last_type<int, Types...>::type>;
  295. /// A type trait whose \c value field is \c true if the given type is a
  296. /// BCArray (of any element kind).
  297. template <typename T> struct is_array {
  298. private:
  299. template <typename E> static bool check(BCArray<E> *);
  300. static int check(...);
  301. public:
  302. typedef bool value_type;
  303. static constexpr bool value = !std::is_same<decltype(check((T *)nullptr)),
  304. decltype(check(false))>::value;
  305. };
  306. /// A type trait whose \c value field is \c true if the last type is a
  307. /// BCArray (of any element kind).
  308. template <typename... Types>
  309. using has_array = is_array<typename last_type<int, Types...>::type>;
  310. } // namespace detail
  311. /// Represents a single bitcode record type.
  312. ///
  313. /// This class template is meant to be instantiated and then given a name,
  314. /// so that from then on that name can be used.
  315. template <typename IDField, typename... Fields> class BCGenericRecordLayout {
  316. llvm::BitstreamWriter &Stream;
  317. public:
  318. /// The abbreviation code used for this record in the current block.
  319. ///
  320. /// Note that this is not the same as the semantic record code, which is the
  321. /// first field of the record.
  322. const unsigned AbbrevCode;
  323. /// Create a layout and register it with the given bitstream writer.
  324. explicit BCGenericRecordLayout(llvm::BitstreamWriter &Stream)
  325. : Stream(Stream), AbbrevCode(emitAbbrev(Stream)) {}
  326. /// Emit a record to the bitstream writer, using the given buffer for scratch
  327. /// space.
  328. ///
  329. /// Note that even fixed arguments must be specified here.
  330. template <typename BufferTy, typename... Data>
  331. void emit(BufferTy &buffer, unsigned id, Data &&...data) const {
  332. emitRecord(Stream, buffer, AbbrevCode, id, std::forward<Data>(data)...);
  333. }
  334. /// Registers this record's layout with the bitstream reader.
  335. ///
  336. /// eturns The abbreviation code for the newly-registered record type.
  337. static unsigned emitAbbrev(llvm::BitstreamWriter &Stream) {
  338. auto Abbrev = std::make_shared<llvm::BitCodeAbbrev>();
  339. detail::emitOps<IDField, Fields...>(*Abbrev);
  340. return Stream.EmitAbbrev(std::move(Abbrev));
  341. }
  342. /// Emit a record identified by \p abbrCode to bitstream reader \p Stream,
  343. /// using \p buffer for scratch space.
  344. ///
  345. /// Note that even fixed arguments must be specified here. Blobs are passed
  346. /// as StringRefs, while arrays can be passed inline, as aggregates, or as
  347. /// pre-encoded StringRef data. Skipped values and empty arrays should use
  348. /// the special Nothing value.
  349. template <typename BufferTy, typename... Data>
  350. static void emitRecord(llvm::BitstreamWriter &Stream, BufferTy &buffer,
  351. unsigned abbrCode, unsigned recordID, Data &&...data) {
  352. static_assert(sizeof...(data) <= sizeof...(Fields) ||
  353. detail::has_array<Fields...>::value,
  354. "Too many record elements");
  355. static_assert(sizeof...(data) >= sizeof...(Fields),
  356. "Too few record elements");
  357. buffer.clear();
  358. detail::BCRecordCoding<IDField, Fields...>::emit(
  359. Stream, buffer, abbrCode, recordID, std::forward<Data>(data)...);
  360. }
  361. /// Extract record data from \p buffer into the given data fields.
  362. ///
  363. /// Note that even fixed arguments must be specified here. Pass \c Nothing
  364. /// if you don't care about a particular parameter. Blob data is not included
  365. /// in the buffer and should be handled separately by the caller.
  366. template <typename ElementTy, typename... Data>
  367. static void readRecord(ArrayRef<ElementTy> buffer, Data &&...data) {
  368. static_assert(sizeof...(data) <= sizeof...(Fields),
  369. "Too many record elements");
  370. static_assert(sizeof...(Fields) <=
  371. sizeof...(data) + detail::has_blob<Fields...>::value,
  372. "Too few record elements");
  373. return detail::BCRecordCoding<Fields...>::read(buffer,
  374. std::forward<Data>(data)...);
  375. }
  376. /// Extract record data from \p buffer into the given data fields.
  377. ///
  378. /// Note that even fixed arguments must be specified here. Pass \c Nothing
  379. /// if you don't care about a particular parameter. Blob data is not included
  380. /// in the buffer and should be handled separately by the caller.
  381. template <typename BufferTy, typename... Data>
  382. static void readRecord(BufferTy &buffer, Data &&...data) {
  383. return readRecord(llvm::ArrayRef(buffer), std::forward<Data>(data)...);
  384. }
  385. };
  386. /// A record with a fixed record code.
  387. template <unsigned RecordCode, typename... Fields>
  388. class BCRecordLayout
  389. : public BCGenericRecordLayout<BCLiteral<RecordCode>, Fields...> {
  390. using Base = BCGenericRecordLayout<BCLiteral<RecordCode>, Fields...>;
  391. public:
  392. enum : unsigned {
  393. /// The record code associated with this layout.
  394. Code = RecordCode
  395. };
  396. /// Create a layout and register it with the given bitstream writer.
  397. explicit BCRecordLayout(llvm::BitstreamWriter &Stream) : Base(Stream) {}
  398. /// Emit a record to the bitstream writer, using the given buffer for scratch
  399. /// space.
  400. ///
  401. /// Note that even fixed arguments must be specified here.
  402. template <typename BufferTy, typename... Data>
  403. void emit(BufferTy &buffer, Data &&...data) const {
  404. Base::emit(buffer, RecordCode, std::forward<Data>(data)...);
  405. }
  406. /// Emit a record identified by \p abbrCode to bitstream reader \p Stream,
  407. /// using \p buffer for scratch space.
  408. ///
  409. /// Note that even fixed arguments must be specified here. Currently, arrays
  410. /// and blobs can only be passed as StringRefs.
  411. template <typename BufferTy, typename... Data>
  412. static void emitRecord(llvm::BitstreamWriter &Stream, BufferTy &buffer,
  413. unsigned abbrCode, Data &&...data) {
  414. Base::emitRecord(Stream, buffer, abbrCode, RecordCode,
  415. std::forward<Data>(data)...);
  416. }
  417. };
  418. /// RAII object to pair entering and exiting a sub-block.
  419. class BCBlockRAII {
  420. llvm::BitstreamWriter &Stream;
  421. public:
  422. BCBlockRAII(llvm::BitstreamWriter &Stream, unsigned block, unsigned abbrev)
  423. : Stream(Stream) {
  424. Stream.EnterSubblock(block, abbrev);
  425. }
  426. ~BCBlockRAII() { Stream.ExitBlock(); }
  427. };
  428. } // namespace llvm
  429. #endif
  430. #ifdef __GNUC__
  431. #pragma GCC diagnostic pop
  432. #endif