- //===- 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 
-