inkwell/values/basic_value_use.rs
1use llvm_sys::core::{LLVMGetNextUse, LLVMGetUsedValue, LLVMGetUser, LLVMIsABasicBlock, LLVMValueAsBasicBlock};
2use llvm_sys::prelude::LLVMUseRef;
3
4use std::marker::PhantomData;
5
6use crate::basic_block::BasicBlock;
7use crate::values::{AnyValueEnum, BasicValueEnum};
8
9/// Either [BasicValueEnum] or [BasicBlock].
10#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
11pub enum Operand<'ctx> {
12 /// Represents a [BasicValueEnum].
13 Value(BasicValueEnum<'ctx>),
14 /// Represents a [BasicBlock].
15 Block(BasicBlock<'ctx>),
16}
17
18impl<'ctx> Operand<'ctx> {
19 /// Determines if the [Operand] is a [BasicValueEnum].
20 #[inline]
21 #[must_use]
22 pub fn is_value(self) -> bool {
23 matches!(self, Self::Value(_))
24 }
25
26 /// Determines if the [Operand] is a [BasicBlock].
27 #[inline]
28 #[must_use]
29 pub fn is_block(self) -> bool {
30 matches!(self, Self::Block(_))
31 }
32
33 /// If the [Operand] is a [BasicValueEnum], map it into [Option::Some].
34 #[inline]
35 #[must_use]
36 pub fn value(self) -> Option<BasicValueEnum<'ctx>> {
37 match self {
38 Self::Value(value) => Some(value),
39 _ => None,
40 }
41 }
42
43 /// If the [Operand] is a [BasicBlock], map it into [Option::Some].
44 #[inline]
45 #[must_use]
46 pub fn block(self) -> Option<BasicBlock<'ctx>> {
47 match self {
48 Self::Block(block) => Some(block),
49 _ => None,
50 }
51 }
52
53 /// Expect [BasicValueEnum], panic with the message if it is not.
54 #[inline]
55 #[must_use]
56 #[track_caller]
57 pub fn expect_value(self, msg: &str) -> BasicValueEnum<'ctx> {
58 match self {
59 Self::Value(value) => value,
60 _ => panic!("{msg}"),
61 }
62 }
63
64 /// Expect [BasicBlock], panic with the message if it is not.
65 #[inline]
66 #[must_use]
67 #[track_caller]
68 pub fn expect_block(self, msg: &str) -> BasicBlock<'ctx> {
69 match self {
70 Self::Block(block) => block,
71 _ => panic!("{msg}"),
72 }
73 }
74
75 /// Unwrap [BasicValueEnum]. Will panic if it is not.
76 #[inline]
77 #[must_use]
78 #[track_caller]
79 pub fn unwrap_value(self) -> BasicValueEnum<'ctx> {
80 self.expect_value("Called unwrap_value() on UsedValue::Block.")
81 }
82
83 /// Unwrap [BasicBlock]. Will panic if it is not.
84 #[inline]
85 #[must_use]
86 #[track_caller]
87 pub fn unwrap_block(self) -> BasicBlock<'ctx> {
88 self.expect_block("Called unwrap_block() on UsedValue::Value.")
89 }
90}
91
92/// A usage of a `BasicValue` in another value.
93#[derive(Clone, Copy, Debug, Eq, PartialEq)]
94pub struct BasicValueUse<'ctx>(LLVMUseRef, PhantomData<&'ctx ()>);
95
96impl<'ctx> BasicValueUse<'ctx> {
97 /// Get a value from an [LLVMUseRef].
98 ///
99 /// # Safety
100 ///
101 /// The ref must be valid and of type basic value.
102 pub unsafe fn new(use_: LLVMUseRef) -> Self {
103 debug_assert!(!use_.is_null());
104
105 BasicValueUse(use_, PhantomData)
106 }
107
108 /// Gets the next use of a `BasicBlock`, `InstructionValue` or `BasicValue` if any.
109 ///
110 /// The following example,
111 ///
112 /// ```no_run
113 /// use inkwell::AddressSpace;
114 /// use inkwell::context::Context;
115 /// use inkwell::values::BasicValue;
116 ///
117 /// let context = Context::create();
118 /// let module = context.create_module("ivs");
119 /// let builder = context.create_builder();
120 /// let void_type = context.void_type();
121 /// let f32_type = context.f32_type();
122 /// #[cfg(feature = "typed-pointers")]
123 /// let f32_ptr_type = f32_type.ptr_type(AddressSpace::default());
124 /// #[cfg(not(feature = "typed-pointers"))]
125 /// let f32_ptr_type = context.ptr_type(AddressSpace::default());
126 /// let fn_type = void_type.fn_type(&[f32_ptr_type.into()], false);
127 ///
128 /// let function = module.add_function("take_f32_ptr", fn_type, None);
129 /// let basic_block = context.append_basic_block(function, "entry");
130 ///
131 /// builder.position_at_end(basic_block);
132 ///
133 /// let arg1 = function.get_first_param().unwrap().into_pointer_value();
134 /// let f32_val = f32_type.const_float(std::f64::consts::PI);
135 /// let store_instruction = builder.build_store(arg1, f32_val).unwrap();
136 /// let free_instruction = builder.build_free(arg1).unwrap();
137 /// let return_instruction = builder.build_return(None).unwrap();
138 ///
139 /// let arg1_first_use = arg1.get_first_use().unwrap();
140 ///
141 /// assert!(arg1_first_use.get_next_use().is_some());
142 /// ```
143 ///
144 /// will generate LLVM IR roughly like (varying slightly across LLVM versions):
145 ///
146 /// ```ir
147 /// ; ModuleID = 'ivs'
148 /// source_filename = "ivs"
149 ///
150 /// define void @take_f32_ptr(float* %0) {
151 /// entry:
152 /// store float 0x400921FB60000000, float* %0
153 /// %1 = bitcast float* %0 to i8*
154 /// tail call void @free(i8* %1)
155 /// ret void
156 /// }
157 ///
158 /// declare void @free(i8*)
159 /// ```
160 ///
161 /// which makes the arg1 (%0) uses clear:
162 /// 1) In the store instruction
163 /// 2) In the pointer bitcast
164 pub fn get_next_use(self) -> Option<Self> {
165 let use_ = unsafe { LLVMGetNextUse(self.0) };
166
167 if use_.is_null() {
168 return None;
169 }
170
171 unsafe { Some(Self::new(use_)) }
172 }
173
174 /// Gets the user (an `AnyValueEnum`) of this use.
175 ///
176 /// ```no_run
177 /// use inkwell::AddressSpace;
178 /// use inkwell::context::Context;
179 /// use inkwell::values::BasicValue;
180 ///
181 /// let context = Context::create();
182 /// let module = context.create_module("ivs");
183 /// let builder = context.create_builder();
184 /// let void_type = context.void_type();
185 /// let f32_type = context.f32_type();
186 /// #[cfg(feature = "typed-pointers")]
187 /// let f32_ptr_type = f32_type.ptr_type(AddressSpace::default());
188 /// #[cfg(not(feature = "typed-pointers"))]
189 /// let f32_ptr_type = context.ptr_type(AddressSpace::default());
190 /// let fn_type = void_type.fn_type(&[f32_ptr_type.into()], false);
191 ///
192 /// let function = module.add_function("take_f32_ptr", fn_type, None);
193 /// let basic_block = context.append_basic_block(function, "entry");
194 ///
195 /// builder.position_at_end(basic_block);
196 ///
197 /// let arg1 = function.get_first_param().unwrap().into_pointer_value();
198 /// let f32_val = f32_type.const_float(std::f64::consts::PI);
199 /// let store_instruction = builder.build_store(arg1, f32_val).unwrap();
200 /// let free_instruction = builder.build_free(arg1).unwrap();
201 /// let return_instruction = builder.build_return(None).unwrap();
202 ///
203 /// let store_operand_use0 = store_instruction.get_operand_use(0).unwrap();
204 /// let store_operand_use1 = store_instruction.get_operand_use(1).unwrap();
205 ///
206 /// assert_eq!(store_operand_use0.get_user(), store_instruction);
207 /// assert_eq!(store_operand_use1.get_user(), store_instruction);
208 /// ```
209 pub fn get_user(self) -> AnyValueEnum<'ctx> {
210 unsafe { AnyValueEnum::new(LLVMGetUser(self.0)) }
211 }
212
213 /// Gets the used value (a `BasicValueEnum` or `BasicBlock`) of this use.
214 ///
215 /// ```no_run
216 /// use inkwell::AddressSpace;
217 /// use inkwell::context::Context;
218 /// use inkwell::values::BasicValue;
219 ///
220 /// let context = Context::create();
221 /// let module = context.create_module("ivs");
222 /// let builder = context.create_builder();
223 /// let void_type = context.void_type();
224 /// let f32_type = context.f32_type();
225 /// #[cfg(feature = "typed-pointers")]
226 /// let f32_ptr_type = f32_type.ptr_type(AddressSpace::default());
227 /// #[cfg(not(feature = "typed-pointers"))]
228 /// let f32_ptr_type = context.ptr_type(AddressSpace::default());
229 /// let fn_type = void_type.fn_type(&[f32_ptr_type.into()], false);
230 ///
231 /// let function = module.add_function("take_f32_ptr", fn_type, None);
232 /// let basic_block = context.append_basic_block(function, "entry");
233 ///
234 /// builder.position_at_end(basic_block);
235 ///
236 /// let arg1 = function.get_first_param().unwrap().into_pointer_value();
237 /// let f32_val = f32_type.const_float(std::f64::consts::PI);
238 /// let store_instruction = builder.build_store(arg1, f32_val).unwrap();
239 /// let free_instruction = builder.build_free(arg1).unwrap();
240 /// let return_instruction = builder.build_return(None).unwrap();
241 ///
242 /// let free_operand0 = free_instruction.get_operand(0).unwrap().unwrap_value();
243 /// let free_operand0_instruction = free_operand0.as_instruction_value().unwrap();
244 /// let bitcast_use_value = free_operand0_instruction
245 /// .get_first_use()
246 /// .unwrap()
247 /// .get_used_value()
248 /// .value()
249 /// .unwrap();
250 ///
251 /// assert_eq!(bitcast_use_value, free_operand0);
252 /// ```
253 pub fn get_used_value(self) -> Operand<'ctx> {
254 let used_value = unsafe { LLVMGetUsedValue(self.0) };
255
256 let is_basic_block = unsafe { !LLVMIsABasicBlock(used_value).is_null() };
257
258 if is_basic_block {
259 let bb = unsafe { BasicBlock::new(LLVMValueAsBasicBlock(used_value)) };
260
261 Operand::Block(bb.expect("BasicBlock should always be valid"))
262 } else {
263 unsafe { Operand::Value(BasicValueEnum::new(used_value)) }
264 }
265 }
266}