llvm_plugin_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(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 pub fn get_name(&self) -> &CStr {
68 self.phi_value.get_name()
69 }
70
71 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 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}