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