llvm_ir/
types.rs

1use crate::module::AddrSpace;
2use either::Either;
3use std::borrow::Borrow;
4use std::collections::HashMap;
5use std::fmt::{self, Display};
6use std::hash::Hash;
7use std::ops::Deref;
8use std::sync::Arc;
9
10/// See [LLVM 14 docs on Type System](https://releases.llvm.org/14.0.0/docs/LangRef.html#type-system)
11#[derive(PartialEq, Eq, Clone, Debug, Hash)]
12#[allow(non_camel_case_types)]
13pub enum Type {
14    /// See [LLVM 14 docs on Void Type](https://releases.llvm.org/14.0.0/docs/LangRef.html#void-type)
15    VoidType,
16    /// See [LLVM 14 docs on Integer Type](https://releases.llvm.org/14.0.0/docs/LangRef.html#integer-type)
17    IntegerType { bits: u32 },
18    /// See [LLVM 14 docs on Pointer Type](https://releases.llvm.org/14.0.0/docs/LangRef.html#pointer-type)
19    #[cfg(feature = "llvm-14-or-lower")]
20    PointerType {
21        pointee_type: TypeRef,
22        addr_space: AddrSpace,
23    },
24    /// See [LLVM 15 docs on Pointer Type](https://releases.llvm.org/15.0.0/docs/LangRef.html#pointer-type)
25    /// and [this documentation on Opaque Pointers, introduced in LLVM 15](https://releases.llvm.org/15.0.0/docs/OpaquePointers.html)
26    #[cfg(feature = "llvm-15-or-greater")]
27    PointerType { addr_space: AddrSpace },
28    /// See [LLVM 14 docs on Floating-Point Types](https://releases.llvm.org/14.0.0/docs/LangRef.html#floating-point-types)
29    FPType(FPType),
30    /// See [LLVM 14 docs on Function Type](https://releases.llvm.org/14.0.0/docs/LangRef.html#function-type)
31    FuncType {
32        result_type: TypeRef,
33        param_types: Vec<TypeRef>,
34        is_var_arg: bool,
35    },
36    /// Vector types (along with integer, FP, pointer, X86_MMX, and X86_AMX types) are "first class types",
37    /// which means they can be produced by instructions (see [LLVM 14 docs on First Class Types](https://releases.llvm.org/14.0.0/docs/LangRef.html#first-class-types)).
38    /// See [LLVM 14 docs on Vector Type](https://releases.llvm.org/14.0.0/docs/LangRef.html#vector-type)
39    VectorType {
40        element_type: TypeRef,
41        num_elements: usize,
42        #[cfg(feature = "llvm-11-or-greater")]
43        scalable: bool,
44    },
45    /// Struct and Array types (but not vector types) are "aggregate types" and cannot be produced by
46    /// a single instruction (see [LLVM 14 docs on Aggregate Types](https://releases.llvm.org/14.0.0/docs/LangRef.html#aggregate-types)).
47    /// See [LLVM 14 docs on Array Type](https://releases.llvm.org/14.0.0/docs/LangRef.html#array-type)
48    ArrayType {
49        element_type: TypeRef,
50        num_elements: usize,
51    },
52    /// The `StructType` variant is used for a "literal" (i.e., anonymous) structure type.
53    /// See [LLVM 14 docs on Structure Type](https://releases.llvm.org/14.0.0/docs/LangRef.html#structure-type)
54    StructType {
55        element_types: Vec<TypeRef>,
56        is_packed: bool,
57    },
58    /// Named structure types. Note that these may be self-referential (i.e., recursive).
59    /// See [LLVM 14 docs on Structure Type](https://releases.llvm.org/14.0.0/docs/LangRef.html#structure-type)
60    /// To get the actual definition of a named structure type, use `module.types.named_struct_def()`.
61    NamedStructType {
62        /// Name of the struct type
63        name: String, // llvm-hs-pure has Name rather than String
64    },
65    /// See [LLVM 14 docs on X86_MMX Type](https://releases.llvm.org/14.0.0/docs/LangRef.html#x86-mmx-type)
66    X86_MMXType,
67    // As of this writing, although X86_AMX type definitely exists in LLVM 12+,
68    // it doesn't appear to be documented in the LangRef
69    #[cfg(feature = "llvm-12-or-greater")]
70    X86_AMXType,
71    /// See [LLVM 14 docs on Metadata Type](https://releases.llvm.org/14.0.0/docs/LangRef.html#metadata-type)
72    MetadataType,
73    /// `LabelType` is the type of [`BasicBlock`](../struct.BasicBlock.html) labels.
74    /// See [LLVM 14 docs on Label Type](https://releases.llvm.org/14.0.0/docs/LangRef.html#label-type)
75    LabelType,
76    /// See [LLVM 14 docs on Token Type](https://releases.llvm.org/14.0.0/docs/LangRef.html#token-type)
77    TokenType,
78    /// See [LLVM 16 docs on Target Extension Type](https://releases.llvm.org/16.0.0/docs/LangRef.html#target-extension-type).
79    ///
80    /// `TargetExtType` needs more fields, but the necessary getter functions
81    /// are apparently not exposed in the LLVM C API (only the C++ API).
82    /// See discussion in #39.
83    #[cfg(feature = "llvm-16-or-greater")]
84    TargetExtType, // TODO ideally we want something like TargetExtType { name: String, contained_types: Vec<TypeRef>, contained_ints: Vec<u32> }
85}
86
87impl Display for Type {
88    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
89        match self {
90            Type::VoidType => write!(f, "void"),
91            Type::IntegerType { bits } => write!(f, "i{}", bits),
92            #[cfg(feature = "llvm-14-or-lower")]
93            Type::PointerType { pointee_type, .. } => write!(f, "{}*", pointee_type),
94            #[cfg(feature = "llvm-15-or-greater")]
95            Type::PointerType { .. } => write!(f, "ptr"),
96            Type::FPType(fpt) => write!(f, "{}", fpt),
97            Type::FuncType {
98                result_type,
99                param_types,
100                is_var_arg,
101            } => {
102                write!(f, "{} (", result_type)?;
103                for (i, param_ty) in param_types.iter().enumerate() {
104                    if i == param_types.len() - 1 {
105                        write!(f, "{}", param_ty)?;
106                    } else {
107                        write!(f, "{}, ", param_ty)?;
108                    }
109                }
110                if *is_var_arg {
111                    write!(f, ", ...")?;
112                }
113                write!(f, ")")?;
114                Ok(())
115            },
116            Type::VectorType {
117                element_type,
118                num_elements,
119                #[cfg(feature = "llvm-11-or-greater")]
120                scalable,
121            } => {
122                #[cfg(feature = "llvm-11-or-greater")]
123                if *scalable {
124                    write!(f, "<vscale x {} x {}>", num_elements, element_type)
125                } else {
126                    write!(f, "<{} x {}>", num_elements, element_type)
127                }
128                #[cfg(feature = "llvm-10-or-lower")]
129                write!(f, "<{} x {}>", num_elements, element_type)
130            },
131            Type::ArrayType {
132                element_type,
133                num_elements,
134            } => write!(f, "[{} x {}]", num_elements, element_type),
135            Type::StructType {
136                element_types,
137                is_packed,
138            } => {
139                if *is_packed {
140                    write!(f, "<")?;
141                }
142                write!(f, "{{ ")?;
143                for (i, element_ty) in element_types.iter().enumerate() {
144                    if i == element_types.len() - 1 {
145                        write!(f, "{}", element_ty)?;
146                    } else {
147                        write!(f, "{}, ", element_ty)?;
148                    }
149                }
150                write!(f, " }}")?;
151                if *is_packed {
152                    write!(f, ">")?;
153                }
154                Ok(())
155            },
156            Type::NamedStructType { name } => write!(f, "%{}", name),
157            Type::X86_MMXType => write!(f, "x86_mmx"),
158            #[cfg(feature = "llvm-12-or-greater")]
159            Type::X86_AMXType => write!(f, "x86_amx"),
160            Type::MetadataType => write!(f, "metadata"),
161            Type::LabelType => write!(f, "label"),
162            Type::TokenType => write!(f, "token"),
163            #[cfg(feature = "llvm-16-or-greater")]
164            Type::TargetExtType => write!(f, "target()"),
165                // someday if/when TargetExtType contains other fields, we need something like the below:
166                /*
167                // Name, then type parameters first then integer parameters.
168                let members = [name]
169                    .iter()
170                    .map(|name| format!("\"{name}\""))
171                    .chain(contained_types.iter().map(ToString::to_string))
172                    .chain(contained_ints.iter().map(ToString::to_string))
173                    .collect::<Vec<_>>()
174                    .join(", ");
175                write!(f, "target({members})")?;
176
177                Ok(())
178                */
179        }
180    }
181}
182
183/// See [LLVM 14 docs on Floating-Point Types](https://releases.llvm.org/14.0.0/docs/LangRef.html#floating-point-types)
184#[derive(PartialEq, Eq, Clone, Copy, Debug, Hash)]
185#[allow(non_camel_case_types)]
186pub enum FPType {
187    Half,
188    #[cfg(feature = "llvm-11-or-greater")]
189    BFloat,
190    Single,
191    Double,
192    FP128,
193    X86_FP80,
194    PPC_FP128,
195}
196
197impl From<FPType> for Type {
198    fn from(fpt: FPType) -> Type {
199        Type::FPType(fpt)
200    }
201}
202
203impl Display for FPType {
204    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
205        match self {
206            FPType::Half => write!(f, "half"),
207            #[cfg(feature = "llvm-11-or-greater")]
208            FPType::BFloat => write!(f, "bfloat"),
209            FPType::Single => write!(f, "float"),
210            FPType::Double => write!(f, "double"),
211            FPType::FP128 => write!(f, "fp128"),
212            FPType::X86_FP80 => write!(f, "x86_fp80"),
213            FPType::PPC_FP128 => write!(f, "ppc_fp128"),
214        }
215    }
216}
217
218/// A `TypeRef` is a reference to a [`Type`](enum.Type.html).
219/// Most importantly, it implements `AsRef<Type>` and `Deref<Target = Type>`.
220/// It also has a cheap `Clone` -- only the reference is cloned, not the
221/// underlying `Type`.
222//
223// `Arc` is used rather than `Rc` so that `Module` can remain `Sync`.
224// This is important because it allows multiple threads to simultaneously access
225// a single (immutable) `Module`.
226#[derive(PartialEq, Eq, Clone, Debug, Hash)]
227pub struct TypeRef(Arc<Type>);
228
229impl AsRef<Type> for TypeRef {
230    fn as_ref(&self) -> &Type {
231        self.0.as_ref()
232    }
233}
234
235impl Deref for TypeRef {
236    type Target = Type;
237
238    fn deref(&self) -> &Type {
239        self.0.deref()
240    }
241}
242
243impl Display for TypeRef {
244    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
245        write!(f, "{}", &self.0)
246    }
247}
248
249impl TypeRef {
250    /// For use only in this module: construct a `TypeRef` by consuming the given owned `Type`.
251    /// External users should get `TypeRefs` only from the `Types` or `TypesBuilder` objects.
252    fn new(ty: Type) -> Self {
253        Self(Arc::new(ty))
254    }
255}
256
257/// The `Typed` trait is used for anything that has a [`Type`](enum.Type.html).
258pub trait Typed {
259    fn get_type(&self, types: &Types) -> TypeRef;
260}
261
262impl Typed for TypeRef {
263    fn get_type(&self, _types: &Types) -> TypeRef {
264        self.clone()
265    }
266}
267
268impl Typed for Type {
269    fn get_type(&self, types: &Types) -> TypeRef {
270        types.get_for_type(self)
271    }
272}
273
274impl Typed for FPType {
275    fn get_type(&self, types: &Types) -> TypeRef {
276        types.fp(*self)
277    }
278}
279
280impl<A, B> Typed for Either<A, B>
281where
282    A: Typed,
283    B: Typed,
284{
285    fn get_type(&self, types: &Types) -> TypeRef {
286        match self {
287            Either::Left(x) => types.type_of(x),
288            Either::Right(y) => types.type_of(y),
289        }
290    }
291}
292
293/// Holds a reference to all of the `Type`s used in the `Module`, and facilitates
294/// lookups so you can get a `TypeRef` to the `Type` you want.
295#[derive(Clone)]
296pub(crate) struct TypesBuilder {
297    /// `TypeRef` to `Type::VoidType`
298    void_type: TypeRef,
299    /// Map of integer size to `Type::IntegerType` of that size
300    int_types: TypeCache<u32>,
301    /// Map of (pointee type, address space) to the corresponding `Type::PointerType`
302    #[cfg(feature = "llvm-14-or-lower")]
303    pointer_types: TypeCache<(TypeRef, AddrSpace)>,
304    /// Map of address space to the corresponding `Type::PointerType`
305    #[cfg(feature = "llvm-15-or-greater")]
306    pointer_types: TypeCache<AddrSpace>,
307    /// Map of `FPType` to the corresponding `Type::FPType`
308    fp_types: TypeCache<FPType>,
309    /// Map of `(result_type, param_types, is_var_arg)` to the corresponding `Type::FunctionType`
310    func_types: TypeCache<(TypeRef, Vec<TypeRef>, bool)>,
311    /// Map of (element type, #elements, scalable) to the corresponding `Type::VectorType`
312    vec_types: TypeCache<(TypeRef, usize, bool)>,
313    /// Map of (element type, #elements) to the corresponding `Type::ArrayType`
314    arr_types: TypeCache<(TypeRef, usize)>,
315    /// Map of `(element_types, is_packed)` to the corresponding `Type::StructType`
316    struct_types: TypeCache<(Vec<TypeRef>, bool)>,
317    /// Map of struct name to the corresponding `Type::NamedStructType`
318    named_struct_types: TypeCache<String>,
319    /// Map of struct name to the corresponding `NamedStructDef`
320    named_struct_defs: HashMap<String, NamedStructDef>,
321    /// `TypeRef` to `Type::X86_MMXType`
322    x86_mmx_type: TypeRef,
323    /// `TypeRef` to `Type::X86_AMXType`
324    #[cfg(feature = "llvm-12-or-greater")]
325    x86_amx_type: TypeRef,
326    /// `TypeRef` to `Type::MetadataType`
327    metadata_type: TypeRef,
328    /// `TypeRef` to `Type::LabelType`
329    label_type: TypeRef,
330    /// `TypeRef` to `Type::TokenType`
331    token_type: TypeRef,
332    /// `TypeRef` to `Type::TargetExtType`
333    // someday: Map of `(name, contained_types, contained_ints)` to the corresponding `Type::TargetExtType`. See notes on Type::TargetExtType
334    #[cfg(feature = "llvm-16-or-greater")]
335    target_ext_type: TypeRef,
336    /// internal cache of already-seen `LLVMTypeRef`s so we can quickly produce
337    /// the corresponding `TypeRef` without re-parsing the type
338    llvm_type_map: HashMap<LLVMTypeRef, TypeRef>,
339}
340
341impl TypesBuilder {
342    pub fn new() -> Self {
343        Self {
344            void_type: TypeRef::new(Type::VoidType),
345            int_types: TypeCache::new(),
346            pointer_types: TypeCache::new(),
347            fp_types: TypeCache::new(),
348            func_types: TypeCache::new(),
349            vec_types: TypeCache::new(),
350            arr_types: TypeCache::new(),
351            struct_types: TypeCache::new(),
352            named_struct_types: TypeCache::new(),
353            named_struct_defs: HashMap::new(),
354            x86_mmx_type: TypeRef::new(Type::X86_MMXType),
355            #[cfg(feature = "llvm-12-or-greater")]
356            x86_amx_type: TypeRef::new(Type::X86_AMXType),
357            metadata_type: TypeRef::new(Type::MetadataType),
358            label_type: TypeRef::new(Type::LabelType),
359            token_type: TypeRef::new(Type::TokenType),
360            #[cfg(feature = "llvm-16-or-greater")]
361            target_ext_type: TypeRef::new(Type::TargetExtType),
362            llvm_type_map: HashMap::new(),
363        }
364    }
365
366    /// Consumes the `TypesBuilder`, producing a `Types`.
367    /// This should be done when no new types are expected to be added;
368    /// and it allows type lookups without &mut self.
369    pub fn build(self) -> Types {
370        Types {
371            void_type: self.void_type,
372            int_types: self.int_types,
373            pointer_types: self.pointer_types,
374            fp_types: self.fp_types,
375            func_types: self.func_types,
376            vec_types: self.vec_types,
377            arr_types: self.arr_types,
378            struct_types: self.struct_types,
379            named_struct_types: self.named_struct_types,
380            named_struct_defs: self.named_struct_defs,
381            x86_mmx_type: self.x86_mmx_type,
382            #[cfg(feature = "llvm-12-or-greater")]
383            x86_amx_type: self.x86_amx_type,
384            metadata_type: self.metadata_type,
385            label_type: self.label_type,
386            token_type: self.token_type,
387            #[cfg(feature = "llvm-16-or-greater")]
388            target_ext_type: self.target_ext_type,
389        }
390    }
391}
392
393// some of these methods might not currently be used, that's fine
394#[allow(dead_code)]
395impl TypesBuilder {
396    /// Get the void type
397    pub fn void(&self) -> TypeRef {
398        self.void_type.clone()
399    }
400
401    /// Get the integer type of the specified size (in bits)
402    pub fn int(&mut self, bits: u32) -> TypeRef {
403        self.int_types
404            .lookup_or_insert(bits, || Type::IntegerType { bits })
405    }
406
407    /// Get the boolean type (`i1`)
408    pub fn bool(&mut self) -> TypeRef {
409        self.int(1)
410    }
411
412    /// Get the 8-bit integer type
413    pub fn i8(&mut self) -> TypeRef {
414        self.int(8)
415    }
416
417    /// Get the 16-bit integer type
418    pub fn i16(&mut self) -> TypeRef {
419        self.int(16)
420    }
421
422    /// Get the 32-bit integer type
423    pub fn i32(&mut self) -> TypeRef {
424        self.int(32)
425    }
426
427    /// Get the 64-bit integer type
428    pub fn i64(&mut self) -> TypeRef {
429        self.int(64)
430    }
431
432    /// Get a pointer type in the default address space (`0`)
433    #[cfg(feature = "llvm-14-or-lower")]
434    pub fn pointer_to(&mut self, pointee_type: TypeRef) -> TypeRef {
435        self.pointer_in_addr_space(pointee_type, 0) // default to address space 0
436    }
437    /// Get the pointer type for the default address space (`0`)
438    #[cfg(feature = "llvm-15-or-greater")]
439    pub fn pointer(&mut self) -> TypeRef {
440        self.pointer_in_addr_space(0) // default to address space 0
441    }
442
443    /// Get a pointer in the specified address space
444    #[cfg(feature = "llvm-14-or-lower")]
445    pub fn pointer_in_addr_space(
446        &mut self,
447        pointee_type: TypeRef,
448        addr_space: AddrSpace,
449    ) -> TypeRef {
450        self.pointer_types
451            .lookup_or_insert((pointee_type.clone(), addr_space), || Type::PointerType {
452                pointee_type,
453                addr_space,
454            })
455    }
456    /// Get a pointer in the specified address space
457    #[cfg(feature = "llvm-15-or-greater")]
458    pub fn pointer_in_addr_space(&mut self, addr_space: AddrSpace) -> TypeRef {
459        self.pointer_types
460            .lookup_or_insert(addr_space, || Type::PointerType { addr_space })
461    }
462
463    /// Get a floating-point type
464    pub fn fp(&mut self, fpt: FPType) -> TypeRef {
465        self.fp_types.lookup_or_insert(fpt, || Type::FPType(fpt))
466    }
467
468    /// Get the single-precision floating-point type
469    pub fn single(&mut self) -> TypeRef {
470        self.fp(FPType::Single)
471    }
472
473    /// Get the double-precision floating-point type
474    pub fn double(&mut self) -> TypeRef {
475        self.fp(FPType::Double)
476    }
477
478    /// Get a function type
479    pub fn func_type(
480        &mut self,
481        result_type: TypeRef,
482        param_types: Vec<TypeRef>,
483        is_var_arg: bool,
484    ) -> TypeRef {
485        self.func_types.lookup_or_insert(
486            (result_type.clone(), param_types.clone(), is_var_arg),
487            || Type::FuncType {
488                result_type,
489                param_types,
490                is_var_arg,
491            },
492        )
493    }
494
495    /// Get a vector type
496    #[cfg(feature = "llvm-11-or-greater")]
497    pub fn vector_of(
498        &mut self,
499        element_type: TypeRef,
500        num_elements: usize,
501        scalable: bool,
502    ) -> TypeRef {
503        self.vec_types
504            .lookup_or_insert((element_type.clone(), num_elements, scalable), || {
505                Type::VectorType {
506                    element_type,
507                    num_elements,
508                    scalable,
509                }
510            })
511    }
512    /// Get a vector type
513    #[cfg(feature = "llvm-10-or-lower")]
514    pub fn vector_of(&mut self, element_type: TypeRef, num_elements: usize) -> TypeRef {
515        self.vec_types
516            .lookup_or_insert((element_type.clone(), num_elements, false), || {
517                Type::VectorType {
518                    element_type,
519                    num_elements,
520                }
521            })
522    }
523
524    /// Get an array type
525    pub fn array_of(&mut self, element_type: TypeRef, num_elements: usize) -> TypeRef {
526        self.arr_types
527            .lookup_or_insert((element_type.clone(), num_elements), || Type::ArrayType {
528                element_type,
529                num_elements,
530            })
531    }
532
533    /// Get a struct type
534    pub fn struct_of(&mut self, element_types: Vec<TypeRef>, is_packed: bool) -> TypeRef {
535        self.struct_types
536            .lookup_or_insert((element_types.clone(), is_packed), || Type::StructType {
537                element_types,
538                is_packed,
539            })
540    }
541
542    /// Get the `TypeRef` for the struct with the given name.
543    ///
544    /// Note that this gives a `NamedStructType`.
545    /// To get the actual _definition_ of a named struct (the `NamedStructDef`),
546    /// use `named_struct_def()`.
547    pub fn named_struct(&mut self, name: String) -> TypeRef {
548        self.named_struct_types
549            .lookup_or_insert(name.clone(), || Type::NamedStructType { name })
550    }
551
552    /// Get the `NamedStructDef` for the struct with the given `name`.
553    ///
554    /// Panics if no definition has been added for that struct name.
555    ///
556    /// Note that this gives a `NamedStructDef`.
557    /// To get the `NamedStructType` for a `name`, use `named_struct()`.
558    pub fn named_struct_def(&self, name: &str) -> &NamedStructDef {
559        self.named_struct_defs
560            .get(name)
561            .expect("Named struct has not been defined")
562    }
563
564    /// Add the given `NamedStructDef` as the definition of the struct with the given `name`.
565    ///
566    /// Panics if that name already had a definition.
567    pub fn add_named_struct_def(&mut self, name: String, def: NamedStructDef) {
568        match self.named_struct_defs.entry(name) {
569            Entry::Occupied(_) => {
570                panic!("Trying to redefine named struct");
571            },
572            Entry::Vacant(ventry) => {
573                ventry.insert(def);
574            },
575        }
576    }
577
578    /// Get the X86_MMX type
579    pub fn x86_mmx(&self) -> TypeRef {
580        self.x86_mmx_type.clone()
581    }
582
583    /// Get the X86_AMX type
584    #[cfg(feature = "llvm-12-or-greater")]
585    pub fn x86_amx(&self) -> TypeRef {
586        self.x86_amx_type.clone()
587    }
588
589    /// Get the metadata type
590    pub fn metadata_type(&self) -> TypeRef {
591        self.metadata_type.clone()
592    }
593
594    /// Get the label type
595    pub fn label_type(&self) -> TypeRef {
596        self.label_type.clone()
597    }
598
599    /// Get the token type
600    pub fn token_type(&self) -> TypeRef {
601        self.token_type.clone()
602    }
603
604    /// Get the target extension type
605    #[cfg(feature = "llvm-16-or-greater")]
606    pub fn target_ext_type(
607        &mut self,
608        // name: String, // TODO not exposed in the LLVM C API; see notes on Type::TargetExtType
609        // contained_types: Vec<TypeRef>, // TODO not exposed in the LLVM C API; see notes on Type::TargetExtType
610        // contained_ints: Vec<u32>, // TODO not exposed in the LLVM C API; see notes on Type::TargetExtType
611    ) -> TypeRef {
612        self.target_ext_type.clone()
613    }
614}
615
616#[derive(Clone, Debug, Hash)]
617pub enum NamedStructDef {
618    /// An opaque struct type; see [LLVM 14 docs on Opaque Structure Types](https://releases.llvm.org/14.0.0/docs/LangRef.html#t-opaque).
619    Opaque,
620    /// A struct type with a definition. The `TypeRef` here is guaranteed to be to a `StructType` variant.
621    Defined(TypeRef),
622}
623
624/// Holds a reference to all of the `Type`s used in the `Module`, and facilitates
625/// lookups so you can get a `TypeRef` to the `Type` you want.
626//
627// Unlike `TypesBuilder`, this is intended to be immutable, and performs type
628// lookups without &mut self.
629// It should be created from `TypesBuilder::build()`, and once it is built,
630// it should contain all types ever used in the `Module`.
631//
632// That said, if you happen to want a type which wasn't encountered when parsing
633// the `Module` (e.g., a pointer to some type in the `Module`, even if the
634// `Module` doesn't itself create pointers to that type), it will still
635// construct that `Type` and give you a `TypeRef`; you'll just be the sole owner
636// of that `Type` object.
637#[derive(Clone)]
638pub struct Types {
639    /// `TypeRef` to `Type::VoidType`
640    void_type: TypeRef,
641    /// Map of integer size to `Type::IntegerType` of that size
642    int_types: TypeCache<u32>,
643    /// Map of (pointee type, address space) to the corresponding `Type::PointerType`
644    #[cfg(feature = "llvm-14-or-lower")]
645    pointer_types: TypeCache<(TypeRef, AddrSpace)>,
646    /// Map of address space to the corresponding `Type::PointerType`
647    #[cfg(feature = "llvm-15-or-greater")]
648    pointer_types: TypeCache<AddrSpace>,
649    /// Map of `FPType` to the corresponding `Type::FPType`
650    fp_types: TypeCache<FPType>,
651    /// Map of `(result_type, param_types, is_var_arg)` to the corresponding `Type::FunctionType`
652    func_types: TypeCache<(TypeRef, Vec<TypeRef>, bool)>,
653    /// Map of (element type, #elements, scalable) to the corresponding `Type::VectorType`.
654    /// For LLVM 10 and lower, `scalable` is always `false`.
655    vec_types: TypeCache<(TypeRef, usize, bool)>,
656    /// Map of (element type, #elements) to the corresponding `Type::ArrayType`
657    arr_types: TypeCache<(TypeRef, usize)>,
658    /// Map of `(element_types, is_packed)` to the corresponding `Type::StructType`
659    struct_types: TypeCache<(Vec<TypeRef>, bool)>,
660    /// Map of struct name to the corresponding `Type::NamedStructType`
661    named_struct_types: TypeCache<String>,
662    /// Map of struct name to the corresponding `NamedStructDef`
663    named_struct_defs: HashMap<String, NamedStructDef>,
664    /// `TypeRef` to `Type::X86_MMXType`
665    x86_mmx_type: TypeRef,
666    /// `TypeRef` to `Type::X86_AMXType`
667    #[cfg(feature = "llvm-12-or-greater")]
668    x86_amx_type: TypeRef,
669    /// `TypeRef` to `Type::MetadataType`
670    metadata_type: TypeRef,
671    /// `TypeRef` to `Type::LabelType`
672    label_type: TypeRef,
673    /// `TypeRef` to `Type::TokenType`
674    token_type: TypeRef,
675    /// `TypeRef` to `Type::TargetExtType`
676    #[cfg(feature = "llvm-16-or-greater")]
677    target_ext_type: TypeRef,
678}
679
680impl Types {
681    /// Get the type of anything that is `Typed`
682    pub fn type_of<T: Typed + ?Sized>(&self, t: &T) -> TypeRef {
683        t.get_type(self)
684    }
685
686    /// Get the void type
687    pub fn void(&self) -> TypeRef {
688        self.void_type.clone()
689    }
690
691    /// Get the integer type of the specified size (in bits)
692    pub fn int(&self, bits: u32) -> TypeRef {
693        self.int_types
694            .lookup(&bits)
695            .unwrap_or_else(|| TypeRef::new(Type::IntegerType { bits }))
696    }
697
698    /// Get the boolean type (`i1`)
699    pub fn bool(&self) -> TypeRef {
700        self.int(1)
701    }
702
703    /// Get the 8-bit integer type
704    pub fn i8(&self) -> TypeRef {
705        self.int(8)
706    }
707
708    /// Get the 16-bit integer type
709    pub fn i16(&self) -> TypeRef {
710        self.int(16)
711    }
712
713    /// Get the 32-bit integer type
714    pub fn i32(&self) -> TypeRef {
715        self.int(32)
716    }
717
718    /// Get the 64-bit integer type
719    pub fn i64(&self) -> TypeRef {
720        self.int(64)
721    }
722
723    /// Get a pointer type in the default address space (`0`)
724    #[cfg(feature = "llvm-14-or-lower")]
725    pub fn pointer_to(&self, pointee_type: TypeRef) -> TypeRef {
726        self.pointer_in_addr_space(pointee_type, 0)
727    }
728    /// Get the pointer type for the default address space (`0`)
729    #[cfg(feature = "llvm-15-or-greater")]
730    pub fn pointer(&self) -> TypeRef {
731        self.pointer_in_addr_space(0)
732    }
733
734    /// Get a pointer type in the specified address space
735    #[cfg(feature = "llvm-14-or-lower")]
736    pub fn pointer_in_addr_space(&self, pointee_type: TypeRef, addr_space: AddrSpace) -> TypeRef {
737        self.pointer_types
738            .lookup(&(pointee_type.clone(), addr_space))
739            .unwrap_or_else(|| {
740                TypeRef::new(Type::PointerType {
741                    pointee_type,
742                    addr_space,
743                })
744            })
745    }
746    /// Get a pointer type in the specified address space
747    #[cfg(feature = "llvm-15-or-greater")]
748    pub fn pointer_in_addr_space(&self, addr_space: AddrSpace) -> TypeRef {
749        self.pointer_types
750            .lookup(&addr_space)
751            .unwrap_or_else(|| TypeRef::new(Type::PointerType { addr_space }))
752    }
753
754    /// Get a floating-point type
755    pub fn fp(&self, fpt: FPType) -> TypeRef {
756        self.fp_types
757            .lookup(&fpt)
758            .unwrap_or_else(|| TypeRef::new(Type::FPType(fpt)))
759    }
760
761    /// Get the single-precision floating-point type
762    pub fn single(&self) -> TypeRef {
763        self.fp(FPType::Single)
764    }
765
766    /// Get the double-precision floating-point type
767    pub fn double(&self) -> TypeRef {
768        self.fp(FPType::Double)
769    }
770
771    /// Get a function type
772    pub fn func_type(
773        &self,
774        result_type: TypeRef,
775        param_types: Vec<TypeRef>,
776        is_var_arg: bool,
777    ) -> TypeRef {
778        self.func_types
779            .lookup(&(result_type.clone(), param_types.clone(), is_var_arg))
780            .unwrap_or_else(|| {
781                TypeRef::new(Type::FuncType {
782                    result_type,
783                    param_types,
784                    is_var_arg,
785                })
786            })
787    }
788
789    /// Get a vector type
790    #[cfg(feature = "llvm-11-or-greater")]
791    pub fn vector_of(&self, element_type: TypeRef, num_elements: usize, scalable: bool) -> TypeRef {
792        self.vec_types
793            .lookup(&(element_type.clone(), num_elements, scalable))
794            .unwrap_or_else(|| {
795                TypeRef::new(Type::VectorType {
796                    element_type,
797                    num_elements,
798                    scalable,
799                })
800            })
801    }
802    #[cfg(feature = "llvm-10-or-lower")]
803    pub fn vector_of(&self, element_type: TypeRef, num_elements: usize) -> TypeRef {
804        self.vec_types
805            .lookup(&(element_type.clone(), num_elements, false))
806            .unwrap_or_else(|| {
807                TypeRef::new(Type::VectorType {
808                    element_type,
809                    num_elements,
810                })
811            })
812    }
813
814    /// Get an array type
815    pub fn array_of(&self, element_type: TypeRef, num_elements: usize) -> TypeRef {
816        self.arr_types
817            .lookup(&(element_type.clone(), num_elements))
818            .unwrap_or_else(|| {
819                TypeRef::new(Type::ArrayType {
820                    element_type,
821                    num_elements,
822                })
823            })
824    }
825
826    /// Get a struct type
827    pub fn struct_of(&self, element_types: Vec<TypeRef>, is_packed: bool) -> TypeRef {
828        self.struct_types
829            .lookup(&(element_types.clone(), is_packed))
830            .unwrap_or_else(|| {
831                TypeRef::new(Type::StructType {
832                    element_types,
833                    is_packed,
834                })
835            })
836    }
837
838    /// Get the `TypeRef` for the struct with the given `name`.
839    ///
840    /// Note that this gives a `NamedStructType`.
841    /// To get the actual _definition_ of a named struct (the `NamedStructDef`),
842    /// use `named_struct_def()`.
843    pub fn named_struct(&self, name: &str) -> TypeRef {
844        self.named_struct_types
845            .lookup(name)
846            .unwrap_or_else(|| TypeRef::new(Type::NamedStructType { name: name.into() }))
847    }
848
849    /// Get the `NamedStructDef` for the struct with the given `name`, or
850    /// `None` if there is no struct by that name.
851    ///
852    /// Note that this gives a `NamedStructDef`.
853    /// To get the `NamedStructType` for a `name`, use `named_struct()`.
854    pub fn named_struct_def(&self, name: &str) -> Option<&NamedStructDef> {
855        self.named_struct_defs.get(name)
856    }
857
858    /// Get the names of all the named structs
859    pub fn all_struct_names(&self) -> impl Iterator<Item = &String> {
860        self.named_struct_defs.keys()
861    }
862
863    /// Add the given `NamedStructDef` as the definition of the struct with the given `name`.
864    ///
865    /// Panics if that name already had a definition.
866    pub fn add_named_struct_def(&mut self, name: String, def: NamedStructDef) {
867        match self.named_struct_defs.entry(name) {
868            Entry::Occupied(_) => {
869                panic!("Trying to redefine named struct");
870            },
871            Entry::Vacant(ventry) => {
872                ventry.insert(def);
873            },
874        }
875    }
876
877    /// Remove the definition of the struct with the given `name`.
878    ///
879    /// Returns `true` if the definition was removed, or `false` if no definition
880    /// existed.
881    pub fn remove_named_struct_def(&mut self, name: &str) -> bool {
882        self.named_struct_defs.remove(name).is_some()
883    }
884
885    /// Get the X86_MMX type
886    pub fn x86_mmx(&self) -> TypeRef {
887        self.x86_mmx_type.clone()
888    }
889
890    /// Get the X86_AMX type
891    #[cfg(feature = "llvm-12-or-greater")]
892    pub fn x86_amx(&self) -> TypeRef {
893        self.x86_amx_type.clone()
894    }
895
896    /// Get the metadata type
897    pub fn metadata_type(&self) -> TypeRef {
898        self.metadata_type.clone()
899    }
900
901    /// Get the label type
902    pub fn label_type(&self) -> TypeRef {
903        self.label_type.clone()
904    }
905
906    /// Get the token type
907    pub fn token_type(&self) -> TypeRef {
908        self.token_type.clone()
909    }
910
911    /// Get the `TypeRef` for target extension type with the given
912    /// name, contained types, and contained ints.
913    #[cfg(feature = "llvm-16-or-greater")]
914    pub fn target_ext_type(
915        &self,
916        // name: String, // TODO not exposed in the LLVM C API; see notes on Type::TargetExtType
917        // contained_types: Vec<TypeRef>, // TODO not exposed in the LLVM C API; see notes on Type::TargetExtType
918        // contained_ints: Vec<u32>, // TODO not exposed in the LLVM C API; see notes on Type::TargetExtType
919    ) -> TypeRef {
920        self.target_ext_type.clone()
921    }
922
923    /// Get a `TypeRef` for the given `Type`
924    #[rustfmt::skip] // so we can keep each of the match arms more consistent with each other
925    pub fn get_for_type(&self, ty: &Type) -> TypeRef {
926        match ty {
927            Type::VoidType => self.void(),
928            Type::IntegerType{ bits } => self.int(*bits),
929            #[cfg(feature = "llvm-14-or-lower")]
930            Type::PointerType { pointee_type, addr_space } => {
931                self.pointer_in_addr_space(pointee_type.clone(), *addr_space)
932            },
933            #[cfg(feature = "llvm-15-or-greater")]
934            Type::PointerType { addr_space } => {
935                self.pointer_in_addr_space(*addr_space)
936            },
937            Type::FPType(fpt) => self.fp(*fpt),
938            Type::FuncType { result_type, param_types, is_var_arg } => {
939                self.func_type(result_type.clone(), param_types.clone(), *is_var_arg)
940            },
941            #[cfg(feature="llvm-11-or-greater")]
942            Type::VectorType { element_type, num_elements, scalable } => {
943                self.vector_of(element_type.clone(), *num_elements, *scalable)
944            },
945            #[cfg(feature="llvm-10-or-lower")]
946            Type::VectorType { element_type, num_elements } => {
947                self.vector_of(element_type.clone(), *num_elements)
948            },
949            Type::ArrayType { element_type, num_elements } => {
950                self.array_of(element_type.clone(), *num_elements)
951            },
952            Type::StructType { element_types, is_packed } => {
953                self.struct_of(element_types.clone(), *is_packed)
954            },
955            Type::NamedStructType { name  } => self.named_struct(name),
956            Type::X86_MMXType => self.x86_mmx(),
957            #[cfg(feature="llvm-12-or-greater")]
958            Type::X86_AMXType => self.x86_amx(),
959            Type::MetadataType => self.metadata_type(),
960            Type::LabelType => self.label_type(),
961            Type::TokenType => self.token_type(),
962            #[cfg(feature="llvm-16-or-greater")]
963            Type::TargetExtType => self.target_ext_type(),
964        }
965    }
966}
967
968impl Types {
969    /// Get a blank `Types` containing essentially no types.
970    /// This function is intended only for use in testing;
971    /// it's probably not useful otherwise.
972    pub fn blank_for_testing() -> Self {
973        TypesBuilder::new().build()
974    }
975}
976
977#[derive(Clone, Debug)]
978struct TypeCache<K: Eq + Hash + Clone> {
979    map: HashMap<K, TypeRef>,
980}
981
982#[allow(dead_code)]
983impl<K: Eq + Hash + Clone> TypeCache<K> {
984    fn new() -> Self {
985        Self {
986            map: HashMap::new(),
987        }
988    }
989
990    /// Get a `TypeRef` to the `Type` with the given key,
991    /// or `None` if the `Type` is not present.
992    fn lookup<Q: ?Sized>(&self, key: &Q) -> Option<TypeRef>
993    where
994        K: Borrow<Q>,
995        Q: Hash + Eq,
996    {
997        self.map.get(key).cloned()
998    }
999
1000    /// Get a `TypeRef` to the `Type` with the given key.
1001    /// The `if_missing` function or closure will be called to create that `Type`
1002    /// if it hasn't been created yet.
1003    fn lookup_or_insert(&mut self, key: K, if_missing: impl FnOnce() -> Type) -> TypeRef {
1004        self.map
1005            .entry(key)
1006            .or_insert_with(|| TypeRef::new(if_missing()))
1007            .clone()
1008    }
1009
1010    /// Is a `Type` for the given key currently in the cache?
1011    fn contains_key(&self, key: &K) -> bool {
1012        self.map.contains_key(key)
1013    }
1014}
1015
1016// ********* //
1017// from_llvm //
1018// ********* //
1019
1020use crate::from_llvm::*;
1021use crate::llvm_sys::*;
1022use llvm_sys::LLVMTypeKind;
1023use std::collections::hash_map::Entry;
1024
1025impl TypesBuilder {
1026    pub(crate) fn type_from_llvm_ref(&mut self, ty: LLVMTypeRef) -> TypeRef {
1027        if let Some(typeref) = self.llvm_type_map.get(&ty) {
1028            return typeref.clone();
1029        }
1030        let typeref = self.parse_type_from_llvm_ref(ty);
1031        self.llvm_type_map.insert(ty, typeref.clone());
1032        typeref
1033    }
1034
1035    fn parse_type_from_llvm_ref(&mut self, ty: LLVMTypeRef) -> TypeRef {
1036        let kind = unsafe { LLVMGetTypeKind(ty) };
1037        match kind {
1038            LLVMTypeKind::LLVMVoidTypeKind => self.void(),
1039            LLVMTypeKind::LLVMIntegerTypeKind => self.int(unsafe { LLVMGetIntTypeWidth(ty) }),
1040            #[cfg(feature = "llvm-14-or-lower")]
1041            LLVMTypeKind::LLVMPointerTypeKind => {
1042                let pointee_type = self.type_from_llvm_ref(unsafe { LLVMGetElementType(ty) });
1043                self.pointer_in_addr_space(pointee_type, unsafe { LLVMGetPointerAddressSpace(ty) })
1044            },
1045            #[cfg(feature = "llvm-15-or-greater")]
1046            LLVMTypeKind::LLVMPointerTypeKind => {
1047                self.pointer_in_addr_space(unsafe { LLVMGetPointerAddressSpace(ty) })
1048            },
1049            LLVMTypeKind::LLVMArrayTypeKind => {
1050                let element_type = self.type_from_llvm_ref(unsafe { LLVMGetElementType(ty) });
1051                
1052                // LLVMGetArrayLength2 was added in LLVM-17: the old function still exists there,
1053                // but is deprecated. The parameters are the same, but the return type is changed
1054                // from c_uint to u64
1055                #[cfg(feature = "llvm-16-or-lower")]
1056                let array_len = unsafe { LLVMGetArrayLength(ty) as usize };
1057                #[cfg(feature = "llvm-17-or-greater")]
1058                let array_len = unsafe { LLVMGetArrayLength2(ty) as usize };
1059                
1060                self.array_of(element_type, array_len)
1061            },
1062            LLVMTypeKind::LLVMVectorTypeKind => {
1063                let element_type = self.type_from_llvm_ref(unsafe { LLVMGetElementType(ty) });
1064                #[cfg(feature = "llvm-11-or-greater")]
1065                let ret = self.vector_of(
1066                    element_type,
1067                    unsafe { LLVMGetVectorSize(ty) as usize },
1068                    false,
1069                );
1070                #[cfg(feature = "llvm-10-or-lower")]
1071                let ret = self.vector_of(element_type, unsafe { LLVMGetVectorSize(ty) as usize });
1072                ret
1073            },
1074            #[cfg(feature = "llvm-11-or-greater")]
1075            LLVMTypeKind::LLVMScalableVectorTypeKind => {
1076                let element_type = self.type_from_llvm_ref(unsafe { LLVMGetElementType(ty) });
1077                self.vector_of(
1078                    element_type,
1079                    unsafe { LLVMGetVectorSize(ty) as usize },
1080                    true,
1081                )
1082            },
1083            LLVMTypeKind::LLVMStructTypeKind => {
1084                let name = if unsafe { LLVMIsLiteralStruct(ty) } != 0 {
1085                    None
1086                } else {
1087                    unsafe { get_struct_name(ty) }
1088                };
1089
1090                match name {
1091                    Some(s) if !s.is_empty() => {
1092                        if self.named_struct_types.contains_key(&s) {
1093                            // already defined: return the NamedStructType and don't change the definition
1094                            self.named_struct(s)
1095                        } else if unsafe { LLVMIsOpaqueStruct(ty) } != 0 {
1096                            // add the definition as opaque
1097                            self.add_named_struct_def(s.clone(), NamedStructDef::Opaque);
1098                            // return the NamedStructType
1099                            self.named_struct(s)
1100                        } else {
1101                            // add the NamedStructType first, so that the call to struct_type_from_llvm_ref will terminate
1102                            let named_struct_typeref = self.named_struct(s.clone());
1103                            // now compute the actual struct type. Any self-references will point to the NamedStructType we just created
1104                            let actual_struct_type = self.struct_type_from_llvm_ref(ty);
1105                            // add this definition for the named struct
1106                            self.add_named_struct_def(
1107                                s,
1108                                NamedStructDef::Defined(actual_struct_type),
1109                            );
1110                            // And now we return the NamedStructType
1111                            named_struct_typeref
1112                        }
1113                    },
1114                    _ => self.struct_type_from_llvm_ref(ty),
1115                }
1116            },
1117            LLVMTypeKind::LLVMFunctionTypeKind => {
1118                let result_type = self.type_from_llvm_ref(unsafe { LLVMGetReturnType(ty) });
1119                let param_types = {
1120                    let num_types = unsafe { LLVMCountParamTypes(ty) };
1121                    let mut types: Vec<LLVMTypeRef> = Vec::with_capacity(num_types as usize);
1122                    unsafe {
1123                        LLVMGetParamTypes(ty, types.as_mut_ptr());
1124                        types.set_len(num_types as usize);
1125                    };
1126                    types
1127                        .into_iter()
1128                        .map(|t| self.type_from_llvm_ref(t))
1129                        .collect()
1130                };
1131                self.func_type(
1132                    result_type,
1133                    param_types,
1134                    unsafe { LLVMIsFunctionVarArg(ty) } != 0,
1135                )
1136            },
1137            LLVMTypeKind::LLVMHalfTypeKind => self.fp(FPType::Half),
1138            #[cfg(feature = "llvm-11-or-greater")]
1139            LLVMTypeKind::LLVMBFloatTypeKind => self.fp(FPType::BFloat),
1140            LLVMTypeKind::LLVMFloatTypeKind => self.fp(FPType::Single),
1141            LLVMTypeKind::LLVMDoubleTypeKind => self.fp(FPType::Double),
1142            LLVMTypeKind::LLVMFP128TypeKind => self.fp(FPType::FP128),
1143            LLVMTypeKind::LLVMX86_FP80TypeKind => self.fp(FPType::X86_FP80),
1144            LLVMTypeKind::LLVMPPC_FP128TypeKind => self.fp(FPType::PPC_FP128),
1145            LLVMTypeKind::LLVMX86_MMXTypeKind => self.x86_mmx(),
1146            #[cfg(feature = "llvm-12-or-greater")]
1147            LLVMTypeKind::LLVMX86_AMXTypeKind => self.x86_amx(),
1148            LLVMTypeKind::LLVMMetadataTypeKind => self.metadata_type(),
1149            LLVMTypeKind::LLVMLabelTypeKind => self.label_type(),
1150            LLVMTypeKind::LLVMTokenTypeKind => self.token_type(),
1151            #[cfg(feature = "llvm-16-or-greater")]
1152            LLVMTypeKind::LLVMTargetExtTypeKind => self.target_ext_type(),
1153        }
1154    }
1155
1156    /// creates an actual `StructType`, regardless of whether the struct is named or not
1157    ///
1158    /// Caller is responsible for ensuring that `ty` is not an opaque struct type
1159    fn struct_type_from_llvm_ref(&mut self, ty: LLVMTypeRef) -> TypeRef {
1160        if unsafe { LLVMIsOpaqueStruct(ty) } != 0 {
1161            panic!(
1162                "struct_type_from_llvm_ref: shouldn't pass an opaque struct type to this function"
1163            );
1164        }
1165        let element_types = {
1166            let num_types = unsafe { LLVMCountStructElementTypes(ty) };
1167            let mut types: Vec<LLVMTypeRef> = Vec::with_capacity(num_types as usize);
1168            unsafe {
1169                LLVMGetStructElementTypes(ty, types.as_mut_ptr());
1170                types.set_len(num_types as usize);
1171            };
1172            types
1173                .into_iter()
1174                .map(|t| self.type_from_llvm_ref(t))
1175                .collect()
1176        };
1177        self.struct_of(element_types, unsafe { LLVMIsPackedStruct(ty) } != 0)
1178    }
1179}