llvm_plugin_inkwell/values/
phi_value.rs

1use llvm_sys::core::{LLVMAddIncoming, LLVMCountIncoming, LLVMGetIncomingBlock, LLVMGetIncomingValue};
2use llvm_sys::prelude::{LLVMBasicBlockRef, LLVMValueRef};
3use std::convert::TryFrom;
4
5use std::ffi::CStr;
6use std::fmt::{self, Display};
7
8use crate::basic_block::BasicBlock;
9use crate::values::traits::AsValueRef;
10use crate::values::{BasicValue, BasicValueEnum, InstructionOpcode, InstructionValue, Value};
11
12use super::AnyValue;
13
14// REVIEW: Metadata for phi values?
15/// A Phi Instruction returns a value based on which basic block branched into
16/// the Phi's containing basic block.
17#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
18pub struct PhiValue<'ctx> {
19    phi_value: Value<'ctx>,
20}
21
22impl<'ctx> PhiValue<'ctx> {
23    pub(crate) unsafe fn new(value: LLVMValueRef) -> Self {
24        assert!(!value.is_null());
25
26        PhiValue {
27            phi_value: Value::new(value),
28        }
29    }
30
31    pub fn add_incoming(self, incoming: &[(&dyn BasicValue<'ctx>, BasicBlock<'ctx>)]) {
32        let (mut values, mut basic_blocks): (Vec<LLVMValueRef>, Vec<LLVMBasicBlockRef>) = {
33            incoming
34                .iter()
35                .map(|&(v, bb)| (v.as_value_ref(), bb.basic_block))
36                .unzip()
37        };
38
39        unsafe {
40            LLVMAddIncoming(
41                self.as_value_ref(),
42                values.as_mut_ptr(),
43                basic_blocks.as_mut_ptr(),
44                incoming.len() as u32,
45            );
46        }
47    }
48
49    pub fn count_incoming(self) -> u32 {
50        unsafe { LLVMCountIncoming(self.as_value_ref()) }
51    }
52
53    pub fn get_incoming(self, index: u32) -> Option<(BasicValueEnum<'ctx>, BasicBlock<'ctx>)> {
54        if index >= self.count_incoming() {
55            return None;
56        }
57
58        let basic_block =
59            unsafe { BasicBlock::new(LLVMGetIncomingBlock(self.as_value_ref(), index)).expect("Invalid BasicBlock") };
60        let value = unsafe { BasicValueEnum::new(LLVMGetIncomingValue(self.as_value_ref(), index)) };
61
62        Some((value, basic_block))
63    }
64
65    /// Gets the name of a `ArrayValue`. If the value is a constant, this will
66    /// return an empty string.
67    pub fn get_name(&self) -> &CStr {
68        self.phi_value.get_name()
69    }
70
71    // I believe PhiValue is never a constant, so this should always work
72    pub fn set_name(self, name: &str) {
73        self.phi_value.set_name(name);
74    }
75
76    pub fn is_null(self) -> bool {
77        self.phi_value.is_null()
78    }
79
80    pub fn is_undef(self) -> bool {
81        self.phi_value.is_undef()
82    }
83
84    // SubType: -> InstructionValue<Phi>
85    pub fn as_instruction(self) -> InstructionValue<'ctx> {
86        self.phi_value
87            .as_instruction()
88            .expect("PhiValue should always be a Phi InstructionValue")
89    }
90
91    pub fn replace_all_uses_with(self, other: &PhiValue<'ctx>) {
92        self.phi_value.replace_all_uses_with(other.as_value_ref())
93    }
94
95    pub fn as_basic_value(self) -> BasicValueEnum<'ctx> {
96        unsafe { BasicValueEnum::new(self.as_value_ref()) }
97    }
98}
99
100unsafe impl AsValueRef for PhiValue<'_> {
101    fn as_value_ref(&self) -> LLVMValueRef {
102        self.phi_value.value
103    }
104}
105
106impl Display for PhiValue<'_> {
107    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
108        write!(f, "{}", self.print_to_string())
109    }
110}
111
112impl<'ctx> TryFrom<InstructionValue<'ctx>> for PhiValue<'ctx> {
113    type Error = ();
114
115    fn try_from(value: InstructionValue) -> Result<Self, Self::Error> {
116        if value.get_opcode() == InstructionOpcode::Phi {
117            unsafe { Ok(PhiValue::new(value.as_value_ref())) }
118        } else {
119            Err(())
120        }
121    }
122}