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 488