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