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