inkwell/values/
phi_value.rs1use 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#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
18pub struct PhiValue<'ctx> {
19 phi_value: Value<'ctx>,
20}
21
22impl<'ctx> PhiValue<'ctx> {
23 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 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 pub fn get_incomings(self) -> IncomingIter<'ctx> {
83 IncomingIter {
84 pv: self,
85 i: 0,
86 count: self.count_incoming(),
87 }
88 }
89
90 pub fn get_name(&self) -> &CStr {
93 self.phi_value.get_name()
94 }
95
96 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 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#[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}