Skip to main content

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}