inkwell_llvm12/values/
basic_value_use.rs

1use either::{
2    Either,
3    Either::{Left, Right},
4};
5use llvm_sys::core::{
6    LLVMGetNextUse, LLVMGetUsedValue, LLVMGetUser, LLVMIsABasicBlock, LLVMValueAsBasicBlock,
7};
8use llvm_sys::prelude::LLVMUseRef;
9
10use std::marker::PhantomData;
11
12use crate::basic_block::BasicBlock;
13use crate::values::{AnyValueEnum, BasicValueEnum};
14
15/// A usage of a `BasicValue` in another value.
16#[derive(Clone, Copy, Debug, Eq, PartialEq)]
17pub struct BasicValueUse<'ctx>(LLVMUseRef, PhantomData<&'ctx ()>);
18
19impl<'ctx> BasicValueUse<'ctx> {
20    pub(crate) unsafe fn new(use_: LLVMUseRef) -> Self {
21        debug_assert!(!use_.is_null());
22
23        BasicValueUse(use_, PhantomData)
24    }
25
26    /// Gets the next use of a `BasicBlock`, `InstructionValue` or `BasicValue` if any.
27    ///
28    /// The following example,
29    ///
30    /// ```no_run
31    /// use inkwell::AddressSpace;
32    /// use inkwell::context::Context;
33    /// use inkwell::values::BasicValue;
34    ///
35    /// let context = Context::create();
36    /// let module = context.create_module("ivs");
37    /// let builder = context.create_builder();
38    /// let void_type = context.void_type();
39    /// let f32_type = context.f32_type();
40    /// let f32_ptr_type = f32_type.ptr_type(AddressSpace::Generic);
41    /// let fn_type = void_type.fn_type(&[f32_ptr_type.into()], false);
42    ///
43    /// let function = module.add_function("take_f32_ptr", fn_type, None);
44    /// let basic_block = context.append_basic_block(function, "entry");
45    ///
46    /// builder.position_at_end(basic_block);
47    ///
48    /// let arg1 = function.get_first_param().unwrap().into_pointer_value();
49    /// let f32_val = f32_type.const_float(::std::f64::consts::PI);
50    /// let store_instruction = builder.build_store(arg1, f32_val);
51    /// let free_instruction = builder.build_free(arg1);
52    /// let return_instruction = builder.build_return(None);
53    ///
54    /// let arg1_first_use = arg1.get_first_use().unwrap();
55    ///
56    /// assert!(arg1_first_use.get_next_use().is_some());
57    /// ```
58    ///
59    /// will generate LLVM IR roughly like (varying slightly across LLVM versions):
60    ///
61    /// ```ir
62    /// ; ModuleID = 'ivs'
63    /// source_filename = "ivs"
64    ///
65    /// define void @take_f32_ptr(float* %0) {
66    /// entry:
67    ///   store float 0x400921FB60000000, float* %0
68    ///   %1 = bitcast float* %0 to i8*
69    ///   tail call void @free(i8* %1)
70    ///   ret void
71    /// }
72    ///
73    /// declare void @free(i8*)
74    /// ```
75    ///
76    /// which makes the arg1 (%0) uses clear:
77    /// 1) In the store instruction
78    /// 2) In the pointer bitcast
79    pub fn get_next_use(self) -> Option<Self> {
80        let use_ = unsafe { LLVMGetNextUse(self.0) };
81
82        if use_.is_null() {
83            return None;
84        }
85
86        unsafe { Some(Self::new(use_)) }
87    }
88
89    /// Gets the user (an `AnyValueEnum`) of this use.
90    ///
91    /// ```no_run
92    /// use inkwell::AddressSpace;
93    /// use inkwell::context::Context;
94    /// use inkwell::values::BasicValue;
95    ///
96    /// let context = Context::create();
97    /// let module = context.create_module("ivs");
98    /// let builder = context.create_builder();
99    /// let void_type = context.void_type();
100    /// let f32_type = context.f32_type();
101    /// let f32_ptr_type = f32_type.ptr_type(AddressSpace::Generic);
102    /// let fn_type = void_type.fn_type(&[f32_ptr_type.into()], false);
103    ///
104    /// let function = module.add_function("take_f32_ptr", fn_type, None);
105    /// let basic_block = context.append_basic_block(function, "entry");
106    ///
107    /// builder.position_at_end(basic_block);
108    ///
109    /// let arg1 = function.get_first_param().unwrap().into_pointer_value();
110    /// let f32_val = f32_type.const_float(::std::f64::consts::PI);
111    /// let store_instruction = builder.build_store(arg1, f32_val);
112    /// let free_instruction = builder.build_free(arg1);
113    /// let return_instruction = builder.build_return(None);
114    ///
115    /// let store_operand_use0 = store_instruction.get_operand_use(0).unwrap();
116    /// let store_operand_use1 = store_instruction.get_operand_use(1).unwrap();
117    ///
118    /// assert_eq!(store_operand_use0.get_user(), store_instruction);
119    /// assert_eq!(store_operand_use1.get_user(), store_instruction);
120    /// ```
121    pub fn get_user(self) -> AnyValueEnum<'ctx> {
122        unsafe { AnyValueEnum::new(LLVMGetUser(self.0)) }
123    }
124
125    /// Gets the used value (a `BasicValueEnum` or `BasicBlock`) of this use.
126    ///
127    /// ```no_run
128    /// use inkwell::AddressSpace;
129    /// use inkwell::context::Context;
130    /// use inkwell::values::BasicValue;
131    ///
132    /// let context = Context::create();
133    /// let module = context.create_module("ivs");
134    /// let builder = context.create_builder();
135    /// let void_type = context.void_type();
136    /// let f32_type = context.f32_type();
137    /// let f32_ptr_type = f32_type.ptr_type(AddressSpace::Generic);
138    /// let fn_type = void_type.fn_type(&[f32_ptr_type.into()], false);
139    ///
140    /// let function = module.add_function("take_f32_ptr", fn_type, None);
141    /// let basic_block = context.append_basic_block(function, "entry");
142    ///
143    /// builder.position_at_end(basic_block);
144    ///
145    /// let arg1 = function.get_first_param().unwrap().into_pointer_value();
146    /// let f32_val = f32_type.const_float(::std::f64::consts::PI);
147    /// let store_instruction = builder.build_store(arg1, f32_val);
148    /// let free_instruction = builder.build_free(arg1);
149    /// let return_instruction = builder.build_return(None);
150    ///
151    /// let free_operand0 = free_instruction.get_operand(0).unwrap().left().unwrap();
152    /// let free_operand0_instruction = free_operand0.as_instruction_value().unwrap();
153    /// let bitcast_use_value = free_operand0_instruction
154    ///     .get_first_use()
155    ///     .unwrap()
156    ///     .get_used_value()
157    ///     .left()
158    ///     .unwrap();
159    ///
160    /// assert_eq!(bitcast_use_value, free_operand0);
161    /// ```
162    pub fn get_used_value(self) -> Either<BasicValueEnum<'ctx>, BasicBlock<'ctx>> {
163        let used_value = unsafe { LLVMGetUsedValue(self.0) };
164
165        let is_basic_block = unsafe { !LLVMIsABasicBlock(used_value).is_null() };
166
167        if is_basic_block {
168            let bb = unsafe { BasicBlock::new(LLVMValueAsBasicBlock(used_value)) };
169
170            Right(bb.expect("BasicBlock should always be valid"))
171        } else {
172            unsafe { Left(BasicValueEnum::new(used_value)) }
173        }
174    }
175}