123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498 |
- #pragma once
- #ifdef __GNUC__
- #pragma GCC diagnostic push
- #pragma GCC diagnostic ignored "-Wunused-parameter"
- #endif
- //===- llvm/Bitcode/BitcodeConvenience.h - Convenience Wrappers -*- C++ -*-===//
- //
- // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
- // See https://llvm.org/LICENSE.txt for license information.
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- //
- //===----------------------------------------------------------------------===//
- ///
- /// \file Convenience wrappers for the LLVM bitcode format and bitstream APIs.
- ///
- /// This allows you to use a sort of DSL to declare and use bitcode
- /// abbreviations and records. Example:
- ///
- /// \code
- /// using Metadata = BCRecordLayout<
- /// METADATA_ID, // ID
- /// BCFixed<16>, // Module format major version
- /// BCFixed<16>, // Module format minor version
- /// BCBlob // misc. version information
- /// >;
- /// Metadata metadata(Out);
- /// metadata.emit(ScratchRecord, VERSION_MAJOR, VERSION_MINOR, Data);
- /// \endcode
- ///
- /// For details on the bitcode format, see
- /// http://llvm.org/docs/BitCodeFormat.html
- ///
- //===----------------------------------------------------------------------===//
- #ifndef LLVM_BITCODE_BITCODECONVENIENCE_H
- #define LLVM_BITCODE_BITCODECONVENIENCE_H
- #include "llvm/Bitstream/BitCodes.h"
- #include "llvm/Bitstream/BitstreamWriter.h"
- #include <cstdint>
- #include <optional>
- namespace llvm {
- namespace detail {
- /// Convenience base for all kinds of bitcode abbreviation fields.
- ///
- /// This just defines common properties queried by the metaprogramming.
- template <bool Compound = false> class BCField {
- public:
- static const bool IsCompound = Compound;
- /// Asserts that the given data is a valid value for this field.
- template <typename T> static void assertValid(const T &data) {}
- /// Converts a raw numeric representation of this value to its preferred
- /// type.
- template <typename T> static T convert(T rawValue) { return rawValue; }
- };
- } // namespace detail
- /// Represents a literal operand in a bitcode record.
- ///
- /// The value of a literal operand is the same for all instances of the record,
- /// so it is only emitted in the abbreviation definition.
- ///
- /// Note that because this uses a compile-time template, you cannot have a
- /// literal operand that is fixed at run-time without dropping down to the
- /// raw LLVM APIs.
- template <uint64_t Value> class BCLiteral : public detail::BCField<> {
- public:
- static void emitOp(llvm::BitCodeAbbrev &abbrev) {
- abbrev.Add(llvm::BitCodeAbbrevOp(Value));
- }
- template <typename T> static void assertValid(const T &data) {
- assert(data == Value && "data value does not match declared literal value");
- }
- };
- /// Represents a fixed-width value in a bitcode record.
- ///
- /// Note that the LLVM bitcode format only supports unsigned values.
- template <unsigned Width> class BCFixed : public detail::BCField<> {
- public:
- static_assert(Width <= 64, "fixed-width field is too large");
- static void emitOp(llvm::BitCodeAbbrev &abbrev) {
- abbrev.Add(llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Fixed, Width));
- }
- static void assertValid(const bool &data) {
- assert(llvm::isUInt<Width>(data) &&
- "data value does not fit in the given bit width");
- }
- template <typename T> static void assertValid(const T &data) {
- assert(data >= 0 && "cannot encode signed integers");
- assert(llvm::isUInt<Width>(data) &&
- "data value does not fit in the given bit width");
- }
- };
- /// Represents a variable-width value in a bitcode record.
- ///
- /// The \p Width parameter should include the continuation bit.
- ///
- /// Note that the LLVM bitcode format only supports unsigned values.
- template <unsigned Width> class BCVBR : public detail::BCField<> {
- static_assert(Width >= 2, "width does not have room for continuation bit");
- public:
- static void emitOp(llvm::BitCodeAbbrev &abbrev) {
- abbrev.Add(llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::VBR, Width));
- }
- template <typename T> static void assertValid(const T &data) {
- assert(data >= 0 && "cannot encode signed integers");
- }
- };
- /// Represents a character encoded in LLVM's Char6 encoding.
- ///
- /// This format is suitable for encoding decimal numbers (without signs or
- /// exponents) and C identifiers (without dollar signs), but not much else.
- ///
- /// \sa http://llvm.org/docs/BitCodeFormat.html#char6-encoded-value
- class BCChar6 : public detail::BCField<> {
- public:
- static void emitOp(llvm::BitCodeAbbrev &abbrev) {
- abbrev.Add(llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Char6));
- }
- template <typename T> static void assertValid(const T &data) {
- assert(llvm::BitCodeAbbrevOp::isChar6(data) && "invalid Char6 data");
- }
- template <typename T> char convert(T rawValue) {
- return static_cast<char>(rawValue);
- }
- };
- /// Represents an untyped blob of bytes.
- ///
- /// If present, this must be the last field in a record.
- class BCBlob : public detail::BCField<true> {
- public:
- static void emitOp(llvm::BitCodeAbbrev &abbrev) {
- abbrev.Add(llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Blob));
- }
- };
- /// Represents an array of some other type.
- ///
- /// If present, this must be the last field in a record.
- template <typename ElementTy> class BCArray : public detail::BCField<true> {
- static_assert(!ElementTy::IsCompound, "arrays can only contain scalar types");
- public:
- static void emitOp(llvm::BitCodeAbbrev &abbrev) {
- abbrev.Add(llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Array));
- ElementTy::emitOp(abbrev);
- }
- };
- namespace detail {
- /// Attaches the last field to an abbreviation.
- ///
- /// This is the base case for \c emitOps.
- ///
- /// \sa BCRecordLayout::emitAbbrev
- template <typename FieldTy> static void emitOps(llvm::BitCodeAbbrev &abbrev) {
- FieldTy::emitOp(abbrev);
- }
- /// Attaches fields to an abbreviation.
- ///
- /// This is the recursive case for \c emitOps.
- ///
- /// \sa BCRecordLayout::emitAbbrev
- template <typename FieldTy, typename Next, typename... Rest>
- static void emitOps(llvm::BitCodeAbbrev &abbrev) {
- static_assert(!FieldTy::IsCompound,
- "arrays and blobs may not appear in the middle of a record");
- FieldTy::emitOp(abbrev);
- emitOps<Next, Rest...>(abbrev);
- }
- /// Helper class for dealing with a scalar element in the middle of a record.
- ///
- /// \sa BCRecordLayout
- template <typename ElementTy, typename... Fields> class BCRecordCoding {
- public:
- template <typename BufferTy, typename ElementDataTy, typename... DataTy>
- static void emit(llvm::BitstreamWriter &Stream, BufferTy &buffer,
- unsigned code, ElementDataTy element, DataTy &&...data) {
- static_assert(!ElementTy::IsCompound,
- "arrays and blobs may not appear in the middle of a record");
- ElementTy::assertValid(element);
- buffer.push_back(element);
- BCRecordCoding<Fields...>::emit(Stream, buffer, code,
- std::forward<DataTy>(data)...);
- }
- template <typename T, typename ElementDataTy, typename... DataTy>
- static void read(ArrayRef<T> buffer, ElementDataTy &element,
- DataTy &&...data) {
- assert(!buffer.empty() && "too few elements in buffer");
- element = ElementTy::convert(buffer.front());
- BCRecordCoding<Fields...>::read(buffer.slice(1),
- std::forward<DataTy>(data)...);
- }
- template <typename T, typename... DataTy>
- static void read(ArrayRef<T> buffer, std::nullopt_t, DataTy &&...data) {
- assert(!buffer.empty() && "too few elements in buffer");
- BCRecordCoding<Fields...>::read(buffer.slice(1),
- std::forward<DataTy>(data)...);
- }
- };
- /// Helper class for dealing with a scalar element at the end of a record.
- ///
- /// This has a separate implementation because up until now we've only been
- /// \em building the record (into a data buffer), and now we need to hand it
- /// off to the BitstreamWriter to be emitted.
- ///
- /// \sa BCRecordLayout
- template <typename ElementTy> class BCRecordCoding<ElementTy> {
- public:
- template <typename BufferTy, typename DataTy>
- static void emit(llvm::BitstreamWriter &Stream, BufferTy &buffer,
- unsigned code, const DataTy &data) {
- static_assert(!ElementTy::IsCompound,
- "arrays and blobs need special handling");
- ElementTy::assertValid(data);
- buffer.push_back(data);
- Stream.EmitRecordWithAbbrev(code, buffer);
- }
- template <typename T, typename DataTy>
- static void read(ArrayRef<T> buffer, DataTy &data) {
- assert(buffer.size() == 1 && "record data does not match layout");
- data = ElementTy::convert(buffer.front());
- }
- template <typename T> static void read(ArrayRef<T> buffer, std::nullopt_t) {
- assert(buffer.size() == 1 && "record data does not match layout");
- (void)buffer;
- }
- template <typename T> static void read(ArrayRef<T> buffer) = delete;
- };
- /// Helper class for dealing with an array at the end of a record.
- ///
- /// \sa BCRecordLayout::emitRecord
- template <typename ElementTy> class BCRecordCoding<BCArray<ElementTy>> {
- public:
- template <typename BufferTy>
- static void emit(llvm::BitstreamWriter &Stream, BufferTy &buffer,
- unsigned code, StringRef data) {
- // TODO: validate array data.
- Stream.EmitRecordWithArray(code, buffer, data);
- }
- template <typename BufferTy, typename ArrayTy>
- static void emit(llvm::BitstreamWriter &Stream, BufferTy &buffer,
- unsigned code, const ArrayTy &array) {
- #ifndef NDEBUG
- for (auto &element : array)
- ElementTy::assertValid(element);
- #endif
- buffer.reserve(buffer.size() + std::distance(array.begin(), array.end()));
- std::copy(array.begin(), array.end(), std::back_inserter(buffer));
- Stream.EmitRecordWithAbbrev(code, buffer);
- }
- template <typename BufferTy, typename ElementDataTy, typename... DataTy>
- static void emit(llvm::BitstreamWriter &Stream, BufferTy &buffer,
- unsigned code, ElementDataTy element, DataTy... data) {
- std::array<ElementDataTy, 1 + sizeof...(data)> array{{element, data...}};
- emit(Stream, buffer, code, array);
- }
- template <typename BufferTy>
- static void emit(llvm::BitstreamWriter &Stream, BufferTy &Buffer,
- unsigned code, std::nullopt_t) {
- Stream.EmitRecordWithAbbrev(code, Buffer);
- }
- template <typename T>
- static void read(ArrayRef<T> Buffer, ArrayRef<T> &rawData) {
- rawData = Buffer;
- }
- template <typename T, typename ArrayTy>
- static void read(ArrayRef<T> buffer, ArrayTy &array) {
- array.append(llvm::map_iterator(buffer.begin(), T::convert),
- llvm::map_iterator(buffer.end(), T::convert));
- }
- template <typename T> static void read(ArrayRef<T> buffer, std::nullopt_t) {
- (void)buffer;
- }
- template <typename T> static void read(ArrayRef<T> buffer) = delete;
- };
- /// Helper class for dealing with a blob at the end of a record.
- ///
- /// \sa BCRecordLayout
- template <> class BCRecordCoding<BCBlob> {
- public:
- template <typename BufferTy>
- static void emit(llvm::BitstreamWriter &Stream, BufferTy &buffer,
- unsigned code, StringRef data) {
- Stream.EmitRecordWithBlob(code, buffer, data);
- }
- template <typename T> static void read(ArrayRef<T> buffer) { (void)buffer; }
- /// Blob data is not stored in the buffer if you are using the correct
- /// accessor; this method should not be used.
- template <typename T, typename DataTy>
- static void read(ArrayRef<T> buffer, DataTy &data) = delete;
- };
- /// A type trait whose \c type field is the last of its template parameters.
- template <typename Head, typename... Tail> struct last_type {
- using type = typename last_type<Tail...>::type;
- };
- template <typename Head> struct last_type<Head> { using type = Head; };
- /// A type trait whose \c value field is \c true if the last type is BCBlob.
- template <typename... Types>
- using has_blob = std::is_same<BCBlob, typename last_type<int, Types...>::type>;
- /// A type trait whose \c value field is \c true if the given type is a
- /// BCArray (of any element kind).
- template <typename T> struct is_array {
- private:
- template <typename E> static bool check(BCArray<E> *);
- static int check(...);
- public:
- typedef bool value_type;
- static constexpr bool value = !std::is_same<decltype(check((T *)nullptr)),
- decltype(check(false))>::value;
- };
- /// A type trait whose \c value field is \c true if the last type is a
- /// BCArray (of any element kind).
- template <typename... Types>
- using has_array = is_array<typename last_type<int, Types...>::type>;
- } // namespace detail
- /// Represents a single bitcode record type.
- ///
- /// This class template is meant to be instantiated and then given a name,
- /// so that from then on that name can be used.
- template <typename IDField, typename... Fields> class BCGenericRecordLayout {
- llvm::BitstreamWriter &Stream;
- public:
- /// The abbreviation code used for this record in the current block.
- ///
- /// Note that this is not the same as the semantic record code, which is the
- /// first field of the record.
- const unsigned AbbrevCode;
- /// Create a layout and register it with the given bitstream writer.
- explicit BCGenericRecordLayout(llvm::BitstreamWriter &Stream)
- : Stream(Stream), AbbrevCode(emitAbbrev(Stream)) {}
- /// Emit a record to the bitstream writer, using the given buffer for scratch
- /// space.
- ///
- /// Note that even fixed arguments must be specified here.
- template <typename BufferTy, typename... Data>
- void emit(BufferTy &buffer, unsigned id, Data &&...data) const {
- emitRecord(Stream, buffer, AbbrevCode, id, std::forward<Data>(data)...);
- }
- /// Registers this record's layout with the bitstream reader.
- ///
- /// eturns The abbreviation code for the newly-registered record type.
- static unsigned emitAbbrev(llvm::BitstreamWriter &Stream) {
- auto Abbrev = std::make_shared<llvm::BitCodeAbbrev>();
- detail::emitOps<IDField, Fields...>(*Abbrev);
- return Stream.EmitAbbrev(std::move(Abbrev));
- }
- /// Emit a record identified by \p abbrCode to bitstream reader \p Stream,
- /// using \p buffer for scratch space.
- ///
- /// Note that even fixed arguments must be specified here. Blobs are passed
- /// as StringRefs, while arrays can be passed inline, as aggregates, or as
- /// pre-encoded StringRef data. Skipped values and empty arrays should use
- /// the special Nothing value.
- template <typename BufferTy, typename... Data>
- static void emitRecord(llvm::BitstreamWriter &Stream, BufferTy &buffer,
- unsigned abbrCode, unsigned recordID, Data &&...data) {
- static_assert(sizeof...(data) <= sizeof...(Fields) ||
- detail::has_array<Fields...>::value,
- "Too many record elements");
- static_assert(sizeof...(data) >= sizeof...(Fields),
- "Too few record elements");
- buffer.clear();
- detail::BCRecordCoding<IDField, Fields...>::emit(
- Stream, buffer, abbrCode, recordID, std::forward<Data>(data)...);
- }
- /// Extract record data from \p buffer into the given data fields.
- ///
- /// Note that even fixed arguments must be specified here. Pass \c Nothing
- /// if you don't care about a particular parameter. Blob data is not included
- /// in the buffer and should be handled separately by the caller.
- template <typename ElementTy, typename... Data>
- static void readRecord(ArrayRef<ElementTy> buffer, Data &&...data) {
- static_assert(sizeof...(data) <= sizeof...(Fields),
- "Too many record elements");
- static_assert(sizeof...(Fields) <=
- sizeof...(data) + detail::has_blob<Fields...>::value,
- "Too few record elements");
- return detail::BCRecordCoding<Fields...>::read(buffer,
- std::forward<Data>(data)...);
- }
- /// Extract record data from \p buffer into the given data fields.
- ///
- /// Note that even fixed arguments must be specified here. Pass \c Nothing
- /// if you don't care about a particular parameter. Blob data is not included
- /// in the buffer and should be handled separately by the caller.
- template <typename BufferTy, typename... Data>
- static void readRecord(BufferTy &buffer, Data &&...data) {
- return readRecord(llvm::ArrayRef(buffer), std::forward<Data>(data)...);
- }
- };
- /// A record with a fixed record code.
- template <unsigned RecordCode, typename... Fields>
- class BCRecordLayout
- : public BCGenericRecordLayout<BCLiteral<RecordCode>, Fields...> {
- using Base = BCGenericRecordLayout<BCLiteral<RecordCode>, Fields...>;
- public:
- enum : unsigned {
- /// The record code associated with this layout.
- Code = RecordCode
- };
- /// Create a layout and register it with the given bitstream writer.
- explicit BCRecordLayout(llvm::BitstreamWriter &Stream) : Base(Stream) {}
- /// Emit a record to the bitstream writer, using the given buffer for scratch
- /// space.
- ///
- /// Note that even fixed arguments must be specified here.
- template <typename BufferTy, typename... Data>
- void emit(BufferTy &buffer, Data &&...data) const {
- Base::emit(buffer, RecordCode, std::forward<Data>(data)...);
- }
- /// Emit a record identified by \p abbrCode to bitstream reader \p Stream,
- /// using \p buffer for scratch space.
- ///
- /// Note that even fixed arguments must be specified here. Currently, arrays
- /// and blobs can only be passed as StringRefs.
- template <typename BufferTy, typename... Data>
- static void emitRecord(llvm::BitstreamWriter &Stream, BufferTy &buffer,
- unsigned abbrCode, Data &&...data) {
- Base::emitRecord(Stream, buffer, abbrCode, RecordCode,
- std::forward<Data>(data)...);
- }
- };
- /// RAII object to pair entering and exiting a sub-block.
- class BCBlockRAII {
- llvm::BitstreamWriter &Stream;
- public:
- BCBlockRAII(llvm::BitstreamWriter &Stream, unsigned block, unsigned abbrev)
- : Stream(Stream) {
- Stream.EnterSubblock(block, abbrev);
- }
- ~BCBlockRAII() { Stream.ExitBlock(); }
- };
- } // namespace llvm
- #endif
- #ifdef __GNUC__
- #pragma GCC diagnostic pop
- #endif
|