llvm_ir/
operand.rs

1use crate::types::{TypeRef, Typed, Types};
2use crate::{ConstantRef, Name};
3use std::fmt::{self, Display};
4
5#[derive(PartialEq, Clone, Debug, Hash)]
6pub enum Operand {
7    /// e.g., `i32 %foo`
8    LocalOperand {
9        name: Name,
10        ty: TypeRef,
11    },
12    /// includes [`GlobalReference`](../constant/enum.Constant.html#variant.GlobalReference) for things like `@foo`
13    ConstantOperand(ConstantRef),
14    MetadataOperand, // --TODO not yet implemented-- MetadataOperand(Box<Metadata>),
15}
16
17impl Typed for Operand {
18    fn get_type(&self, types: &Types) -> TypeRef {
19        match self {
20            Operand::LocalOperand { ty, .. } => ty.clone(),
21            Operand::ConstantOperand(c) => types.type_of(c),
22            Operand::MetadataOperand => types.metadata_type(),
23        }
24    }
25}
26
27impl Operand {
28    /// Get a reference to the `Constant`, if the operand is a constant;
29    /// otherwise, returns `None`.
30    ///
31    /// This allows nested matching on `Operand`. Instead of the following code
32    /// (which doesn't compile because you can't directly match on `ConstantRef`)
33    /// ```ignore
34    /// if let Operand::ConstantOperand(Constant::Float(Float::Double(val))) = op
35    /// ```
36    /// you can write this:
37    /// ```ignore
38    /// if let Some(Constant::Float(Float::Double(val))) = op.as_constant()
39    /// ```
40    pub fn as_constant(&self) -> Option<&Constant> {
41        match self {
42            Operand::ConstantOperand(cref) => Some(cref),
43            _ => None,
44        }
45    }
46}
47
48impl Display for Operand {
49    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
50        match self {
51            Operand::LocalOperand { name, ty } => write!(f, "{} {}", ty, name),
52            Operand::ConstantOperand(cref) => write!(f, "{}", &cref),
53            Operand::MetadataOperand => write!(f, "<metadata>"),
54        }
55    }
56}
57
58// ********* //
59// from_llvm //
60// ********* //
61
62use crate::constant::Constant;
63use crate::function::FunctionContext;
64use crate::llvm_sys::*;
65use crate::module::ModuleContext;
66use llvm_sys::LLVMValueKind;
67
68impl Operand {
69    pub(crate) fn from_llvm_ref(
70        operand: LLVMValueRef,
71        ctx: &mut ModuleContext,
72        func_ctx: &FunctionContext,
73    ) -> Self {
74        let constant = unsafe { LLVMIsAConstant(operand) };
75        if !constant.is_null() {
76            Operand::ConstantOperand(Constant::from_llvm_ref(constant, ctx))
77        } else if unsafe {
78            LLVMGetValueKind(operand) == LLVMValueKind::LLVMMetadataAsValueValueKind
79        } {
80            Operand::MetadataOperand
81        } else {
82            Operand::LocalOperand {
83                name: func_ctx.val_names
84                    .get(&operand)
85                    .unwrap_or_else(|| {
86                        let names: Vec<_> = func_ctx.val_names.values().collect();
87                        let kind = unsafe { LLVMGetValueKind(operand) };
88                        panic!(
89                            "Failed to find operand with kind {:?} in func_ctx.val_names; have names {:?}",
90                            kind, names
91                        )
92                    })
93                    .clone(),
94                ty: ctx.types.type_from_llvm_ref(unsafe { LLVMTypeOf(operand) }),
95            }
96        }
97    }
98}