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}