llvm_ir/
constant.rs

1use crate::name::Name;
2#[cfg(feature = "llvm-18-or-lower")]
3use crate::predicates::*;
4use crate::types::{FPType, NamedStructDef, Type, TypeRef, Typed, Types};
5use std::convert::TryFrom;
6use std::fmt::{self, Display};
7use std::ops::Deref;
8use std::sync::Arc;
9
10/// See [LLVM 14 docs on Constants](https://releases.llvm.org/14.0.0/docs/LangRef.html#constants).
11/// Constants can be either values, or expressions involving other constants (see [LLVM 14 docs on Constant Expressions](https://releases.llvm.org/14.0.0/docs/LangRef.html#constant-expressions)).
12#[derive(PartialEq, Clone, Debug, Hash)]
13pub enum Constant {
14    Int {
15        /// Number of bits in the constant integer
16        bits: u32,
17        /// The constant value itself.
18        ///
19        /// If `bits == 64`, this is the value.
20        ///
21        /// If `bits < 64`, the constant value is zero-extended to fit in this
22        /// field.
23        ///
24        /// If `bits > 64`, the constant value is truncated to fit in this field;
25        /// but if this truncation would change the value (i.e., if the value is
26        /// >= 2^64 when interpreted as unsigned) then `Module::from_bc_path()`
27        /// will fail. See [#5](https://github.com/cdisselkoen/llvm-ir/issues/5).
28        //
29        // Note that LLVM integers aren't signed or unsigned; each individual
30        // instruction indicates whether it's treating the integer as signed or
31        // unsigned if necessary (e.g., UDiv vs SDiv).
32        value: u64,
33    },
34    Float(Float),
35    /// The `TypeRef` here must be to a `PointerType`. See [LLVM 14 docs on Simple Constants](https://releases.llvm.org/14.0.0/docs/LangRef.html#simple-constants)
36    Null(TypeRef),
37    /// A zero-initialized array or struct (or scalar).
38    AggregateZero(TypeRef),
39    Struct {
40        name: Option<String>, // llvm-hs-pure has Option<Name> here, but I don't think struct types can be numbered
41        values: Vec<ConstantRef>,
42        is_packed: bool,
43    },
44    Array {
45        element_type: TypeRef,
46        elements: Vec<ConstantRef>,
47    },
48    Vector(Vec<ConstantRef>),
49    /// `Undef` can be used anywhere a constant is expected. See [LLVM 14 docs on Undefined Values](https://releases.llvm.org/14.0.0/docs/LangRef.html#undefined-values)
50    Undef(TypeRef),
51    /// See [LLVM 14 docs on Poison Values](https://releases.llvm.org/14.0.0/docs/LangRef.html#undefined-values)
52    #[cfg(feature = "llvm-12-or-greater")]
53    Poison(TypeRef),
54    /// The address of the given (non-entry) [`BasicBlock`](../struct.BasicBlock.html). See [LLVM 14 docs on Addresses of Basic Blocks](https://releases.llvm.org/14.0.0/docs/LangRef.html#addresses-of-basic-blocks).
55    /// `BlockAddress` needs more fields, but the necessary getter functions are apparently not exposed in the LLVM C API (only the C++ API)
56    BlockAddress, // --TODO ideally we want BlockAddress { function: Name, block: Name },
57    /// Global variable or function
58    GlobalReference {
59        name: Name,
60        ty: TypeRef,
61    },
62    TokenNone,
63    /// See [LLVM 19 docs on ptrauth constants](https://releases.llvm.org/19.1.0/docs/LangRef.html#pointer-authentication-constants)
64    #[cfg(feature = "llvm-19-or-greater")]
65    PtrAuth {
66        ptr : ConstantRef,
67        key : ConstantRef,
68        disc : ConstantRef,
69        addr_disc : ConstantRef
70    },
71
72    // Constants can also be expressed as operations applied to other constants:
73
74    // Integer binary ops
75    Add(Add),
76    Sub(Sub),
77    Mul(Mul),
78    #[cfg(feature = "llvm-14-or-lower")]
79    UDiv(UDiv),
80    #[cfg(feature = "llvm-14-or-lower")]
81    SDiv(SDiv),
82    #[cfg(feature = "llvm-14-or-lower")]
83    URem(URem),
84    #[cfg(feature = "llvm-14-or-lower")]
85    SRem(SRem),
86
87    // Bitwise binary ops
88    #[cfg(feature = "llvm-17-or-lower")]
89    And(And),
90    #[cfg(feature = "llvm-17-or-lower")]
91    Or(Or),
92    Xor(Xor),
93    #[cfg(feature = "llvm-18-or-lower")]
94    Shl(Shl),
95    #[cfg(feature = "llvm-17-or-lower")]
96    LShr(LShr),
97    #[cfg(feature = "llvm-17-or-lower")]
98    AShr(AShr),
99
100    // Floating-point ops
101    #[cfg(feature = "llvm-14-or-lower")]
102    FAdd(FAdd),
103    #[cfg(feature = "llvm-14-or-lower")]
104    FSub(FSub),
105    #[cfg(feature = "llvm-14-or-lower")]
106    FMul(FMul),
107    #[cfg(feature = "llvm-14-or-lower")]
108    FDiv(FDiv),
109    #[cfg(feature = "llvm-14-or-lower")]
110    FRem(FRem),
111
112    // Vector ops
113    ExtractElement(ExtractElement),
114    InsertElement(InsertElement),
115    ShuffleVector(ShuffleVector),
116
117    // Aggregate ops
118    #[cfg(feature = "llvm-14-or-lower")]
119    ExtractValue(ExtractValue),
120    #[cfg(feature = "llvm-14-or-lower")]
121    InsertValue(InsertValue),
122
123    // Memory-related ops
124    GetElementPtr(GetElementPtr),
125
126    // Conversion ops
127    Trunc(Trunc),
128    #[cfg(feature = "llvm-17-or-lower")]
129    ZExt(ZExt),
130    #[cfg(feature = "llvm-17-or-lower")]
131    SExt(SExt),
132    #[cfg(feature = "llvm-17-or-lower")]
133    FPTrunc(FPTrunc),
134    #[cfg(feature = "llvm-17-or-lower")]
135    FPExt(FPExt),
136    #[cfg(feature = "llvm-17-or-lower")]
137    FPToUI(FPToUI),
138    #[cfg(feature = "llvm-17-or-lower")]
139    FPToSI(FPToSI),
140    #[cfg(feature = "llvm-17-or-lower")]
141    UIToFP(UIToFP),
142    #[cfg(feature = "llvm-17-or-lower")]
143    SIToFP(SIToFP),
144    PtrToInt(PtrToInt),
145    IntToPtr(IntToPtr),
146    BitCast(BitCast),
147    AddrSpaceCast(AddrSpaceCast),
148
149    // Other ops
150    #[cfg(feature = "llvm-18-or-lower")]
151    ICmp(ICmp),
152    #[cfg(feature = "llvm-18-or-lower")]
153    FCmp(FCmp),
154    #[cfg(feature = "llvm-16-or-lower")]
155    Select(Select),
156}
157
158/// All of these `Float` variants should have data associated with them, but
159/// Rust only has `f32` and `f64` floating-point types, and furthermore,
160/// it's not clear how to get 16-, 80-, or 128-bit FP constant values through
161/// the LLVM C API (the getters seem to only be exposed in the C++ API?)
162#[derive(PartialEq, Clone, Debug)]
163#[allow(non_camel_case_types)]
164pub enum Float {
165    Half, // TODO perhaps Half(u16)
166    #[cfg(feature = "llvm-11-or-greater")]
167    BFloat, // TODO perhaps BFloat(u16)
168    Single(f32),
169    Double(f64),
170    Quadruple, // TODO perhaps Quadruple(u128)
171    X86_FP80,  // TODO perhaps X86_FP80((u16, u64)) with the most-significant bits on the left
172    PPC_FP128, // TODO perhaps PPC_FP128((u64, u64)) with the most-significant bits on the left
173}
174
175impl std::hash::Hash for Float {
176    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
177        core::mem::discriminant(self).hash(state);
178        match self {
179            Float::Single(f) => ordered_float::OrderedFloat(*f).hash(state),
180            Float::Double(f) => ordered_float::OrderedFloat(*f).hash(state),
181            _ => {},
182        }
183    }
184}
185
186impl Typed for Float {
187    fn get_type(&self, types: &Types) -> TypeRef {
188        types.fp(match self {
189            Float::Half => FPType::Half,
190            #[cfg(feature = "llvm-11-or-greater")]
191            Float::BFloat => FPType::BFloat,
192            Float::Single(_) => FPType::Single,
193            Float::Double(_) => FPType::Double,
194            Float::Quadruple => FPType::FP128,
195            Float::X86_FP80 => FPType::X86_FP80,
196            Float::PPC_FP128 => FPType::PPC_FP128,
197        })
198    }
199}
200
201impl Display for Float {
202    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
203        match self {
204            Float::Half => write!(f, "half"),
205            #[cfg(feature = "llvm-11-or-greater")]
206            Float::BFloat => write!(f, "bfloat"),
207            Float::Single(s) => write!(f, "float {}", s),
208            Float::Double(d) => write!(f, "double {}", d),
209            Float::Quadruple => write!(f, "quadruple"),
210            Float::X86_FP80 => write!(f, "x86_fp80"),
211            Float::PPC_FP128 => write!(f, "ppc_fp128"),
212        }
213    }
214}
215
216impl Typed for Constant {
217    #[rustfmt::skip] // to keep all the branches more consistent with each other
218    fn get_type(&self, types: &Types) -> TypeRef {
219        match self {
220            Constant::Int { bits, .. } => types.int(*bits),
221            Constant::Float(f) => types.type_of(f),
222            Constant::Null(t) => t.clone(),
223            Constant::AggregateZero(t) => t.clone(),
224            Constant::Struct { values, is_packed, .. } => types.struct_of(
225                values.iter().map(|v| types.type_of(v)).collect(),
226                *is_packed,
227            ),
228            Constant::Array { element_type, elements } => types.array_of(
229                element_type.clone(),
230                elements.len(),
231            ),
232            #[cfg(feature="llvm-11-or-greater")]
233            Constant::Vector(v) => types.vector_of(
234                types.type_of(&v[0]),
235                v.len(),
236                false, // I don't think it's possible (at least as of LLVM 11) to have a constant of scalable vector type?
237            ),
238            #[cfg(feature="llvm-10-or-lower")]
239            Constant::Vector(v) => types.vector_of(
240                types.type_of(&v[0]),
241                v.len(),
242            ),
243            Constant::Undef(t) => t.clone(),
244            #[cfg(feature="llvm-12-or-greater")]
245            Constant::Poison(t) => t.clone(),
246            Constant::BlockAddress { .. } => types.label_type(),
247            #[cfg(feature="llvm-14-or-lower")]
248            Constant::GlobalReference { ty, .. } => types.pointer_to(ty.clone()),
249            #[cfg(feature="llvm-15-or-greater")]
250            Constant::GlobalReference { .. } => types.pointer(),
251            Constant::TokenNone => types.token_type(),
252            Constant::Add(a) => types.type_of(a),
253            Constant::Sub(s) => types.type_of(s),
254            Constant::Mul(m) => types.type_of(m),
255            #[cfg(feature = "llvm-14-or-lower")]
256            Constant::UDiv(d) => types.type_of(d),
257            #[cfg(feature = "llvm-14-or-lower")]
258            Constant::SDiv(d) => types.type_of(d),
259            #[cfg(feature = "llvm-14-or-lower")]
260            Constant::URem(r) => types.type_of(r),
261            #[cfg(feature = "llvm-14-or-lower")]
262            Constant::SRem(r) => types.type_of(r),
263            #[cfg(feature = "llvm-17-or-lower")]
264            Constant::And(a) => types.type_of(a),
265            #[cfg(feature = "llvm-17-or-lower")]
266            Constant::Or(o) => types.type_of(o),
267            Constant::Xor(x) => types.type_of(x),
268            #[cfg(feature = "llvm-18-or-lower")]
269            Constant::Shl(s) => types.type_of(s),
270            #[cfg(feature = "llvm-17-or-lower")]
271            Constant::LShr(l) => types.type_of(l),
272            #[cfg(feature = "llvm-17-or-lower")]
273            Constant::AShr(a) => types.type_of(a),
274            #[cfg(feature = "llvm-14-or-lower")]
275            Constant::FAdd(f) => types.type_of(f),
276            #[cfg(feature = "llvm-14-or-lower")]
277            Constant::FSub(f) => types.type_of(f),
278            #[cfg(feature = "llvm-14-or-lower")]
279            Constant::FMul(f) => types.type_of(f),
280            #[cfg(feature = "llvm-14-or-lower")]
281            Constant::FDiv(f) => types.type_of(f),
282            #[cfg(feature = "llvm-14-or-lower")]
283            Constant::FRem(f) => types.type_of(f),
284            Constant::ExtractElement(e) => types.type_of(e),
285            Constant::InsertElement(i) => types.type_of(i),
286            Constant::ShuffleVector(s) => types.type_of(s),
287            #[cfg(feature = "llvm-14-or-lower")]
288            Constant::ExtractValue(e) => types.type_of(e),
289            #[cfg(feature = "llvm-14-or-lower")]
290            Constant::InsertValue(i) => types.type_of(i),
291            Constant::GetElementPtr(g) => types.type_of(g),
292            Constant::Trunc(t) => types.type_of(t),
293            #[cfg(feature = "llvm-17-or-lower")]
294            Constant::ZExt(z) => types.type_of(z),
295            #[cfg(feature = "llvm-17-or-lower")]
296            Constant::SExt(s) => types.type_of(s),
297            #[cfg(feature = "llvm-17-or-lower")]
298            Constant::FPTrunc(f) => types.type_of(f),
299            #[cfg(feature = "llvm-17-or-lower")]
300            Constant::FPExt(f) => types.type_of(f),
301            #[cfg(feature = "llvm-17-or-lower")]
302            Constant::FPToUI(f) => types.type_of(f),
303            #[cfg(feature = "llvm-17-or-lower")]
304            Constant::FPToSI(f) => types.type_of(f),
305            #[cfg(feature = "llvm-17-or-lower")]
306            Constant::UIToFP(u) => types.type_of(u),
307            #[cfg(feature = "llvm-17-or-lower")]
308            Constant::SIToFP(s) => types.type_of(s),
309            Constant::PtrToInt(p) => types.type_of(p),
310            Constant::IntToPtr(i) => types.type_of(i),
311            Constant::BitCast(b) => types.type_of(b),
312            Constant::AddrSpaceCast(a) => types.type_of(a),
313            #[cfg(feature = "llvm-18-or-lower")]
314            Constant::ICmp(i) => types.type_of(i),
315            #[cfg(feature = "llvm-18-or-lower")]
316            Constant::FCmp(f) => types.type_of(f),
317            #[cfg(feature="llvm-16-or-lower")]
318            Constant::Select(s) => types.type_of(s),
319            #[cfg(feature="llvm-19-or-greater")]
320            Constant::PtrAuth { .. } => types.pointer(),
321        }
322    }
323}
324
325impl Display for Constant {
326    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
327        match self {
328            Constant::Int { bits, value } => {
329                if *bits == 1 {
330                    if *value == 0 {
331                        write!(f, "i1 false")
332                    } else {
333                        write!(f, "i1 true")
334                    }
335                } else {
336                    // for readability, use heuristic to decide whether to show as negative number or not
337                    match *bits {
338                        16 => {
339                            let signed_val = (*value & 0xFFFF) as i16;
340                            if signed_val > -1000 {
341                                write!(f, "i{} {}", bits, signed_val)
342                            } else {
343                                write!(f, "i{} {}", bits, *value)
344                            }
345                        },
346                        32 => {
347                            let signed_val = (*value & 0xFFFF_FFFF) as i32;
348                            if signed_val > -1000 {
349                                write!(f, "i{} {}", bits, signed_val)
350                            } else {
351                                write!(f, "i{} {}", bits, *value)
352                            }
353                        },
354                        64 => {
355                            let signed_val = *value as i64;
356                            if signed_val > -1000 {
357                                write!(f, "i{} {}", bits, signed_val)
358                            } else {
359                                write!(f, "i{} {}", bits, *value)
360                            }
361                        },
362                        _ => write!(f, "i{} {}", bits, value),
363                    }
364                }
365            },
366            Constant::Float(float) => write!(f, "{}", float),
367            Constant::Null(ty) => write!(f, "{} null", ty),
368            Constant::AggregateZero(ty) => write!(f, "{} zeroinitializer", ty),
369            Constant::Struct {
370                values, is_packed, ..
371            } => {
372                if *is_packed {
373                    write!(f, "<")?;
374                }
375                write!(f, "{{ ")?;
376                for (i, val) in values.iter().enumerate() {
377                    if i == values.len() - 1 {
378                        write!(f, "{}", val)?;
379                    } else {
380                        write!(f, "{}, ", val)?;
381                    }
382                }
383                write!(f, " }}")?;
384                if *is_packed {
385                    write!(f, ">")?;
386                }
387                Ok(())
388            },
389            Constant::Array { elements, .. } => {
390                write!(f, "[ ")?;
391                for (i, elt) in elements.iter().enumerate() {
392                    if i == elements.len() - 1 {
393                        write!(f, "{}", elt)?;
394                    } else {
395                        write!(f, "{}, ", elt)?;
396                    }
397                }
398                write!(f, " ]")?;
399                Ok(())
400            },
401            Constant::Vector(v) => {
402                write!(f, "< ")?;
403                for (i, elt) in v.iter().enumerate() {
404                    if i == v.len() - 1 {
405                        write!(f, "{}", elt)?;
406                    } else {
407                        write!(f, "{}, ", elt)?;
408                    }
409                }
410                write!(f, " >")?;
411                Ok(())
412            },
413            Constant::Undef(ty) => write!(f, "{} undef", ty),
414            #[cfg(feature = "llvm-12-or-greater")]
415            Constant::Poison(ty) => write!(f, "{} poison", ty),
416            Constant::BlockAddress => write!(f, "blockaddr"),
417            Constant::GlobalReference { name, ty } => {
418                let name = match name {
419                    Name::Name(n) => String::clone(n),
420                    Name::Number(n) => n.to_string(),
421                };
422                match ty.as_ref() {
423                    Type::FuncType { .. } => {
424                        // function types: just write the name, not the type
425                        write!(f, "@{}", name)
426                    },
427                    _ if cfg!(feature = "llvm-14-or-lower") => {
428                        // non-function types: typical style with the type and name
429                        write!(f, "{}* @{}", ty, name)
430                    },
431                    _ => {
432                        // in LLVM 15+ the (opaque) pointer type is always "ptr"
433                        write!(f, "ptr @{}", name)
434                    },
435                }
436            },
437            Constant::TokenNone => write!(f, "none"),
438            Constant::Add(a) => write!(f, "{}", a),
439            Constant::Sub(s) => write!(f, "{}", s),
440            Constant::Mul(m) => write!(f, "{}", m),
441            #[cfg(feature = "llvm-14-or-lower")]
442            Constant::UDiv(d) => write!(f, "{}", d),
443            #[cfg(feature = "llvm-14-or-lower")]
444            Constant::SDiv(d) => write!(f, "{}", d),
445            #[cfg(feature = "llvm-14-or-lower")]
446            Constant::URem(r) => write!(f, "{}", r),
447            #[cfg(feature = "llvm-14-or-lower")]
448            Constant::SRem(r) => write!(f, "{}", r),
449            #[cfg(feature = "llvm-17-or-lower")]
450            Constant::And(a) => write!(f, "{}", a),
451            #[cfg(feature = "llvm-17-or-lower")]
452            Constant::Or(o) => write!(f, "{}", o),
453            Constant::Xor(x) => write!(f, "{}", x),
454            #[cfg(feature = "llvm-18-or-lower")]
455            Constant::Shl(s) => write!(f, "{}", s),
456            #[cfg(feature = "llvm-17-or-lower")]
457            Constant::LShr(l) => write!(f, "{}", l),
458            #[cfg(feature = "llvm-17-or-lower")]
459            Constant::AShr(a) => write!(f, "{}", a),
460            #[cfg(feature = "llvm-14-or-lower")]
461            Constant::FAdd(a) => write!(f, "{}", a),
462            #[cfg(feature = "llvm-14-or-lower")]
463            Constant::FSub(s) => write!(f, "{}", s),
464            #[cfg(feature = "llvm-14-or-lower")]
465            Constant::FMul(m) => write!(f, "{}", m),
466            #[cfg(feature = "llvm-14-or-lower")]
467            Constant::FDiv(d) => write!(f, "{}", d),
468            #[cfg(feature = "llvm-14-or-lower")]
469            Constant::FRem(r) => write!(f, "{}", r),
470            Constant::ExtractElement(e) => write!(f, "{}", e),
471            Constant::InsertElement(i) => write!(f, "{}", i),
472            Constant::ShuffleVector(s) => write!(f, "{}", s),
473            #[cfg(feature = "llvm-14-or-lower")]
474            Constant::ExtractValue(e) => write!(f, "{}", e),
475            #[cfg(feature = "llvm-14-or-lower")]
476            Constant::InsertValue(i) => write!(f, "{}", i),
477            Constant::GetElementPtr(g) => write!(f, "{}", g),
478            Constant::Trunc(t) => write!(f, "{}", t),
479            #[cfg(feature = "llvm-17-or-lower")]
480            Constant::ZExt(z) => write!(f, "{}", z),
481            #[cfg(feature = "llvm-17-or-lower")]
482            Constant::SExt(s) => write!(f, "{}", s),
483            #[cfg(feature = "llvm-17-or-lower")]
484            Constant::FPTrunc(t) => write!(f, "{}", t),
485            #[cfg(feature = "llvm-17-or-lower")]
486            Constant::FPExt(e) => write!(f, "{}", e),
487            #[cfg(feature = "llvm-17-or-lower")]
488            Constant::FPToUI(t) => write!(f, "{}", t),
489            #[cfg(feature = "llvm-17-or-lower")]
490            Constant::FPToSI(t) => write!(f, "{}", t),
491            #[cfg(feature = "llvm-17-or-lower")]
492            Constant::UIToFP(t) => write!(f, "{}", t),
493            #[cfg(feature = "llvm-17-or-lower")]
494            Constant::SIToFP(t) => write!(f, "{}", t),
495            Constant::PtrToInt(p) => write!(f, "{}", p),
496            Constant::IntToPtr(i) => write!(f, "{}", i),
497            Constant::BitCast(b) => write!(f, "{}", b),
498            Constant::AddrSpaceCast(a) => write!(f, "{}", a),
499            #[cfg(feature = "llvm-18-or-lower")]
500            Constant::ICmp(i) => write!(f, "{}", i),
501            #[cfg(feature = "llvm-18-or-lower")]
502            Constant::FCmp(c) => write!(f, "{}", c),
503            #[cfg(feature="llvm-16-or-lower")]
504            Constant::Select(s) => write!(f, "{}", s),
505            #[cfg(feature="llvm-19-or-greater")]
506            Constant::PtrAuth { ptr, key, disc, addr_disc } => {
507                write!(f, "ptrauth({}, {}, {}, {})", ptr, key, disc, addr_disc)
508            }
509        }
510    }
511}
512
513/// A `ConstantRef` is a reference to a [`Constant`](enum.Constant.html).
514/// Most importantly, it implements `AsRef<Constant>` and `Deref<Target = Constant>`.
515/// It also has a cheap `Clone` -- only the reference is cloned, not the
516/// underlying `Constant`.
517//
518// `Arc` is used rather than `Rc` so that `Module` can remain `Sync`.
519// This is important because it allows multiple threads to simultaneously access
520// a single (immutable) `Module`.
521#[derive(PartialEq, Clone, Debug, Hash)]
522pub struct ConstantRef(Arc<Constant>);
523
524impl AsRef<Constant> for ConstantRef {
525    fn as_ref(&self) -> &Constant {
526        self.0.as_ref()
527    }
528}
529
530impl Deref for ConstantRef {
531    type Target = Constant;
532
533    fn deref(&self) -> &Constant {
534        self.0.deref()
535    }
536}
537
538impl Typed for ConstantRef {
539    fn get_type(&self, types: &Types) -> TypeRef {
540        self.as_ref().get_type(types)
541    }
542}
543
544impl Display for ConstantRef {
545    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
546        write!(f, "{}", &self.0)
547    }
548}
549
550impl ConstantRef {
551    /// Construct a new `ConstantRef` by consuming the given owned `Constant`.
552    //
553    // Internal users should get `ConstantRef`s from the `ModuleContext` cache
554    // instead if possible, so that if we already have that `Constant`
555    // somewhere, we can just give you a new `ConstantRef` to that `Constant`.
556    pub fn new(c: Constant) -> Self {
557        Self(Arc::new(c))
558    }
559}
560
561pub trait ConstUnaryOp {
562    fn get_operand(&self) -> ConstantRef;
563}
564
565pub trait ConstBinaryOp {
566    fn get_operand0(&self) -> ConstantRef;
567    fn get_operand1(&self) -> ConstantRef;
568}
569
570macro_rules! impl_constexpr {
571    ($expr:ty, $id:ident) => {
572        impl From<$expr> for Constant {
573            fn from(expr: $expr) -> Constant {
574                Constant::$id(expr)
575            }
576        }
577
578        impl TryFrom<Constant> for $expr {
579            type Error = &'static str;
580            fn try_from(constant: Constant) -> Result<Self, Self::Error> {
581                match constant {
582                    Constant::$id(expr) => Ok(expr),
583                    _ => Err("Constant is not of requested kind"),
584                }
585            }
586        }
587    };
588}
589
590// impls which are shared by all UnaryOps.
591// If possible, prefer `unop_explicitly_typed!`, which provides additional impls
592macro_rules! impl_unop {
593    ($expr:ty) => {
594        impl ConstUnaryOp for $expr {
595            fn get_operand(&self) -> ConstantRef {
596                self.operand.clone()
597            }
598        }
599    };
600}
601
602// impls which are shared by all BinaryOps.
603// If possible, prefer `binop_same_type!` or `binop_left_type!`, which
604// provide additional impls
605macro_rules! impl_binop {
606    ($expr:ty, $dispname:expr) => {
607        impl ConstBinaryOp for $expr {
608            fn get_operand0(&self) -> ConstantRef {
609                self.operand0.clone()
610            }
611            fn get_operand1(&self) -> ConstantRef {
612                self.operand1.clone()
613            }
614        }
615    };
616}
617
618// Use on binops where the result type is the same as both operand types
619// (and the Display impl doesn't need to show any more information other than the operands)
620macro_rules! binop_same_type {
621    ($expr:ty, $dispname:expr) => {
622        impl_binop!($expr, $dispname);
623
624        impl Typed for $expr {
625            fn get_type(&self, types: &Types) -> TypeRef {
626                let t = types.type_of(&self.get_operand0());
627                debug_assert_eq!(t, types.type_of(&self.get_operand1()));
628                t
629            }
630        }
631
632        impl Display for $expr {
633            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
634                write!(f, "{} ({}, {})", $dispname, &self.operand0, &self.operand1)
635            }
636        }
637    };
638}
639
640// Use on binops where the result type is the same as the first operand type
641// (and the Display impl doesn't need to show any more information other than the operands)
642#[cfg(feature = "llvm-18-or-lower")]
643macro_rules! binop_left_type {
644    ($expr:ty, $dispname:expr) => {
645        impl_binop!($expr, $dispname);
646
647        impl Typed for $expr {
648            fn get_type(&self, types: &Types) -> TypeRef {
649                types.type_of(&self.get_operand0())
650            }
651        }
652
653        impl Display for $expr {
654            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
655                write!(f, "{} ({}, {})", $dispname, &self.operand0, &self.operand1)
656            }
657        }
658    };
659}
660
661// Use on unops with a 'to_type' field which indicates the result type
662macro_rules! unop_explicitly_typed {
663    ($expr:ty, $dispname:expr) => {
664        impl_unop!($expr);
665
666        impl Typed for $expr {
667            fn get_type(&self, _types: &Types) -> TypeRef {
668                self.to_type.clone()
669            }
670        }
671
672        impl Display for $expr {
673            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
674                write!(
675                    f,
676                    "{} ({} to {})",
677                    $dispname,
678                    &self.get_operand(),
679                    &self.to_type,
680                )
681            }
682        }
683    };
684}
685
686#[derive(PartialEq, Clone, Debug, Hash)]
687pub struct Add {
688    pub operand0: ConstantRef,
689    pub operand1: ConstantRef,
690    // pub nsw: bool,  // getters for these seem to not be exposed in the LLVM C API, only in the C++ one
691    // pub nuw: bool,  // getters for these seem to not be exposed in the LLVM C API, only in the C++ one
692}
693
694impl_constexpr!(Add, Add);
695binop_same_type!(Add, "add");
696
697#[derive(PartialEq, Clone, Debug, Hash)]
698pub struct Sub {
699    pub operand0: ConstantRef,
700    pub operand1: ConstantRef,
701    // pub nsw: bool,  // getters for these seem to not be exposed in the LLVM C API, only in the C++ one
702    // pub nuw: bool,  // getters for these seem to not be exposed in the LLVM C API, only in the C++ one
703}
704
705impl_constexpr!(Sub, Sub);
706binop_same_type!(Sub, "sub");
707
708#[derive(PartialEq, Clone, Debug, Hash)]
709pub struct Mul {
710    pub operand0: ConstantRef,
711    pub operand1: ConstantRef,
712    // pub nsw: bool,  // getters for these seem to not be exposed in the LLVM C API, only in the C++ one
713    // pub nuw: bool,  // getters for these seem to not be exposed in the LLVM C API, only in the C++ one
714}
715
716impl_constexpr!(Mul, Mul);
717binop_same_type!(Mul, "mul");
718
719#[cfg(feature = "llvm-14-or-lower")]
720#[derive(PartialEq, Clone, Debug, Hash)]
721pub struct UDiv {
722    pub operand0: ConstantRef,
723    pub operand1: ConstantRef,
724    // pub exact: bool,  // getters for these seem to not be exposed in the LLVM C API, only in the C++ one
725}
726
727#[cfg(feature = "llvm-14-or-lower")]
728impl_constexpr!(UDiv, UDiv);
729#[cfg(feature = "llvm-14-or-lower")]
730binop_same_type!(UDiv, "udiv");
731
732#[cfg(feature = "llvm-14-or-lower")]
733#[derive(PartialEq, Clone, Debug, Hash)]
734pub struct SDiv {
735    pub operand0: ConstantRef,
736    pub operand1: ConstantRef,
737    // pub exact: bool,  // getters for these seem to not be exposed in the LLVM C API, only in the C++ one
738}
739
740#[cfg(feature = "llvm-14-or-lower")]
741impl_constexpr!(SDiv, SDiv);
742#[cfg(feature = "llvm-14-or-lower")]
743binop_same_type!(SDiv, "sdiv");
744
745#[cfg(feature = "llvm-14-or-lower")]
746#[derive(PartialEq, Clone, Debug, Hash)]
747pub struct URem {
748    pub operand0: ConstantRef,
749    pub operand1: ConstantRef,
750}
751
752#[cfg(feature = "llvm-14-or-lower")]
753impl_constexpr!(URem, URem);
754#[cfg(feature = "llvm-14-or-lower")]
755binop_same_type!(URem, "urem");
756
757#[cfg(feature = "llvm-14-or-lower")]
758#[derive(PartialEq, Clone, Debug, Hash)]
759pub struct SRem {
760    pub operand0: ConstantRef,
761    pub operand1: ConstantRef,
762}
763
764#[cfg(feature = "llvm-14-or-lower")]
765impl_constexpr!(SRem, SRem);
766#[cfg(feature = "llvm-14-or-lower")]
767binop_same_type!(SRem, "srem");
768
769#[cfg(feature = "llvm-17-or-lower")]
770#[derive(PartialEq, Clone, Debug, Hash)]
771pub struct And {
772    pub operand0: ConstantRef,
773    pub operand1: ConstantRef,
774}
775
776#[cfg(feature = "llvm-17-or-lower")]
777impl_constexpr!(And, And);
778#[cfg(feature = "llvm-17-or-lower")]
779binop_same_type!(And, "and");
780
781#[cfg(feature = "llvm-17-or-lower")]
782#[derive(PartialEq, Clone, Debug, Hash)]
783pub struct Or {
784    pub operand0: ConstantRef,
785    pub operand1: ConstantRef,
786}
787
788#[cfg(feature = "llvm-17-or-lower")]
789impl_constexpr!(Or, Or);
790#[cfg(feature = "llvm-17-or-lower")]
791binop_same_type!(Or, "or");
792
793#[derive(PartialEq, Clone, Debug, Hash)]
794pub struct Xor {
795    pub operand0: ConstantRef,
796    pub operand1: ConstantRef,
797}
798
799impl_constexpr!(Xor, Xor);
800binop_same_type!(Xor, "xor");
801
802#[cfg(feature = "llvm-18-or-lower")]
803#[derive(PartialEq, Clone, Debug, Hash)]
804pub struct Shl {
805    pub operand0: ConstantRef,
806    pub operand1: ConstantRef,
807    // pub nsw: bool,  // getters for these seem to not be exposed in the LLVM C API, only in the C++ one
808    // pub nuw: bool,  // getters for these seem to not be exposed in the LLVM C API, only in the C++ one
809}
810
811#[cfg(feature = "llvm-18-or-lower")]
812impl_constexpr!(Shl, Shl);
813#[cfg(feature = "llvm-18-or-lower")]
814binop_left_type!(Shl, "shl");
815
816#[cfg(feature = "llvm-17-or-lower")]
817#[derive(PartialEq, Clone, Debug, Hash)]
818pub struct LShr {
819    pub operand0: ConstantRef,
820    pub operand1: ConstantRef,
821    // pub exact: bool,  // getters for these seem to not be exposed in the LLVM C API, only in the C++ one
822}
823
824#[cfg(feature = "llvm-17-or-lower")]
825impl_constexpr!(LShr, LShr);
826#[cfg(feature = "llvm-17-or-lower")]
827binop_left_type!(LShr, "lshr");
828
829#[cfg(feature = "llvm-17-or-lower")]
830#[derive(PartialEq, Clone, Debug, Hash)]
831pub struct AShr {
832    pub operand0: ConstantRef,
833    pub operand1: ConstantRef,
834    // pub exact: bool,  // getters for these seem to not be exposed in the LLVM C API, only in the C++ one
835}
836
837#[cfg(feature = "llvm-17-or-lower")]
838impl_constexpr!(AShr, AShr);
839#[cfg(feature = "llvm-17-or-lower")]
840binop_left_type!(AShr, "ashr");
841
842#[cfg(feature = "llvm-14-or-lower")]
843#[derive(PartialEq, Clone, Debug, Hash)]
844pub struct FAdd {
845    pub operand0: ConstantRef,
846    pub operand1: ConstantRef,
847}
848
849#[cfg(feature = "llvm-14-or-lower")]
850impl_constexpr!(FAdd, FAdd);
851#[cfg(feature = "llvm-14-or-lower")]
852binop_same_type!(FAdd, "fadd");
853
854#[cfg(feature = "llvm-14-or-lower")]
855#[derive(PartialEq, Clone, Debug, Hash)]
856pub struct FSub {
857    pub operand0: ConstantRef,
858    pub operand1: ConstantRef,
859}
860
861#[cfg(feature = "llvm-14-or-lower")]
862impl_constexpr!(FSub, FSub);
863#[cfg(feature = "llvm-14-or-lower")]
864binop_same_type!(FSub, "fsub");
865
866#[cfg(feature = "llvm-14-or-lower")]
867#[derive(PartialEq, Clone, Debug, Hash)]
868pub struct FMul {
869    pub operand0: ConstantRef,
870    pub operand1: ConstantRef,
871}
872
873#[cfg(feature = "llvm-14-or-lower")]
874impl_constexpr!(FMul, FMul);
875#[cfg(feature = "llvm-14-or-lower")]
876binop_same_type!(FMul, "fmul");
877
878#[cfg(feature = "llvm-14-or-lower")]
879#[derive(PartialEq, Clone, Debug, Hash)]
880pub struct FDiv {
881    pub operand0: ConstantRef,
882    pub operand1: ConstantRef,
883}
884
885#[cfg(feature = "llvm-14-or-lower")]
886impl_constexpr!(FDiv, FDiv);
887#[cfg(feature = "llvm-14-or-lower")]
888binop_same_type!(FDiv, "fdiv");
889
890#[cfg(feature = "llvm-14-or-lower")]
891#[derive(PartialEq, Clone, Debug, Hash)]
892pub struct FRem {
893    pub operand0: ConstantRef,
894    pub operand1: ConstantRef,
895}
896
897#[cfg(feature = "llvm-14-or-lower")]
898impl_constexpr!(FRem, FRem);
899#[cfg(feature = "llvm-14-or-lower")]
900binop_same_type!(FRem, "frem");
901
902#[derive(PartialEq, Clone, Debug, Hash)]
903pub struct ExtractElement {
904    pub vector: ConstantRef,
905    pub index: ConstantRef,
906}
907
908impl_constexpr!(ExtractElement, ExtractElement);
909
910impl Typed for ExtractElement {
911    fn get_type(&self, types: &Types) -> TypeRef {
912        match types.type_of(&self.vector).as_ref() {
913            Type::VectorType { element_type, .. } => element_type.clone(),
914            ty => panic!(
915                "Expected an ExtractElement vector to be VectorType, got {:?}",
916                ty
917            ),
918        }
919    }
920}
921
922impl Display for ExtractElement {
923    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
924        write!(f, "extractelement ({}, {})", &self.vector, &self.index)
925    }
926}
927
928#[derive(PartialEq, Clone, Debug, Hash)]
929pub struct InsertElement {
930    pub vector: ConstantRef,
931    pub element: ConstantRef,
932    pub index: ConstantRef,
933}
934
935impl_constexpr!(InsertElement, InsertElement);
936
937impl Typed for InsertElement {
938    fn get_type(&self, types: &Types) -> TypeRef {
939        types.type_of(&self.vector)
940    }
941}
942
943impl Display for InsertElement {
944    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
945        write!(
946            f,
947            "insertelement ({}, {}, {})",
948            &self.vector, &self.element, &self.index,
949        )
950    }
951}
952
953#[derive(PartialEq, Clone, Debug, Hash)]
954pub struct ShuffleVector {
955    pub operand0: ConstantRef,
956    pub operand1: ConstantRef,
957    pub mask: ConstantRef,
958}
959
960impl_constexpr!(ShuffleVector, ShuffleVector);
961impl_binop!(ShuffleVector, "shufflevector");
962
963impl Typed for ShuffleVector {
964    fn get_type(&self, types: &Types) -> TypeRef {
965        let ty = types.type_of(&self.operand0);
966        debug_assert_eq!(ty, types.type_of(&self.operand1));
967        match ty.as_ref() {
968            Type::VectorType { element_type, .. } => match types.type_of(&self.mask).as_ref() {
969                #[cfg(feature = "llvm-11-or-greater")]
970                Type::VectorType {
971                    num_elements,
972                    scalable,
973                    ..
974                } => types.vector_of(element_type.clone(), *num_elements, *scalable),
975                #[cfg(feature = "llvm-10-or-lower")]
976                Type::VectorType { num_elements, .. } => {
977                    types.vector_of(element_type.clone(), *num_elements)
978                },
979                ty => panic!(
980                    "Expected a ShuffleVector mask to be VectorType, got {:?}",
981                    ty
982                ),
983            },
984            _ => panic!(
985                "Expected a ShuffleVector operand to be VectorType, got {:?}",
986                ty
987            ),
988        }
989    }
990}
991
992impl Display for ShuffleVector {
993    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
994        write!(
995            f,
996            "shufflevector ({}, {}, {})",
997            &self.operand0, &self.operand1, &self.mask,
998        )
999    }
1000}
1001
1002#[cfg(feature = "llvm-14-or-lower")]
1003#[derive(PartialEq, Clone, Debug, Hash)]
1004pub struct ExtractValue {
1005    pub aggregate: ConstantRef,
1006    pub indices: Vec<u32>,
1007}
1008
1009#[cfg(feature = "llvm-14-or-lower")]
1010impl_constexpr!(ExtractValue, ExtractValue);
1011
1012#[cfg(feature = "llvm-14-or-lower")]
1013impl Typed for ExtractValue {
1014    fn get_type(&self, types: &Types) -> TypeRef {
1015        ev_type(types.type_of(&self.aggregate), self.indices.iter().copied())
1016    }
1017}
1018
1019#[cfg(feature = "llvm-14-or-lower")]
1020fn ev_type(cur_type: TypeRef, mut indices: impl Iterator<Item = u32>) -> TypeRef {
1021    match indices.next() {
1022        None => cur_type,
1023        Some(index) => match cur_type.as_ref() {
1024            Type::ArrayType { element_type, .. } => ev_type(element_type.clone(), indices),
1025            Type::StructType { element_types, .. } => ev_type(
1026                element_types
1027                    .get(index as usize)
1028                    .expect("ExtractValue index out of range")
1029                    .clone(),
1030                indices,
1031            ),
1032            _ => panic!(
1033                "ExtractValue from something that's not ArrayType or StructType; its type is {:?}",
1034                cur_type
1035            ),
1036        },
1037    }
1038}
1039
1040#[cfg(feature = "llvm-14-or-lower")]
1041impl Display for ExtractValue {
1042    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1043        write!(f, "extractvalue ({}", &self.aggregate)?;
1044        for idx in &self.indices {
1045            write!(f, ", {}", idx)?;
1046        }
1047        write!(f, ")")?;
1048        Ok(())
1049    }
1050}
1051
1052#[cfg(feature = "llvm-14-or-lower")]
1053#[derive(PartialEq, Clone, Debug, Hash)]
1054pub struct InsertValue {
1055    pub aggregate: ConstantRef,
1056    pub element: ConstantRef,
1057    pub indices: Vec<u32>,
1058}
1059
1060#[cfg(feature = "llvm-14-or-lower")]
1061impl_constexpr!(InsertValue, InsertValue);
1062
1063#[cfg(feature = "llvm-14-or-lower")]
1064impl Typed for InsertValue {
1065    fn get_type(&self, types: &Types) -> TypeRef {
1066        types.type_of(&self.aggregate)
1067    }
1068}
1069
1070#[cfg(feature = "llvm-14-or-lower")]
1071impl Display for InsertValue {
1072    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1073        write!(f, "insertvalue ({}, {}", &self.aggregate, &self.element)?;
1074        for idx in &self.indices {
1075            write!(f, ", {}", idx)?;
1076        }
1077        write!(f, ")")?;
1078        Ok(())
1079    }
1080}
1081
1082#[derive(PartialEq, Clone, Debug, Hash)]
1083pub struct GetElementPtr {
1084    pub address: ConstantRef,
1085    pub indices: Vec<ConstantRef>,
1086    pub in_bounds: bool,
1087}
1088
1089impl_constexpr!(GetElementPtr, GetElementPtr);
1090
1091#[cfg(feature = "llvm-14-or-lower")]
1092impl Typed for GetElementPtr {
1093    fn get_type(&self, types: &Types) -> TypeRef {
1094        gep_type(types.type_of(&self.address), self.indices.iter(), types)
1095    }
1096}
1097#[cfg(feature = "llvm-15-or-greater")]
1098impl Typed for GetElementPtr {
1099    fn get_type(&self, types: &Types) -> TypeRef {
1100        types.pointer()
1101    }
1102}
1103
1104#[cfg(feature = "llvm-14-or-lower")]
1105fn gep_type<'c>(
1106    cur_type: TypeRef,
1107    mut indices: impl Iterator<Item = &'c ConstantRef>,
1108    types: &Types,
1109) -> TypeRef {
1110    match indices.next() {
1111        None => types.pointer_to(cur_type), // iterator is done
1112        Some(index) => match cur_type.as_ref() {
1113            Type::PointerType { pointee_type, .. } => gep_type(pointee_type.clone(), indices, types),
1114            Type::VectorType { element_type, .. } => gep_type(element_type.clone(), indices, types),
1115            Type::ArrayType { element_type, .. } => gep_type(element_type.clone(), indices, types),
1116            Type::StructType { element_types, .. } => {
1117                if let Constant::Int { value, .. } = index.as_ref() {
1118                    gep_type(
1119                        element_types.get(*value as usize).cloned().expect("GEP index out of range"),
1120                        indices,
1121                        types,
1122                    )
1123                } else {
1124                    panic!("Expected GEP index on a constant struct to be a Constant::Int; got {:?}", index)
1125                }
1126            },
1127            Type::NamedStructType { name } => match types.named_struct_def(name) {
1128                None => panic!("Named struct with no definition (struct name {:?})", name),
1129                Some(NamedStructDef::Opaque) => panic!("GEP on an opaque struct type"),
1130                Some(NamedStructDef::Defined(ty)) => match ty.as_ref() {
1131                    Type::StructType { element_types, .. } => {
1132                        if let Constant::Int { value, .. } = index.as_ref() {
1133                            gep_type(element_types.get(*value as usize).cloned().expect("GEP index out of range"), indices, types)
1134                        } else {
1135                            panic!("Expected GEP index on a struct to be a Constant::Int; got {:?}", index)
1136                        }
1137                    },
1138                    ty => panic!("Expected NamedStructDef inner type to be a StructType; got {:?}", ty),
1139                },
1140            }
1141            _ => panic!("Expected GEP base type to be a PointerType, VectorType, ArrayType, StructType, or NamedStructType; got {:?}", cur_type),
1142        },
1143    }
1144}
1145
1146impl Display for GetElementPtr {
1147    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1148        write!(
1149            f,
1150            "getelementptr{} ({}",
1151            if self.in_bounds { " inbounds" } else { "" },
1152            &self.address
1153        )?;
1154        for idx in &self.indices {
1155            write!(f, ", {}", idx)?;
1156        }
1157        write!(f, ")")?;
1158        Ok(())
1159    }
1160}
1161
1162#[derive(PartialEq, Clone, Debug, Hash)]
1163pub struct Trunc {
1164    pub operand: ConstantRef,
1165    pub to_type: TypeRef,
1166}
1167
1168impl_constexpr!(Trunc, Trunc);
1169unop_explicitly_typed!(Trunc, "trunc");
1170
1171#[cfg(feature = "llvm-17-or-lower")]
1172#[derive(PartialEq, Clone, Debug, Hash)]
1173pub struct ZExt {
1174    pub operand: ConstantRef,
1175    pub to_type: TypeRef,
1176}
1177
1178#[cfg(feature = "llvm-17-or-lower")]
1179impl_constexpr!(ZExt, ZExt);
1180#[cfg(feature = "llvm-17-or-lower")]
1181unop_explicitly_typed!(ZExt, "zext");
1182
1183#[cfg(feature = "llvm-17-or-lower")]
1184#[derive(PartialEq, Clone, Debug, Hash)]
1185pub struct SExt {
1186    pub operand: ConstantRef,
1187    pub to_type: TypeRef,
1188}
1189
1190#[cfg(feature = "llvm-17-or-lower")]
1191impl_constexpr!(SExt, SExt);
1192#[cfg(feature = "llvm-17-or-lower")]
1193unop_explicitly_typed!(SExt, "sext");
1194
1195#[cfg(feature = "llvm-17-or-lower")]
1196#[derive(PartialEq, Clone, Debug, Hash)]
1197pub struct FPTrunc {
1198    pub operand: ConstantRef,
1199    pub to_type: TypeRef,
1200}
1201#[cfg(feature = "llvm-17-or-lower")]
1202impl_constexpr!(FPTrunc, FPTrunc);
1203#[cfg(feature = "llvm-17-or-lower")]
1204unop_explicitly_typed!(FPTrunc, "fptrunc");
1205
1206#[cfg(feature = "llvm-17-or-lower")]
1207#[derive(PartialEq, Clone, Debug, Hash)]
1208pub struct FPExt {
1209    pub operand: ConstantRef,
1210    pub to_type: TypeRef,
1211}
1212
1213#[cfg(feature = "llvm-17-or-lower")]
1214impl_constexpr!(FPExt, FPExt);
1215#[cfg(feature = "llvm-17-or-lower")]
1216unop_explicitly_typed!(FPExt, "fpext");
1217
1218#[cfg(feature = "llvm-17-or-lower")]
1219#[derive(PartialEq, Clone, Debug, Hash)]
1220pub struct FPToUI {
1221    pub operand: ConstantRef,
1222    pub to_type: TypeRef,
1223}
1224
1225#[cfg(feature = "llvm-17-or-lower")]
1226impl_constexpr!(FPToUI, FPToUI);
1227#[cfg(feature = "llvm-17-or-lower")]
1228unop_explicitly_typed!(FPToUI, "fptoui");
1229
1230#[cfg(feature = "llvm-17-or-lower")]
1231#[derive(PartialEq, Clone, Debug, Hash)]
1232pub struct FPToSI {
1233    pub operand: ConstantRef,
1234    pub to_type: TypeRef,
1235}
1236
1237#[cfg(feature = "llvm-17-or-lower")]
1238impl_constexpr!(FPToSI, FPToSI);
1239#[cfg(feature = "llvm-17-or-lower")]
1240unop_explicitly_typed!(FPToSI, "fptosi");
1241
1242#[cfg(feature = "llvm-17-or-lower")]
1243#[derive(PartialEq, Clone, Debug, Hash)]
1244pub struct UIToFP {
1245    pub operand: ConstantRef,
1246    pub to_type: TypeRef,
1247}
1248
1249#[cfg(feature = "llvm-17-or-lower")]
1250impl_constexpr!(UIToFP, UIToFP);
1251#[cfg(feature = "llvm-17-or-lower")]
1252unop_explicitly_typed!(UIToFP, "uitofp");
1253
1254#[cfg(feature = "llvm-17-or-lower")]
1255#[derive(PartialEq, Clone, Debug, Hash)]
1256pub struct SIToFP {
1257    pub operand: ConstantRef,
1258    pub to_type: TypeRef,
1259}
1260
1261#[cfg(feature = "llvm-17-or-lower")]
1262impl_constexpr!(SIToFP, SIToFP);
1263#[cfg(feature = "llvm-17-or-lower")]
1264unop_explicitly_typed!(SIToFP, "sitofp");
1265
1266#[derive(PartialEq, Clone, Debug, Hash)]
1267pub struct PtrToInt {
1268    pub operand: ConstantRef,
1269    pub to_type: TypeRef,
1270}
1271
1272impl_constexpr!(PtrToInt, PtrToInt);
1273unop_explicitly_typed!(PtrToInt, "ptrtoint");
1274
1275#[derive(PartialEq, Clone, Debug, Hash)]
1276pub struct IntToPtr {
1277    pub operand: ConstantRef,
1278    pub to_type: TypeRef,
1279}
1280
1281impl_constexpr!(IntToPtr, IntToPtr);
1282unop_explicitly_typed!(IntToPtr, "inttoptr");
1283
1284#[derive(PartialEq, Clone, Debug, Hash)]
1285pub struct BitCast {
1286    pub operand: ConstantRef,
1287    pub to_type: TypeRef,
1288}
1289
1290impl_constexpr!(BitCast, BitCast);
1291unop_explicitly_typed!(BitCast, "bitcast");
1292
1293#[derive(PartialEq, Clone, Debug, Hash)]
1294pub struct AddrSpaceCast {
1295    pub operand: ConstantRef,
1296    pub to_type: TypeRef,
1297}
1298
1299impl_constexpr!(AddrSpaceCast, AddrSpaceCast);
1300unop_explicitly_typed!(AddrSpaceCast, "addrspacecast");
1301
1302#[cfg(feature = "llvm-18-or-lower")]
1303#[derive(PartialEq, Clone, Debug, Hash)]
1304pub struct ICmp {
1305    pub predicate: IntPredicate,
1306    pub operand0: ConstantRef,
1307    pub operand1: ConstantRef,
1308}
1309
1310#[cfg(feature = "llvm-18-or-lower")]
1311impl_constexpr!(ICmp, ICmp);
1312#[cfg(feature = "llvm-18-or-lower")]
1313impl_binop!(ICmp, "icmp");
1314
1315#[cfg(feature = "llvm-18-or-lower")]
1316impl Typed for ICmp {
1317    fn get_type(&self, types: &Types) -> TypeRef {
1318        let ty = types.type_of(&self.operand0);
1319        debug_assert_eq!(ty, types.type_of(&self.operand1));
1320        match ty.as_ref() {
1321            #[cfg(feature = "llvm-11-or-greater")]
1322            Type::VectorType {
1323                num_elements,
1324                scalable,
1325                ..
1326            } => types.vector_of(types.bool(), *num_elements, *scalable),
1327            #[cfg(feature = "llvm-10-or-lower")]
1328            Type::VectorType { num_elements, .. } => types.vector_of(types.bool(), *num_elements),
1329            _ => types.bool(),
1330        }
1331    }
1332}
1333
1334#[cfg(feature = "llvm-18-or-lower")]
1335impl Display for ICmp {
1336    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1337        write!(
1338            f,
1339            "icmp {} ({}, {})",
1340            &self.predicate, &self.operand0, &self.operand1,
1341        )
1342    }
1343}
1344
1345#[cfg(feature = "llvm-18-or-lower")]
1346#[derive(PartialEq, Clone, Debug, Hash)]
1347pub struct FCmp {
1348    pub predicate: FPPredicate,
1349    pub operand0: ConstantRef,
1350    pub operand1: ConstantRef,
1351}
1352
1353#[cfg(feature = "llvm-18-or-lower")]
1354impl_constexpr!(FCmp, FCmp);
1355#[cfg(feature = "llvm-18-or-lower")]
1356impl_binop!(FCmp, "fcmp");
1357
1358#[cfg(feature = "llvm-18-or-lower")]
1359impl Typed for FCmp {
1360    fn get_type(&self, types: &Types) -> TypeRef {
1361        let ty = types.type_of(&self.operand0);
1362        debug_assert_eq!(ty, types.type_of(&self.operand1));
1363        match ty.as_ref() {
1364            #[cfg(feature = "llvm-11-or-greater")]
1365            Type::VectorType {
1366                num_elements,
1367                scalable,
1368                ..
1369            } => types.vector_of(types.bool(), *num_elements, *scalable),
1370            #[cfg(feature = "llvm-10-or-lower")]
1371            Type::VectorType { num_elements, .. } => types.vector_of(types.bool(), *num_elements),
1372            _ => types.bool(),
1373        }
1374    }
1375}
1376
1377#[cfg(feature = "llvm-18-or-lower")]
1378impl Display for FCmp {
1379    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1380        write!(
1381            f,
1382            "fcmp {} ({}, {})",
1383            &self.predicate, &self.operand0, &self.operand1,
1384        )
1385    }
1386}
1387
1388#[cfg(feature="llvm-16-or-lower")]
1389#[derive(PartialEq, Clone, Debug, Hash)]
1390pub struct Select {
1391    pub condition: ConstantRef,
1392    pub true_value: ConstantRef,
1393    pub false_value: ConstantRef,
1394}
1395
1396#[cfg(feature="llvm-16-or-lower")]
1397impl_constexpr!(Select, Select);
1398
1399#[cfg(feature="llvm-16-or-lower")]
1400impl Typed for Select {
1401    fn get_type(&self, types: &Types) -> TypeRef {
1402        let t = types.type_of(&self.true_value);
1403        debug_assert_eq!(t, types.type_of(&self.false_value));
1404        t
1405    }
1406}
1407
1408#[cfg(feature="llvm-16-or-lower")]
1409impl Display for Select {
1410    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1411        write!(
1412            f,
1413            "select ({}, {}, {})",
1414            &self.condition, &self.true_value, &self.false_value,
1415        )
1416    }
1417}
1418
1419// ********* //
1420// from_llvm //
1421// ********* //
1422
1423use crate::llvm_sys::*;
1424use crate::module::ModuleContext;
1425use std::collections::hash_map::Entry;
1426
1427impl Constant {
1428    pub(crate) fn from_llvm_ref(constant: LLVMValueRef, ctx: &mut ModuleContext) -> ConstantRef {
1429        if let Some(constantref) = ctx.constants.get(&constant) {
1430            return constantref.clone();
1431        }
1432        let parsed = Self::parse_from_llvm_ref(constant, ctx);
1433        match ctx.constants.entry(constant) {
1434            Entry::Occupied(_) => panic!("This case should have been handled above"),
1435            Entry::Vacant(ventry) => ventry.insert(ConstantRef::new(parsed)).clone(),
1436        }
1437    }
1438
1439    fn parse_from_llvm_ref(constant: LLVMValueRef, ctx: &mut ModuleContext) -> Self {
1440        use llvm_sys::LLVMValueKind;
1441        if unsafe { LLVMIsAConstant(constant).is_null() } {
1442            panic!(
1443                "Constant::from_llvm_ref: argument wasn't a constant; ValueKind {:?}",
1444                unsafe { LLVMGetValueKind(constant) }
1445            )
1446        }
1447        match unsafe { LLVMGetValueKind(constant) } {
1448            LLVMValueKind::LLVMConstantIntValueKind => {
1449                match ctx.types.type_from_llvm_ref( unsafe { LLVMTypeOf(constant) } ).as_ref() {
1450                    Type::IntegerType { bits } => Constant::Int {
1451                        bits: *bits,
1452                        value: unsafe { LLVMConstIntGetZExtValue(constant) } as u64,
1453                    },
1454                    ty => panic!("Expected Constant::Int to have type Type::IntegerType; got {:?}", ty),
1455                }
1456            },
1457            LLVMValueKind::LLVMConstantFPValueKind => {
1458                match ctx.types.type_from_llvm_ref( unsafe { LLVMTypeOf(constant) } ).as_ref() {
1459                    Type::FPType(fptype) => Constant::Float(match fptype {
1460                        FPType::Half => Float::Half,
1461                        #[cfg(feature="llvm-11-or-greater")]
1462                        FPType::BFloat => Float::BFloat,
1463                        FPType::Single => Float::Single( unsafe {
1464                            let mut b = 0;
1465                            let b_ptr: *mut std::os::raw::c_int = &mut b;
1466                            LLVMConstRealGetDouble(constant, b_ptr)
1467                        } as f32),
1468                        FPType::Double => Float::Double( unsafe {
1469                            let mut b = 0;
1470                            let b_ptr: *mut std::os::raw::c_int = &mut b;
1471                            LLVMConstRealGetDouble(constant, b_ptr)
1472                        } ),
1473                        FPType::FP128 => Float::Quadruple,
1474                        FPType::X86_FP80 => Float::X86_FP80,
1475                        FPType::PPC_FP128 => Float::PPC_FP128,
1476                    }),
1477                    ty => panic!("Expected Constant::Float to have type Type::FPType; got {:?}", ty),
1478                }
1479            },
1480            LLVMValueKind::LLVMConstantStructValueKind => {
1481                let (num_elements, is_packed) = match ctx.types.type_from_llvm_ref( unsafe { LLVMTypeOf(constant) } ).as_ref() {
1482                    Type::StructType { element_types, is_packed } => (element_types.len(), *is_packed),
1483                    Type::NamedStructType { name } => match ctx.types.named_struct_def(name) {
1484                        NamedStructDef::Opaque => panic!("Constant of opaque struct type (struct name {:?})", name),
1485                        NamedStructDef::Defined(ty) => match ty.as_ref() {
1486                            Type::StructType { element_types, is_packed } => {
1487                                (element_types.len(), *is_packed)
1488                            },
1489                            ty => panic!("Expected NamedStructDef inner type to be a StructType, but it actually is a {:?}", ty),
1490                        },
1491                    },
1492                    ty => panic!("Expected Constant::Struct to have type StructType or NamedStructType; got {:?}", ty),
1493                };
1494                Constant::Struct {
1495                    name: None,  // --TODO not yet implemented: Constant::Struct name
1496                    values: {
1497                        (0 .. num_elements).map(|i| {
1498                            Constant::from_llvm_ref( unsafe { LLVMGetOperand(constant, i as u32) }, ctx)
1499                        }).collect()
1500                    },
1501                    is_packed,
1502                }
1503            },
1504            LLVMValueKind::LLVMConstantArrayValueKind => {
1505                match ctx.types.type_from_llvm_ref( unsafe { LLVMTypeOf(constant) } ).as_ref() {
1506                    Type::ArrayType { element_type, num_elements } => Constant::Array {
1507                        element_type: element_type.clone(),
1508                        elements: {
1509                            (0 .. *num_elements).map(|i| Constant::from_llvm_ref( unsafe { LLVMGetOperand(constant, i as u32) }, ctx)).collect()
1510                        },
1511                    },
1512                    ty => panic!("Expected Constant::Array to have type Type::ArrayType; got {:?}", ty),
1513                }
1514            },
1515            LLVMValueKind::LLVMConstantVectorValueKind => {
1516                let num_elements = unsafe { LLVMGetNumOperands(constant) };
1517                Constant::Vector(
1518                    (0 .. num_elements).map(|i| Constant::from_llvm_ref( unsafe { LLVMGetOperand(constant, i as u32) }, ctx)).collect()
1519                )
1520            },
1521            LLVMValueKind::LLVMConstantDataArrayValueKind => {
1522                match ctx.types.type_from_llvm_ref( unsafe { LLVMTypeOf(constant) } ).as_ref() {
1523                    Type::ArrayType { element_type, num_elements } => Constant::Array {
1524                        element_type: element_type.clone(),
1525                        elements: {
1526                            #[cfg(feature = "llvm-14-or-lower")]
1527                            { (0 .. *num_elements).map(|i| Constant::from_llvm_ref( unsafe { LLVMGetElementAsConstant(constant, i as u32) }, ctx)).collect() }
1528                            #[cfg(feature = "llvm-15-or-greater")]
1529                            { (0 .. *num_elements).map(|i| Constant::from_llvm_ref( unsafe { LLVMGetAggregateElement(constant, i as u32) }, ctx)).collect() }
1530                        },
1531                    },
1532                    ty => panic!("Expected ConstantDataArray to have type Type::ArrayType; got {:?}", ty),
1533                }
1534            },
1535            LLVMValueKind::LLVMConstantDataVectorValueKind => {
1536                match ctx.types.type_from_llvm_ref( unsafe { LLVMTypeOf(constant) } ).as_ref() {
1537                    Type::VectorType { num_elements, .. } => Constant::Vector(
1538                        (0 .. *num_elements).map(
1539                            |i| Constant::from_llvm_ref(
1540                                unsafe {
1541                                    #[cfg(feature = "llvm-14-or-lower")]
1542                                    { LLVMGetElementAsConstant(constant, i as u32) }
1543                                    #[cfg(feature = "llvm-15-or-greater")]
1544                                    { LLVMGetAggregateElement(constant, i as u32) }
1545                                },
1546                                ctx)).collect()
1547                    ),
1548                    ty => panic!("Expected ConstantDataVector to have type Type::VectorType; got {:?}", ty),
1549                }
1550            },
1551            LLVMValueKind::LLVMConstantPointerNullValueKind => {
1552                Constant::Null(ctx.types.type_from_llvm_ref( unsafe { LLVMTypeOf(constant) } ))
1553            },
1554            LLVMValueKind::LLVMConstantAggregateZeroValueKind => {
1555                Constant::AggregateZero(ctx.types.type_from_llvm_ref( unsafe { LLVMTypeOf(constant) } ))
1556            },
1557            LLVMValueKind::LLVMUndefValueValueKind => {
1558                Constant::Undef(ctx.types.type_from_llvm_ref( unsafe { LLVMTypeOf(constant) } ))
1559            },
1560            #[cfg(feature = "llvm-12-or-greater")]
1561            LLVMValueKind::LLVMPoisonValueKind => {
1562                Constant::Poison(ctx.types.type_from_llvm_ref( unsafe { LLVMTypeOf(constant) } ))
1563            },
1564            LLVMValueKind::LLVMConstantTokenNoneValueKind => {
1565                Constant::TokenNone
1566            },
1567            LLVMValueKind::LLVMBlockAddressValueKind => {
1568                Constant::BlockAddress
1569            },
1570            LLVMValueKind::LLVMConstantExprValueKind => {
1571                use llvm_sys::LLVMOpcode;
1572                match unsafe { LLVMGetConstOpcode(constant) } {
1573                    LLVMOpcode::LLVMAdd => Constant::Add(Add::from_llvm_ref(constant, ctx)),
1574                    LLVMOpcode::LLVMSub => Constant::Sub(Sub::from_llvm_ref(constant, ctx)),
1575                    LLVMOpcode::LLVMMul => Constant::Mul(Mul::from_llvm_ref(constant, ctx)),
1576                    #[cfg(feature = "llvm-14-or-lower")]
1577                    LLVMOpcode::LLVMUDiv => Constant::UDiv(UDiv::from_llvm_ref(constant, ctx)),
1578                    #[cfg(feature = "llvm-14-or-lower")]
1579                    LLVMOpcode::LLVMSDiv => Constant::SDiv(SDiv::from_llvm_ref(constant, ctx)),
1580                    #[cfg(feature = "llvm-14-or-lower")]
1581                    LLVMOpcode::LLVMURem => Constant::URem(URem::from_llvm_ref(constant, ctx)),
1582                    #[cfg(feature = "llvm-14-or-lower")]
1583                    LLVMOpcode::LLVMSRem => Constant::SRem(SRem::from_llvm_ref(constant, ctx)),
1584                    #[cfg(feature = "llvm-17-or-lower")]
1585                    LLVMOpcode::LLVMAnd => Constant::And(And::from_llvm_ref(constant, ctx)),
1586                    #[cfg(feature = "llvm-17-or-lower")]
1587                    LLVMOpcode::LLVMOr => Constant::Or(Or::from_llvm_ref(constant, ctx)),
1588                    LLVMOpcode::LLVMXor => Constant::Xor(Xor::from_llvm_ref(constant, ctx)),
1589                    #[cfg(feature = "llvm-18-or-lower")]
1590                    LLVMOpcode::LLVMShl => Constant::Shl(Shl::from_llvm_ref(constant, ctx)),
1591                    #[cfg(feature = "llvm-17-or-lower")]
1592                    LLVMOpcode::LLVMLShr => Constant::LShr(LShr::from_llvm_ref(constant, ctx)),
1593                    #[cfg(feature = "llvm-17-or-lower")]
1594                    LLVMOpcode::LLVMAShr => Constant::AShr(AShr::from_llvm_ref(constant, ctx)),
1595                    #[cfg(feature = "llvm-14-or-lower")]
1596                    LLVMOpcode::LLVMFAdd => Constant::FAdd(FAdd::from_llvm_ref(constant, ctx)),
1597                    #[cfg(feature = "llvm-14-or-lower")]
1598                    LLVMOpcode::LLVMFSub => Constant::FSub(FSub::from_llvm_ref(constant, ctx)),
1599                    #[cfg(feature = "llvm-14-or-lower")]
1600                    LLVMOpcode::LLVMFMul => Constant::FMul(FMul::from_llvm_ref(constant, ctx)),
1601                    #[cfg(feature = "llvm-14-or-lower")]
1602                    LLVMOpcode::LLVMFDiv => Constant::FDiv(FDiv::from_llvm_ref(constant, ctx)),
1603                    #[cfg(feature = "llvm-14-or-lower")]
1604                    LLVMOpcode::LLVMFRem => Constant::FRem(FRem::from_llvm_ref(constant, ctx)),
1605                    LLVMOpcode::LLVMExtractElement => Constant::ExtractElement(ExtractElement::from_llvm_ref(constant, ctx)),
1606                    LLVMOpcode::LLVMInsertElement => Constant::InsertElement(InsertElement::from_llvm_ref(constant, ctx)),
1607                    LLVMOpcode::LLVMShuffleVector => Constant::ShuffleVector(ShuffleVector::from_llvm_ref(constant, ctx)),
1608                    #[cfg(feature = "llvm-14-or-lower")]
1609                    LLVMOpcode::LLVMExtractValue => Constant::ExtractValue(ExtractValue::from_llvm_ref(constant, ctx)),
1610                    #[cfg(feature = "llvm-14-or-lower")]
1611                    LLVMOpcode::LLVMInsertValue => Constant::InsertValue(InsertValue::from_llvm_ref(constant, ctx)),
1612                    LLVMOpcode::LLVMGetElementPtr => Constant::GetElementPtr(GetElementPtr::from_llvm_ref(constant, ctx)),
1613                    LLVMOpcode::LLVMTrunc => Constant::Trunc(Trunc::from_llvm_ref(constant, ctx)),
1614                    #[cfg(feature = "llvm-17-or-lower")]
1615                    LLVMOpcode::LLVMZExt => Constant::ZExt(ZExt::from_llvm_ref(constant, ctx)),
1616                    #[cfg(feature = "llvm-17-or-lower")]
1617                    LLVMOpcode::LLVMSExt => Constant::SExt(SExt::from_llvm_ref(constant, ctx)),
1618                    #[cfg(feature = "llvm-17-or-lower")]
1619                    LLVMOpcode::LLVMFPTrunc => Constant::FPTrunc(FPTrunc::from_llvm_ref(constant, ctx)),
1620                    #[cfg(feature = "llvm-17-or-lower")]
1621                    LLVMOpcode::LLVMFPExt => Constant::FPExt(FPExt::from_llvm_ref(constant, ctx)),
1622                    #[cfg(feature = "llvm-17-or-lower")]
1623                    LLVMOpcode::LLVMFPToUI => Constant::FPToUI(FPToUI::from_llvm_ref(constant, ctx)),
1624                    #[cfg(feature = "llvm-17-or-lower")]
1625                    LLVMOpcode::LLVMFPToSI => Constant::FPToSI(FPToSI::from_llvm_ref(constant, ctx)),
1626                    #[cfg(feature = "llvm-17-or-lower")]
1627                    LLVMOpcode::LLVMUIToFP => Constant::UIToFP(UIToFP::from_llvm_ref(constant, ctx)),
1628                    #[cfg(feature = "llvm-17-or-lower")]
1629                    LLVMOpcode::LLVMSIToFP => Constant::SIToFP(SIToFP::from_llvm_ref(constant, ctx)),
1630                    LLVMOpcode::LLVMPtrToInt => Constant::PtrToInt(PtrToInt::from_llvm_ref(constant, ctx)),
1631                    LLVMOpcode::LLVMIntToPtr => Constant::IntToPtr(IntToPtr::from_llvm_ref(constant, ctx)),
1632                    LLVMOpcode::LLVMBitCast => Constant::BitCast(BitCast::from_llvm_ref(constant, ctx)),
1633                    LLVMOpcode::LLVMAddrSpaceCast => Constant::AddrSpaceCast(AddrSpaceCast::from_llvm_ref(constant, ctx)),
1634                    #[cfg(feature = "llvm-18-or-lower")]
1635                    LLVMOpcode::LLVMICmp => Constant::ICmp(ICmp::from_llvm_ref(constant, ctx)),
1636                    #[cfg(feature = "llvm-18-or-lower")]
1637                    LLVMOpcode::LLVMFCmp => Constant::FCmp(FCmp::from_llvm_ref(constant, ctx)),
1638                    #[cfg(feature="llvm-16-or-lower")]
1639                    LLVMOpcode::LLVMSelect => Constant::Select(Select::from_llvm_ref(constant, ctx)),
1640                    opcode => panic!("ConstantExpr has unexpected opcode {:?}", opcode),
1641                }
1642            },
1643            #[cfg(feature = "llvm-19-or-greater")]
1644            LLVMValueKind::LLVMConstantPtrAuthValueKind => {
1645                Constant::PtrAuth {
1646                    ptr : Constant::from_llvm_ref( unsafe { LLVMGetConstantPtrAuthPointer(constant) }, ctx),
1647                    key : Constant::from_llvm_ref( unsafe { LLVMGetConstantPtrAuthKey(constant) }, ctx),
1648                    disc : Constant::from_llvm_ref( unsafe { LLVMGetConstantPtrAuthDiscriminator(constant) }, ctx),
1649                    addr_disc : Constant::from_llvm_ref( unsafe { LLVMGetConstantPtrAuthAddrDiscriminator(constant) }, ctx)
1650                }
1651            }
1652            _ if unsafe { !LLVMIsAGlobalValue(constant).is_null() } => {
1653                Constant::GlobalReference {
1654                    name: ctx.global_names.get(&constant)
1655                        .unwrap_or_else(|| { let names: Vec<_> = ctx.global_names.values().collect(); panic!("Global not found in ctx.global_names; have names {:?}", names) })
1656                        .clone(),
1657                    ty: ctx.types.type_from_llvm_ref( unsafe { LLVMGlobalGetValueType(constant) } ),
1658                }
1659            },
1660            k => panic!("Constant::from_llvm_ref: don't know how to handle this Constant with ValueKind {:?}", k),
1661        }
1662    }
1663}
1664
1665macro_rules! binop_from_llvm {
1666    ($expr:ident) => {
1667        impl $expr {
1668            pub(crate) fn from_llvm_ref(expr: LLVMValueRef, ctx: &mut ModuleContext) -> Self {
1669                assert_eq!(unsafe { LLVMGetNumOperands(expr) }, 2);
1670                Self {
1671                    operand0: Constant::from_llvm_ref(unsafe { LLVMGetOperand(expr, 0) }, ctx),
1672                    operand1: Constant::from_llvm_ref(unsafe { LLVMGetOperand(expr, 1) }, ctx),
1673                }
1674            }
1675        }
1676    };
1677}
1678
1679binop_from_llvm!(Add);
1680binop_from_llvm!(Sub);
1681binop_from_llvm!(Mul);
1682#[cfg(feature = "llvm-14-or-lower")]
1683binop_from_llvm!(UDiv);
1684#[cfg(feature = "llvm-14-or-lower")]
1685binop_from_llvm!(SDiv);
1686#[cfg(feature = "llvm-14-or-lower")]
1687binop_from_llvm!(URem);
1688#[cfg(feature = "llvm-14-or-lower")]
1689binop_from_llvm!(SRem);
1690#[cfg(feature = "llvm-17-or-lower")]
1691binop_from_llvm!(And);
1692#[cfg(feature = "llvm-17-or-lower")]
1693binop_from_llvm!(Or);
1694binop_from_llvm!(Xor);
1695#[cfg(feature = "llvm-18-or-lower")]
1696binop_from_llvm!(Shl);
1697#[cfg(feature = "llvm-17-or-lower")]
1698binop_from_llvm!(LShr);
1699#[cfg(feature = "llvm-17-or-lower")]
1700binop_from_llvm!(AShr);
1701#[cfg(feature = "llvm-14-or-lower")]
1702binop_from_llvm!(FAdd);
1703#[cfg(feature = "llvm-14-or-lower")]
1704binop_from_llvm!(FSub);
1705#[cfg(feature = "llvm-14-or-lower")]
1706binop_from_llvm!(FMul);
1707#[cfg(feature = "llvm-14-or-lower")]
1708binop_from_llvm!(FDiv);
1709#[cfg(feature = "llvm-14-or-lower")]
1710binop_from_llvm!(FRem);
1711
1712impl ExtractElement {
1713    pub(crate) fn from_llvm_ref(expr: LLVMValueRef, ctx: &mut ModuleContext) -> Self {
1714        assert_eq!(unsafe { LLVMGetNumOperands(expr) }, 2);
1715        Self {
1716            vector: Constant::from_llvm_ref(unsafe { LLVMGetOperand(expr, 0) }, ctx),
1717            index: Constant::from_llvm_ref(unsafe { LLVMGetOperand(expr, 1) }, ctx),
1718        }
1719    }
1720}
1721
1722impl InsertElement {
1723    pub(crate) fn from_llvm_ref(expr: LLVMValueRef, ctx: &mut ModuleContext) -> Self {
1724        assert_eq!(unsafe { LLVMGetNumOperands(expr) }, 3);
1725        Self {
1726            vector: Constant::from_llvm_ref(unsafe { LLVMGetOperand(expr, 0) }, ctx),
1727            element: Constant::from_llvm_ref(unsafe { LLVMGetOperand(expr, 1) }, ctx),
1728            index: Constant::from_llvm_ref(unsafe { LLVMGetOperand(expr, 2) }, ctx),
1729        }
1730    }
1731}
1732
1733impl ShuffleVector {
1734    #[cfg(feature = "llvm-10-or-lower")]
1735    pub(crate) fn from_llvm_ref(expr: LLVMValueRef, ctx: &mut ModuleContext) -> Self {
1736        assert_eq!(unsafe { LLVMGetNumOperands(expr) }, 3);
1737        Self {
1738            operand0: Constant::from_llvm_ref(unsafe { LLVMGetOperand(expr, 0) }, ctx),
1739            operand1: Constant::from_llvm_ref(unsafe { LLVMGetOperand(expr, 1) }, ctx),
1740            mask: Constant::from_llvm_ref(unsafe { LLVMGetOperand(expr, 2) }, ctx),
1741        }
1742    }
1743    #[cfg(feature = "llvm-11-or-greater")]
1744    pub(crate) fn from_llvm_ref(expr: LLVMValueRef, _ctx: &mut ModuleContext) -> Self {
1745        assert_eq!(unsafe { LLVMGetNumOperands(expr) }, 2);
1746        // We currently (as of LLVM 11) have no way to get the mask of a
1747        // ShuffleVector constant expression; LLVMGetMaskValue() only works for
1748        // ShuffleVector instructions, not ShuffleVector constant expressions
1749        panic!("Encountered a Constant::ShuffleVector, which is not supported for LLVM 11+")
1750    }
1751}
1752
1753#[cfg(feature = "llvm-14-or-lower")]
1754impl ExtractValue {
1755    pub(crate) fn from_llvm_ref(expr: LLVMValueRef, ctx: &mut ModuleContext) -> Self {
1756        assert_eq!(unsafe { LLVMGetNumOperands(expr) }, 2);
1757        Self {
1758            aggregate: Constant::from_llvm_ref(unsafe { LLVMGetOperand(expr, 0) }, ctx),
1759            indices: unsafe {
1760                let num_indices = LLVMGetNumIndices(expr);
1761                let ptr = LLVMGetIndices(expr);
1762                std::slice::from_raw_parts(ptr, num_indices as usize).to_vec()
1763            },
1764        }
1765    }
1766}
1767
1768#[cfg(feature = "llvm-14-or-lower")]
1769impl InsertValue {
1770    pub(crate) fn from_llvm_ref(expr: LLVMValueRef, ctx: &mut ModuleContext) -> Self {
1771        assert_eq!(unsafe { LLVMGetNumOperands(expr) }, 3);
1772        Self {
1773            aggregate: Constant::from_llvm_ref(unsafe { LLVMGetOperand(expr, 0) }, ctx),
1774            element: Constant::from_llvm_ref(unsafe { LLVMGetOperand(expr, 1) }, ctx),
1775            indices: unsafe {
1776                let num_indices = LLVMGetNumIndices(expr);
1777                let ptr = LLVMGetIndices(expr);
1778                std::slice::from_raw_parts(ptr, num_indices as usize).to_vec()
1779            },
1780        }
1781    }
1782}
1783
1784impl GetElementPtr {
1785    pub(crate) fn from_llvm_ref(expr: LLVMValueRef, ctx: &mut ModuleContext) -> Self {
1786        Self {
1787            address: Constant::from_llvm_ref(unsafe { LLVMGetOperand(expr, 0) }, ctx),
1788            indices: {
1789                let num_indices = unsafe { LLVMGetNumOperands(expr) as u32 } - 1; // LLVMGetNumIndices(), which we use for instruction::GetElementPtr, appears empirically to not work for constant::GetElementPtr
1790                (1 ..= num_indices)
1791                    .map(|i| Constant::from_llvm_ref(unsafe { LLVMGetOperand(expr, i) }, ctx))
1792                    .collect()
1793            },
1794            in_bounds: unsafe { LLVMIsInBounds(expr) } != 0,
1795        }
1796    }
1797}
1798
1799// These constexprs have the property that their result type is ambiguous from
1800//   knowing only their operands.
1801macro_rules! typed_unop_from_llvm {
1802    ($expr:ident) => {
1803        impl $expr {
1804            pub(crate) fn from_llvm_ref(expr: LLVMValueRef, ctx: &mut ModuleContext) -> Self {
1805                assert_eq!(unsafe { LLVMGetNumOperands(expr) }, 1);
1806                Self {
1807                    operand: Constant::from_llvm_ref(unsafe { LLVMGetOperand(expr, 0) }, ctx),
1808                    to_type: ctx.types.type_from_llvm_ref(unsafe { LLVMTypeOf(expr) }),
1809                }
1810            }
1811        }
1812    };
1813}
1814
1815typed_unop_from_llvm!(Trunc);
1816#[cfg(feature = "llvm-17-or-lower")]
1817typed_unop_from_llvm!(ZExt);
1818#[cfg(feature = "llvm-17-or-lower")]
1819typed_unop_from_llvm!(SExt);
1820#[cfg(feature = "llvm-17-or-lower")]
1821typed_unop_from_llvm!(FPTrunc);
1822#[cfg(feature = "llvm-17-or-lower")]
1823typed_unop_from_llvm!(FPExt);
1824#[cfg(feature = "llvm-17-or-lower")]
1825typed_unop_from_llvm!(FPToUI);
1826#[cfg(feature = "llvm-17-or-lower")]
1827typed_unop_from_llvm!(FPToSI);
1828#[cfg(feature = "llvm-17-or-lower")]
1829typed_unop_from_llvm!(UIToFP);
1830#[cfg(feature = "llvm-17-or-lower")]
1831typed_unop_from_llvm!(SIToFP);
1832typed_unop_from_llvm!(PtrToInt);
1833typed_unop_from_llvm!(IntToPtr);
1834typed_unop_from_llvm!(BitCast);
1835typed_unop_from_llvm!(AddrSpaceCast);
1836
1837#[cfg(feature = "llvm-18-or-lower")]
1838impl ICmp {
1839    pub(crate) fn from_llvm_ref(expr: LLVMValueRef, ctx: &mut ModuleContext) -> Self {
1840        assert_eq!(unsafe { LLVMGetNumOperands(expr) }, 2);
1841        Self {
1842            predicate: IntPredicate::from_llvm(unsafe { LLVMGetICmpPredicate(expr) }),
1843            operand0: Constant::from_llvm_ref(unsafe { LLVMGetOperand(expr, 0) }, ctx),
1844            operand1: Constant::from_llvm_ref(unsafe { LLVMGetOperand(expr, 1) }, ctx),
1845        }
1846    }
1847}
1848
1849#[cfg(feature = "llvm-18-or-lower")]
1850impl FCmp {
1851    pub(crate) fn from_llvm_ref(expr: LLVMValueRef, ctx: &mut ModuleContext) -> Self {
1852        assert_eq!(unsafe { LLVMGetNumOperands(expr) }, 2);
1853        Self {
1854            predicate: FPPredicate::from_llvm(unsafe { LLVMGetFCmpPredicate(expr) }),
1855            operand0: Constant::from_llvm_ref(unsafe { LLVMGetOperand(expr, 0) }, ctx),
1856            operand1: Constant::from_llvm_ref(unsafe { LLVMGetOperand(expr, 1) }, ctx),
1857        }
1858    }
1859}
1860
1861#[cfg(feature="llvm-16-or-lower")]
1862impl Select {
1863    pub(crate) fn from_llvm_ref(expr: LLVMValueRef, ctx: &mut ModuleContext) -> Self {
1864        assert_eq!(unsafe { LLVMGetNumOperands(expr) }, 3);
1865        Self {
1866            condition: Constant::from_llvm_ref(unsafe { LLVMGetOperand(expr, 0) }, ctx),
1867            true_value: Constant::from_llvm_ref(unsafe { LLVMGetOperand(expr, 1) }, ctx),
1868            false_value: Constant::from_llvm_ref(unsafe { LLVMGetOperand(expr, 2) }, ctx),
1869        }
1870    }
1871}