Subversion Repositories QNX 8.QNX8 LLVM/Clang compiler suite

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
14 pmbaty 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