Skip to main content

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    /// Get a value from an [LLVMValueRef].
24    ///
25    /// # Safety
26    ///
27    /// The ref must be valid and of type phi.
28    pub unsafe fn new(value: LLVMValueRef) -> Self {
29        assert!(!value.is_null());
30
31        PhiValue {
32            phi_value: Value::new(value),
33        }
34    }
35
36    pub fn add_incoming(self, incoming: &[(&dyn BasicValue<'ctx>, BasicBlock<'ctx>)]) {
37        let (mut values, mut basic_blocks): (Vec<LLVMValueRef>, Vec<LLVMBasicBlockRef>) = {
38            incoming
39                .iter()
40                .map(|&(v, bb)| (v.as_value_ref(), bb.basic_block))
41                .unzip()
42        };
43
44        unsafe {
45            LLVMAddIncoming(
46                self.as_value_ref(),
47                values.as_mut_ptr(),
48                basic_blocks.as_mut_ptr(),
49                incoming.len() as u32,
50            );
51        }
52    }
53
54    pub fn count_incoming(self) -> u32 {
55        unsafe { LLVMCountIncoming(self.as_value_ref()) }
56    }
57
58    pub fn get_incoming(self, index: u32) -> Option<(BasicValueEnum<'ctx>, BasicBlock<'ctx>)> {
59        if index >= self.count_incoming() {
60            return None;
61        }
62
63        let basic_block =
64            unsafe { BasicBlock::new(LLVMGetIncomingBlock(self.as_value_ref(), index)).expect("Invalid BasicBlock") };
65        let value = unsafe { BasicValueEnum::new(LLVMGetIncomingValue(self.as_value_ref(), index)) };
66
67        Some((value, basic_block))
68    }
69
70    /// # Safety
71    ///
72    /// The index must be smaller [PhiValue::count_incoming].
73    pub unsafe fn get_incoming_unchecked(self, index: u32) -> (BasicValueEnum<'ctx>, BasicBlock<'ctx>) {
74        let basic_block =
75            unsafe { BasicBlock::new(LLVMGetIncomingBlock(self.as_value_ref(), index)).expect("Invalid BasicBlock") };
76        let value = unsafe { BasicValueEnum::new(LLVMGetIncomingValue(self.as_value_ref(), index)) };
77
78        (value, basic_block)
79    }
80
81    /// Get an incoming edge iterator.
82    pub fn get_incomings(self) -> IncomingIter<'ctx> {
83        IncomingIter {
84            pv: self,
85            i: 0,
86            count: self.count_incoming(),
87        }
88    }
89
90    /// Gets the name of a `ArrayValue`. If the value is a constant, this will
91    /// return an empty string.
92    pub fn get_name(&self) -> &CStr {
93        self.phi_value.get_name()
94    }
95
96    // I believe PhiValue is never a constant, so this should always work
97    pub fn set_name(self, name: &str) {
98        self.phi_value.set_name(name);
99    }
100
101    pub fn is_null(self) -> bool {
102        self.phi_value.is_null()
103    }
104
105    pub fn is_undef(self) -> bool {
106        self.phi_value.is_undef()
107    }
108
109    // SubType: -> InstructionValue<Phi>
110    pub fn as_instruction(self) -> InstructionValue<'ctx> {
111        self.phi_value
112            .as_instruction()
113            .expect("PhiValue should always be a Phi InstructionValue")
114    }
115
116    pub fn replace_all_uses_with(self, other: &PhiValue<'ctx>) {
117        self.phi_value.replace_all_uses_with(other.as_value_ref())
118    }
119
120    pub fn as_basic_value(self) -> BasicValueEnum<'ctx> {
121        unsafe { BasicValueEnum::new(self.as_value_ref()) }
122    }
123}
124
125unsafe impl AsValueRef for PhiValue<'_> {
126    fn as_value_ref(&self) -> LLVMValueRef {
127        self.phi_value.value
128    }
129}
130
131impl Display for PhiValue<'_> {
132    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
133        write!(f, "{}", self.print_to_string())
134    }
135}
136
137impl<'ctx> TryFrom<InstructionValue<'ctx>> for PhiValue<'ctx> {
138    type Error = ();
139
140    fn try_from(value: InstructionValue) -> Result<Self, Self::Error> {
141        if value.get_opcode() == InstructionOpcode::Phi {
142            unsafe { Ok(PhiValue::new(value.as_value_ref())) }
143        } else {
144            Err(())
145        }
146    }
147}
148
149/// Iterate over all the incoming edges of a phi value.
150#[derive(Debug)]
151pub struct IncomingIter<'ctx> {
152    pv: PhiValue<'ctx>,
153    i: u32,
154    count: u32,
155}
156
157impl<'ctx> Iterator for IncomingIter<'ctx> {
158    type Item = (BasicValueEnum<'ctx>, BasicBlock<'ctx>);
159
160    fn next(&mut self) -> Option<Self::Item> {
161        if self.i < self.count {
162            let result = unsafe { self.pv.get_incoming_unchecked(self.i) };
163            self.i += 1;
164            Some(result)
165        } else {
166            None
167        }
168    }
169}