1 | //===- llvm/Type.h - Classes for handling data types ------------*- 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 | // This file contains the declaration of the Type class. For more "Type" |
10 | // stuff, look in DerivedTypes.h. |
11 | // |
12 | //===----------------------------------------------------------------------===// |
13 | |
14 | #ifndef LLVM_IR_TYPE_H |
15 | #define LLVM_IR_TYPE_H |
16 | |
17 | #include "llvm/ADT/ArrayRef.h" |
18 | #include "llvm/Support/CBindingWrapping.h" |
19 | #include "llvm/Support/Casting.h" |
20 | #include "llvm/Support/Compiler.h" |
21 | #include "llvm/Support/ErrorHandling.h" |
22 | #include "llvm/Support/TypeSize.h" |
23 | #include <cassert> |
24 | #include <cstdint> |
25 | #include <iterator> |
26 | |
27 | namespace llvm { |
28 | |
29 | class IntegerType; |
30 | struct fltSemantics; |
31 | class LLVMContext; |
32 | class PointerType; |
33 | class raw_ostream; |
34 | class StringRef; |
35 | template <typename PtrType> class SmallPtrSetImpl; |
36 | |
37 | /// The instances of the Type class are immutable: once they are created, |
38 | /// they are never changed. Also note that only one instance of a particular |
39 | /// type is ever created. Thus seeing if two types are equal is a matter of |
40 | /// doing a trivial pointer comparison. To enforce that no two equal instances |
41 | /// are created, Type instances can only be created via static factory methods |
42 | /// in class Type and in derived classes. Once allocated, Types are never |
43 | /// free'd. |
44 | /// |
45 | class Type { |
46 | public: |
47 | //===--------------------------------------------------------------------===// |
48 | /// Definitions of all of the base types for the Type system. Based on this |
49 | /// value, you can cast to a class defined in DerivedTypes.h. |
50 | /// Note: If you add an element to this, you need to add an element to the |
51 | /// Type::getPrimitiveType function, or else things will break! |
52 | /// Also update LLVMTypeKind and LLVMGetTypeKind () in the C binding. |
53 | /// |
54 | enum TypeID { |
55 | // PrimitiveTypes |
56 | HalfTyID = 0, ///< 16-bit floating point type |
57 | BFloatTyID, ///< 16-bit floating point type (7-bit significand) |
58 | FloatTyID, ///< 32-bit floating point type |
59 | DoubleTyID, ///< 64-bit floating point type |
60 | X86_FP80TyID, ///< 80-bit floating point type (X87) |
61 | FP128TyID, ///< 128-bit floating point type (112-bit significand) |
62 | PPC_FP128TyID, ///< 128-bit floating point type (two 64-bits, PowerPC) |
63 | VoidTyID, ///< type with no size |
64 | LabelTyID, ///< Labels |
65 | MetadataTyID, ///< Metadata |
66 | X86_MMXTyID, ///< MMX vectors (64 bits, X86 specific) |
67 | X86_AMXTyID, ///< AMX vectors (8192 bits, X86 specific) |
68 | TokenTyID, ///< Tokens |
69 | |
70 | // Derived types... see DerivedTypes.h file. |
71 | IntegerTyID, ///< Arbitrary bit width integers |
72 | FunctionTyID, ///< Functions |
73 | PointerTyID, ///< Pointers |
74 | StructTyID, ///< Structures |
75 | ArrayTyID, ///< Arrays |
76 | FixedVectorTyID, ///< Fixed width SIMD vector type |
77 | ScalableVectorTyID, ///< Scalable SIMD vector type |
78 | TypedPointerTyID, ///< Typed pointer used by some GPU targets |
79 | TargetExtTyID, ///< Target extension type |
80 | }; |
81 | |
82 | private: |
83 | /// This refers to the LLVMContext in which this type was uniqued. |
84 | LLVMContext &Context; |
85 | |
86 | TypeID ID : 8; // The current base type of this type. |
87 | unsigned SubclassData : 24; // Space for subclasses to store data. |
88 | // Note that this should be synchronized with |
89 | // MAX_INT_BITS value in IntegerType class. |
90 | |
91 | protected: |
92 | friend class LLVMContextImpl; |
93 | |
94 | explicit Type(LLVMContext &C, TypeID tid) |
95 | : Context(C), ID(tid), SubclassData(0) {} |
96 | ~Type() = default; |
97 | |
98 | unsigned getSubclassData() const { return SubclassData; } |
99 | |
100 | void setSubclassData(unsigned val) { |
101 | SubclassData = val; |
102 | // Ensure we don't have any accidental truncation. |
103 | assert(getSubclassData() == val && "Subclass data too large for field" ); |
104 | } |
105 | |
106 | /// Keeps track of how many Type*'s there are in the ContainedTys list. |
107 | unsigned NumContainedTys = 0; |
108 | |
109 | /// A pointer to the array of Types contained by this Type. For example, this |
110 | /// includes the arguments of a function type, the elements of a structure, |
111 | /// the pointee of a pointer, the element type of an array, etc. This pointer |
112 | /// may be 0 for types that don't contain other types (Integer, Double, |
113 | /// Float). |
114 | Type * const *ContainedTys = nullptr; |
115 | |
116 | public: |
117 | /// Print the current type. |
118 | /// Omit the type details if \p NoDetails == true. |
119 | /// E.g., let %st = type { i32, i16 } |
120 | /// When \p NoDetails is true, we only print %st. |
121 | /// Put differently, \p NoDetails prints the type as if |
122 | /// inlined with the operands when printing an instruction. |
123 | void print(raw_ostream &O, bool IsForDebug = false, |
124 | bool NoDetails = false) const; |
125 | |
126 | void dump() const; |
127 | |
128 | /// Return the LLVMContext in which this type was uniqued. |
129 | LLVMContext &getContext() const { return Context; } |
130 | |
131 | //===--------------------------------------------------------------------===// |
132 | // Accessors for working with types. |
133 | // |
134 | |
135 | /// Return the type id for the type. This will return one of the TypeID enum |
136 | /// elements defined above. |
137 | TypeID getTypeID() const { return ID; } |
138 | |
139 | /// Return true if this is 'void'. |
140 | bool isVoidTy() const { return getTypeID() == VoidTyID; } |
141 | |
142 | /// Return true if this is 'half', a 16-bit IEEE fp type. |
143 | bool isHalfTy() const { return getTypeID() == HalfTyID; } |
144 | |
145 | /// Return true if this is 'bfloat', a 16-bit bfloat type. |
146 | bool isBFloatTy() const { return getTypeID() == BFloatTyID; } |
147 | |
148 | /// Return true if this is a 16-bit float type. |
149 | bool is16bitFPTy() const { |
150 | return getTypeID() == BFloatTyID || getTypeID() == HalfTyID; |
151 | } |
152 | |
153 | /// Return true if this is 'float', a 32-bit IEEE fp type. |
154 | bool isFloatTy() const { return getTypeID() == FloatTyID; } |
155 | |
156 | /// Return true if this is 'double', a 64-bit IEEE fp type. |
157 | bool isDoubleTy() const { return getTypeID() == DoubleTyID; } |
158 | |
159 | /// Return true if this is x86 long double. |
160 | bool isX86_FP80Ty() const { return getTypeID() == X86_FP80TyID; } |
161 | |
162 | /// Return true if this is 'fp128'. |
163 | bool isFP128Ty() const { return getTypeID() == FP128TyID; } |
164 | |
165 | /// Return true if this is powerpc long double. |
166 | bool isPPC_FP128Ty() const { return getTypeID() == PPC_FP128TyID; } |
167 | |
168 | /// Return true if this is a well-behaved IEEE-like type, which has a IEEE |
169 | /// compatible layout as defined by APFloat::isIEEE(), and does not have |
170 | /// non-IEEE values, such as x86_fp80's unnormal values. |
171 | bool isIEEELikeFPTy() const { |
172 | switch (getTypeID()) { |
173 | case DoubleTyID: |
174 | case FloatTyID: |
175 | case HalfTyID: |
176 | case BFloatTyID: |
177 | case FP128TyID: |
178 | return true; |
179 | default: |
180 | return false; |
181 | } |
182 | } |
183 | |
184 | /// Return true if this is one of the floating-point types |
185 | bool isFloatingPointTy() const { |
186 | return isIEEELikeFPTy() || getTypeID() == X86_FP80TyID || |
187 | getTypeID() == PPC_FP128TyID; |
188 | } |
189 | |
190 | /// Returns true if this is a floating-point type that is an unevaluated sum |
191 | /// of multiple floating-point units. |
192 | /// An example of such a type is ppc_fp128, also known as double-double, which |
193 | /// consists of two IEEE 754 doubles. |
194 | bool isMultiUnitFPType() const { |
195 | return getTypeID() == PPC_FP128TyID; |
196 | } |
197 | |
198 | const fltSemantics &getFltSemantics() const; |
199 | |
200 | /// Return true if this is X86 MMX. |
201 | bool isX86_MMXTy() const { return getTypeID() == X86_MMXTyID; } |
202 | |
203 | /// Return true if this is X86 AMX. |
204 | bool isX86_AMXTy() const { return getTypeID() == X86_AMXTyID; } |
205 | |
206 | /// Return true if this is a target extension type. |
207 | bool isTargetExtTy() const { return getTypeID() == TargetExtTyID; } |
208 | |
209 | /// Return true if this is a target extension type with a scalable layout. |
210 | bool isScalableTargetExtTy() const; |
211 | |
212 | /// Return true if this is a type whose size is a known multiple of vscale. |
213 | bool isScalableTy() const; |
214 | |
215 | /// Return true if this is a FP type or a vector of FP. |
216 | bool isFPOrFPVectorTy() const { return getScalarType()->isFloatingPointTy(); } |
217 | |
218 | /// Return true if this is 'label'. |
219 | bool isLabelTy() const { return getTypeID() == LabelTyID; } |
220 | |
221 | /// Return true if this is 'metadata'. |
222 | bool isMetadataTy() const { return getTypeID() == MetadataTyID; } |
223 | |
224 | /// Return true if this is 'token'. |
225 | bool isTokenTy() const { return getTypeID() == TokenTyID; } |
226 | |
227 | /// True if this is an instance of IntegerType. |
228 | bool isIntegerTy() const { return getTypeID() == IntegerTyID; } |
229 | |
230 | /// Return true if this is an IntegerType of the given width. |
231 | bool isIntegerTy(unsigned Bitwidth) const; |
232 | |
233 | /// Return true if this is an integer type or a vector of integer types. |
234 | bool isIntOrIntVectorTy() const { return getScalarType()->isIntegerTy(); } |
235 | |
236 | /// Return true if this is an integer type or a vector of integer types of |
237 | /// the given width. |
238 | bool isIntOrIntVectorTy(unsigned BitWidth) const { |
239 | return getScalarType()->isIntegerTy(Bitwidth: BitWidth); |
240 | } |
241 | |
242 | /// Return true if this is an integer type or a pointer type. |
243 | bool isIntOrPtrTy() const { return isIntegerTy() || isPointerTy(); } |
244 | |
245 | /// True if this is an instance of FunctionType. |
246 | bool isFunctionTy() const { return getTypeID() == FunctionTyID; } |
247 | |
248 | /// True if this is an instance of StructType. |
249 | bool isStructTy() const { return getTypeID() == StructTyID; } |
250 | |
251 | /// True if this is an instance of ArrayType. |
252 | bool isArrayTy() const { return getTypeID() == ArrayTyID; } |
253 | |
254 | /// True if this is an instance of PointerType. |
255 | bool isPointerTy() const { return getTypeID() == PointerTyID; } |
256 | |
257 | /// True if this is an instance of an opaque PointerType. |
258 | LLVM_DEPRECATED("Use isPointerTy() instead" , "isPointerTy" ) |
259 | bool isOpaquePointerTy() const { return isPointerTy(); }; |
260 | |
261 | /// Return true if this is a pointer type or a vector of pointer types. |
262 | bool isPtrOrPtrVectorTy() const { return getScalarType()->isPointerTy(); } |
263 | |
264 | /// True if this is an instance of VectorType. |
265 | inline bool isVectorTy() const { |
266 | return getTypeID() == ScalableVectorTyID || getTypeID() == FixedVectorTyID; |
267 | } |
268 | |
269 | /// Return true if this type could be converted with a lossless BitCast to |
270 | /// type 'Ty'. For example, i8* to i32*. BitCasts are valid for types of the |
271 | /// same size only where no re-interpretation of the bits is done. |
272 | /// Determine if this type could be losslessly bitcast to Ty |
273 | bool canLosslesslyBitCastTo(Type *Ty) const; |
274 | |
275 | /// Return true if this type is empty, that is, it has no elements or all of |
276 | /// its elements are empty. |
277 | bool isEmptyTy() const; |
278 | |
279 | /// Return true if the type is "first class", meaning it is a valid type for a |
280 | /// Value. |
281 | bool isFirstClassType() const { |
282 | return getTypeID() != FunctionTyID && getTypeID() != VoidTyID; |
283 | } |
284 | |
285 | /// Return true if the type is a valid type for a register in codegen. This |
286 | /// includes all first-class types except struct and array types. |
287 | bool isSingleValueType() const { |
288 | return isFloatingPointTy() || isX86_MMXTy() || isIntegerTy() || |
289 | isPointerTy() || isVectorTy() || isX86_AMXTy() || isTargetExtTy(); |
290 | } |
291 | |
292 | /// Return true if the type is an aggregate type. This means it is valid as |
293 | /// the first operand of an insertvalue or extractvalue instruction. This |
294 | /// includes struct and array types, but does not include vector types. |
295 | bool isAggregateType() const { |
296 | return getTypeID() == StructTyID || getTypeID() == ArrayTyID; |
297 | } |
298 | |
299 | /// Return true if it makes sense to take the size of this type. To get the |
300 | /// actual size for a particular target, it is reasonable to use the |
301 | /// DataLayout subsystem to do this. |
302 | bool isSized(SmallPtrSetImpl<Type*> *Visited = nullptr) const { |
303 | // If it's a primitive, it is always sized. |
304 | if (getTypeID() == IntegerTyID || isFloatingPointTy() || |
305 | getTypeID() == PointerTyID || getTypeID() == X86_MMXTyID || |
306 | getTypeID() == X86_AMXTyID) |
307 | return true; |
308 | // If it is not something that can have a size (e.g. a function or label), |
309 | // it doesn't have a size. |
310 | if (getTypeID() != StructTyID && getTypeID() != ArrayTyID && |
311 | !isVectorTy() && getTypeID() != TargetExtTyID) |
312 | return false; |
313 | // Otherwise we have to try harder to decide. |
314 | return isSizedDerivedType(Visited); |
315 | } |
316 | |
317 | /// Return the basic size of this type if it is a primitive type. These are |
318 | /// fixed by LLVM and are not target-dependent. |
319 | /// This will return zero if the type does not have a size or is not a |
320 | /// primitive type. |
321 | /// |
322 | /// If this is a scalable vector type, the scalable property will be set and |
323 | /// the runtime size will be a positive integer multiple of the base size. |
324 | /// |
325 | /// Note that this may not reflect the size of memory allocated for an |
326 | /// instance of the type or the number of bytes that are written when an |
327 | /// instance of the type is stored to memory. The DataLayout class provides |
328 | /// additional query functions to provide this information. |
329 | /// |
330 | TypeSize getPrimitiveSizeInBits() const LLVM_READONLY; |
331 | |
332 | /// If this is a vector type, return the getPrimitiveSizeInBits value for the |
333 | /// element type. Otherwise return the getPrimitiveSizeInBits value for this |
334 | /// type. |
335 | unsigned getScalarSizeInBits() const LLVM_READONLY; |
336 | |
337 | /// Return the width of the mantissa of this type. This is only valid on |
338 | /// floating-point types. If the FP type does not have a stable mantissa (e.g. |
339 | /// ppc long double), this method returns -1. |
340 | int getFPMantissaWidth() const; |
341 | |
342 | /// Return whether the type is IEEE compatible, as defined by the eponymous |
343 | /// method in APFloat. |
344 | bool isIEEE() const; |
345 | |
346 | /// If this is a vector type, return the element type, otherwise return |
347 | /// 'this'. |
348 | inline Type *getScalarType() const { |
349 | if (isVectorTy()) |
350 | return getContainedType(i: 0); |
351 | return const_cast<Type *>(this); |
352 | } |
353 | |
354 | //===--------------------------------------------------------------------===// |
355 | // Type Iteration support. |
356 | // |
357 | using subtype_iterator = Type * const *; |
358 | |
359 | subtype_iterator subtype_begin() const { return ContainedTys; } |
360 | subtype_iterator subtype_end() const { return &ContainedTys[NumContainedTys];} |
361 | ArrayRef<Type*> subtypes() const { |
362 | return ArrayRef(subtype_begin(), subtype_end()); |
363 | } |
364 | |
365 | using subtype_reverse_iterator = std::reverse_iterator<subtype_iterator>; |
366 | |
367 | subtype_reverse_iterator subtype_rbegin() const { |
368 | return subtype_reverse_iterator(subtype_end()); |
369 | } |
370 | subtype_reverse_iterator subtype_rend() const { |
371 | return subtype_reverse_iterator(subtype_begin()); |
372 | } |
373 | |
374 | /// This method is used to implement the type iterator (defined at the end of |
375 | /// the file). For derived types, this returns the types 'contained' in the |
376 | /// derived type. |
377 | Type *getContainedType(unsigned i) const { |
378 | assert(i < NumContainedTys && "Index out of range!" ); |
379 | return ContainedTys[i]; |
380 | } |
381 | |
382 | /// Return the number of types in the derived type. |
383 | unsigned getNumContainedTypes() const { return NumContainedTys; } |
384 | |
385 | //===--------------------------------------------------------------------===// |
386 | // Helper methods corresponding to subclass methods. This forces a cast to |
387 | // the specified subclass and calls its accessor. "getArrayNumElements" (for |
388 | // example) is shorthand for cast<ArrayType>(Ty)->getNumElements(). This is |
389 | // only intended to cover the core methods that are frequently used, helper |
390 | // methods should not be added here. |
391 | |
392 | inline unsigned getIntegerBitWidth() const; |
393 | |
394 | inline Type *getFunctionParamType(unsigned i) const; |
395 | inline unsigned getFunctionNumParams() const; |
396 | inline bool isFunctionVarArg() const; |
397 | |
398 | inline StringRef getStructName() const; |
399 | inline unsigned getStructNumElements() const; |
400 | inline Type *getStructElementType(unsigned N) const; |
401 | |
402 | inline uint64_t getArrayNumElements() const; |
403 | |
404 | Type *getArrayElementType() const { |
405 | assert(getTypeID() == ArrayTyID); |
406 | return ContainedTys[0]; |
407 | } |
408 | |
409 | inline StringRef getTargetExtName() const; |
410 | |
411 | /// Only use this method in code that is not reachable with opaque pointers, |
412 | /// or part of deprecated methods that will be removed as part of the opaque |
413 | /// pointers transition. |
414 | [[deprecated("Pointers no longer have element types" )]] |
415 | Type *getNonOpaquePointerElementType() const { |
416 | llvm_unreachable("Pointers no longer have element types" ); |
417 | } |
418 | |
419 | /// Given vector type, change the element type, |
420 | /// whilst keeping the old number of elements. |
421 | /// For non-vectors simply returns \p EltTy. |
422 | inline Type *getWithNewType(Type *EltTy) const; |
423 | |
424 | /// Given an integer or vector type, change the lane bitwidth to NewBitwidth, |
425 | /// whilst keeping the old number of lanes. |
426 | inline Type *getWithNewBitWidth(unsigned NewBitWidth) const; |
427 | |
428 | /// Given scalar/vector integer type, returns a type with elements twice as |
429 | /// wide as in the original type. For vectors, preserves element count. |
430 | inline Type *getExtendedType() const; |
431 | |
432 | /// Get the address space of this pointer or pointer vector type. |
433 | inline unsigned getPointerAddressSpace() const; |
434 | |
435 | //===--------------------------------------------------------------------===// |
436 | // Static members exported by the Type class itself. Useful for getting |
437 | // instances of Type. |
438 | // |
439 | |
440 | /// Return a type based on an identifier. |
441 | static Type *getPrimitiveType(LLVMContext &C, TypeID IDNumber); |
442 | |
443 | //===--------------------------------------------------------------------===// |
444 | // These are the builtin types that are always available. |
445 | // |
446 | static Type *getVoidTy(LLVMContext &C); |
447 | static Type *getLabelTy(LLVMContext &C); |
448 | static Type *getHalfTy(LLVMContext &C); |
449 | static Type *getBFloatTy(LLVMContext &C); |
450 | static Type *getFloatTy(LLVMContext &C); |
451 | static Type *getDoubleTy(LLVMContext &C); |
452 | static Type *getMetadataTy(LLVMContext &C); |
453 | static Type *getX86_FP80Ty(LLVMContext &C); |
454 | static Type *getFP128Ty(LLVMContext &C); |
455 | static Type *getPPC_FP128Ty(LLVMContext &C); |
456 | static Type *getX86_MMXTy(LLVMContext &C); |
457 | static Type *getX86_AMXTy(LLVMContext &C); |
458 | static Type *getTokenTy(LLVMContext &C); |
459 | static IntegerType *getIntNTy(LLVMContext &C, unsigned N); |
460 | static IntegerType *getInt1Ty(LLVMContext &C); |
461 | static IntegerType *getInt8Ty(LLVMContext &C); |
462 | static IntegerType *getInt16Ty(LLVMContext &C); |
463 | static IntegerType *getInt32Ty(LLVMContext &C); |
464 | static IntegerType *getInt64Ty(LLVMContext &C); |
465 | static IntegerType *getInt128Ty(LLVMContext &C); |
466 | template <typename ScalarTy> static Type *getScalarTy(LLVMContext &C) { |
467 | int noOfBits = sizeof(ScalarTy) * CHAR_BIT; |
468 | if (std::is_integral<ScalarTy>::value) { |
469 | return (Type*) Type::getIntNTy(C, N: noOfBits); |
470 | } else if (std::is_floating_point<ScalarTy>::value) { |
471 | switch (noOfBits) { |
472 | case 32: |
473 | return Type::getFloatTy(C); |
474 | case 64: |
475 | return Type::getDoubleTy(C); |
476 | } |
477 | } |
478 | llvm_unreachable("Unsupported type in Type::getScalarTy" ); |
479 | } |
480 | static Type *getFloatingPointTy(LLVMContext &C, const fltSemantics &S); |
481 | |
482 | //===--------------------------------------------------------------------===// |
483 | // Convenience methods for getting pointer types. |
484 | // |
485 | static Type *getWasm_ExternrefTy(LLVMContext &C); |
486 | static Type *getWasm_FuncrefTy(LLVMContext &C); |
487 | |
488 | /// Return a pointer to the current type. This is equivalent to |
489 | /// PointerType::get(Foo, AddrSpace). |
490 | /// TODO: Remove this after opaque pointer transition is complete. |
491 | PointerType *getPointerTo(unsigned AddrSpace = 0) const; |
492 | |
493 | private: |
494 | /// Derived types like structures and arrays are sized iff all of the members |
495 | /// of the type are sized as well. Since asking for their size is relatively |
496 | /// uncommon, move this operation out-of-line. |
497 | bool isSizedDerivedType(SmallPtrSetImpl<Type*> *Visited = nullptr) const; |
498 | }; |
499 | |
500 | // Printing of types. |
501 | inline raw_ostream &operator<<(raw_ostream &OS, const Type &T) { |
502 | T.print(O&: OS); |
503 | return OS; |
504 | } |
505 | |
506 | // allow isa<PointerType>(x) to work without DerivedTypes.h included. |
507 | template <> struct isa_impl<PointerType, Type> { |
508 | static inline bool doit(const Type &Ty) { |
509 | return Ty.getTypeID() == Type::PointerTyID; |
510 | } |
511 | }; |
512 | |
513 | // Create wrappers for C Binding types (see CBindingWrapping.h). |
514 | DEFINE_ISA_CONVERSION_FUNCTIONS(Type, LLVMTypeRef) |
515 | |
516 | /* Specialized opaque type conversions. |
517 | */ |
518 | inline Type **unwrap(LLVMTypeRef* Tys) { |
519 | return reinterpret_cast<Type**>(Tys); |
520 | } |
521 | |
522 | inline LLVMTypeRef *wrap(Type **Tys) { |
523 | return reinterpret_cast<LLVMTypeRef*>(const_cast<Type**>(Tys)); |
524 | } |
525 | |
526 | } // end namespace llvm |
527 | |
528 | #endif // LLVM_IR_TYPE_H |
529 | |