LLVM 20.0.0git
BitcodeConvenience.h
Go to the documentation of this file.
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
35#include <cstdint>
36#include <optional>
37
38namespace llvm {
39namespace detail {
40/// Convenience base for all kinds of bitcode abbreviation fields.
41///
42/// This just defines common properties queried by the metaprogramming.
43template <bool Compound = false> class BCField {
44public:
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.
64template <uint64_t Value> class BCLiteral : public detail::BCField<> {
65public:
66 static void emitOp(llvm::BitCodeAbbrev &abbrev) {
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.
78template <unsigned Width> class BCFixed : public detail::BCField<> {
79public:
80 static_assert(Width <= 64, "fixed-width field is too large");
81
82 static void emitOp(llvm::BitCodeAbbrev &abbrev) {
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.
103template <unsigned Width> class BCVBR : public detail::BCField<> {
104 static_assert(Width >= 2, "width does not have room for continuation bit");
105
106public:
107 static void emitOp(llvm::BitCodeAbbrev &abbrev) {
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
122class BCChar6 : public detail::BCField<> {
123public:
124 static void emitOp(llvm::BitCodeAbbrev &abbrev) {
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.
140class BCBlob : public detail::BCField<true> {
141public:
142 static void emitOp(llvm::BitCodeAbbrev &abbrev) {
144 }
145};
146
147/// Represents an array of some other type.
148///
149/// If present, this must be the last field in a record.
150template <typename ElementTy> class BCArray : public detail::BCField<true> {
151 static_assert(!ElementTy::IsCompound, "arrays can only contain scalar types");
152
153public:
154 static void emitOp(llvm::BitCodeAbbrev &abbrev) {
156 ElementTy::emitOp(abbrev);
157 }
158};
159
160namespace detail {
161/// Attaches the last field to an abbreviation.
162///
163/// This is the base case for \c emitOps.
164///
165/// \sa BCRecordLayout::emitAbbrev
166template <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
175template <typename FieldTy, typename Next, typename... Rest>
176static 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
186template <typename ElementTy, typename... Fields> class BCRecordCoding {
187public:
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());
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");
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
223template <typename ElementTy> class BCRecordCoding<ElementTy> {
224public:
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
252template <typename ElementTy> class BCRecordCoding<BCArray<ElementTy>> {
253public:
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
307template <> class BCRecordCoding<BCBlob> {
308public:
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.
324template <typename Head, typename... Tail> struct last_type {
325 using type = typename last_type<Tail...>::type;
326};
327
328template <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.
331template <typename... Types>
332using 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).
336template <typename T> struct is_array {
337private:
338 template <typename E> static bool check(BCArray<E> *);
339 static int check(...);
340
341public:
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).
349template <typename... Types>
350using 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.
357template <typename IDField, typename... Fields> class BCGenericRecordLayout {
358 llvm::BitstreamWriter &Stream;
359
360public:
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.
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();
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");
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.
437template <unsigned RecordCode, typename... Fields>
439 : public BCGenericRecordLayout<BCLiteral<RecordCode>, Fields...> {
441
442public:
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.
475 llvm::BitstreamWriter &Stream;
476
477public:
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
Given that RA is a live value
#define T
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
unify loop Fixup each natural loop to have a single exit block
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition: ArrayRef.h:41
const T & front() const
front - Get the first element.
Definition: ArrayRef.h:168
iterator end() const
Definition: ArrayRef.h:154
size_t size() const
size - Get the array size.
Definition: ArrayRef.h:165
iterator begin() const
Definition: ArrayRef.h:153
bool empty() const
empty - Check if the array is empty.
Definition: ArrayRef.h:160
ArrayRef< T > slice(size_t N, size_t M) const
slice(n, m) - Chop off the first N elements of the array, and keep M elements in the array.
Definition: ArrayRef.h:195
Represents an array of some other type.
static void emitOp(llvm::BitCodeAbbrev &abbrev)
Represents an untyped blob of bytes.
static void emitOp(llvm::BitCodeAbbrev &abbrev)
RAII object to pair entering and exiting a sub-block.
BCBlockRAII(llvm::BitstreamWriter &Stream, unsigned block, unsigned abbrev)
Represents a character encoded in LLVM's Char6 encoding.
char convert(T rawValue)
static void assertValid(const T &data)
static void emitOp(llvm::BitCodeAbbrev &abbrev)
Represents a fixed-width value in a bitcode record.
static void emitOp(llvm::BitCodeAbbrev &abbrev)
static void assertValid(const bool &data)
static void assertValid(const T &data)
Represents a single bitcode record type.
static void readRecord(BufferTy &buffer, Data &&...data)
Extract record data from buffer into the given data fields.
static unsigned emitAbbrev(llvm::BitstreamWriter &Stream)
Registers this record's layout with the bitstream reader.
BCGenericRecordLayout(llvm::BitstreamWriter &Stream)
Create a layout and register it with the given bitstream writer.
static void readRecord(ArrayRef< ElementTy > buffer, Data &&...data)
Extract record data from buffer into the given data fields.
const unsigned AbbrevCode
The abbreviation code used for this record in the current block.
static void emitRecord(llvm::BitstreamWriter &Stream, BufferTy &buffer, unsigned abbrCode, unsigned recordID, Data &&...data)
Emit a record identified by abbrCode to bitstream reader Stream, using buffer for scratch space.
void emit(BufferTy &buffer, unsigned id, Data &&...data) const
Emit a record to the bitstream writer, using the given buffer for scratch space.
Represents a literal operand in a bitcode record.
static void emitOp(llvm::BitCodeAbbrev &abbrev)
static void assertValid(const T &data)
A record with a fixed record code.
void emit(BufferTy &buffer, Data &&...data) const
Emit a record to the bitstream writer, using the given buffer for scratch space.
BCRecordLayout(llvm::BitstreamWriter &Stream)
Create a layout and register it with the given bitstream writer.
static void emitRecord(llvm::BitstreamWriter &Stream, BufferTy &buffer, unsigned abbrCode, Data &&...data)
Emit a record identified by abbrCode to bitstream reader Stream, using buffer for scratch space.
@ Code
The record code associated with this layout.
Represents a variable-width value in a bitcode record.
static void assertValid(const T &data)
static void emitOp(llvm::BitCodeAbbrev &abbrev)
BitCodeAbbrevOp - This describes one or more operands in an abbreviation.
Definition: BitCodes.h:33
static bool isChar6(char C)
isChar6 - Return true if this character is legal in the Char6 encoding.
Definition: BitCodes.h:82
BitCodeAbbrev - This class represents an abbreviation record.
Definition: BitCodes.h:103
void Add(const BitCodeAbbrevOp &OpInfo)
Definition: BitCodes.h:119
unsigned EmitAbbrev(std::shared_ptr< BitCodeAbbrev > Abbv)
Emits the abbreviation Abbv to the stream.
void EmitRecordWithBlob(unsigned Abbrev, const Container &Vals, StringRef Blob)
EmitRecordWithBlob - Emit the specified record to the stream, using an abbrev that includes a blob at...
void EmitRecordWithArray(unsigned Abbrev, const Container &Vals, StringRef Array)
EmitRecordWithArray - Just like EmitRecordWithBlob, works with records that end with an array.
void EnterSubblock(unsigned BlockID, unsigned CodeLen)
void EmitRecordWithAbbrev(unsigned Abbrev, const Container &Vals)
EmitRecordWithAbbrev - Emit a record with the specified abbreviation.
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:50
LLVM Value Representation.
Definition: Value.h:74
Convenience base for all kinds of bitcode abbreviation fields.
static const bool IsCompound
static void assertValid(const T &data)
Asserts that the given data is a valid value for this field.
static T convert(T rawValue)
Converts a raw numeric representation of this value to its preferred type.
static void emit(llvm::BitstreamWriter &Stream, BufferTy &buffer, unsigned code, StringRef data)
static void read(ArrayRef< T > buffer, std::nullopt_t)
static void read(ArrayRef< T > buffer)=delete
static void emit(llvm::BitstreamWriter &Stream, BufferTy &Buffer, unsigned code, std::nullopt_t)
static void emit(llvm::BitstreamWriter &Stream, BufferTy &buffer, unsigned code, ElementDataTy element, DataTy... data)
static void read(ArrayRef< T > buffer, ArrayTy &array)
static void read(ArrayRef< T > Buffer, ArrayRef< T > &rawData)
static void emit(llvm::BitstreamWriter &Stream, BufferTy &buffer, unsigned code, const ArrayTy &array)
static void emit(llvm::BitstreamWriter &Stream, BufferTy &buffer, unsigned code, StringRef data)
static void read(ArrayRef< T > buffer, DataTy &data)=delete
Blob data is not stored in the buffer if you are using the correct accessor; this method should not b...
static void read(ArrayRef< T > buffer)
static void emit(llvm::BitstreamWriter &Stream, BufferTy &buffer, unsigned code, const DataTy &data)
static void read(ArrayRef< T > buffer, std::nullopt_t)
static void read(ArrayRef< T > buffer)=delete
static void read(ArrayRef< T > buffer, DataTy &data)
Helper class for dealing with a scalar element in the middle of a record.
static void read(ArrayRef< T > buffer, ElementDataTy &element, DataTy &&...data)
static void emit(llvm::BitstreamWriter &Stream, BufferTy &buffer, unsigned code, ElementDataTy element, DataTy &&...data)
static void read(ArrayRef< T > buffer, std::nullopt_t, DataTy &&...data)
@ Tail
Attemps to make calls as fast as possible while guaranteeing that tail call optimization can always b...
Definition: CallingConv.h:76
static void emitOps(llvm::BitCodeAbbrev &abbrev)
Attaches the last field to an abbreviation.
std::is_same< BCBlob, typename last_type< int, Types... >::type > has_blob
A type trait whose value field is true if the last type is BCBlob.
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
mapped_iterator< ItTy, FuncTy > map_iterator(ItTy I, FuncTy F)
Definition: STLExtras.h:372
A type trait whose value field is true if the given type is a BCArray (of any element kind).
static constexpr bool value
A type trait whose type field is the last of its template parameters.
typename last_type< Tail... >::type type