/rust/registry/src/index.crates.io-6f17d22bba15001f/inkwell-0.1.1/src/values/int_value.rs
Line | Count | Source (jump to first uncovered line) |
1 | | use llvm_sys::core::{ |
2 | | LLVMConstAShr, LLVMConstAdd, LLVMConstAnd, LLVMConstBitCast, LLVMConstICmp, LLVMConstIntCast, |
3 | | LLVMConstIntGetSExtValue, LLVMConstIntGetZExtValue, LLVMConstIntToPtr, LLVMConstLShr, LLVMConstMul, |
4 | | LLVMConstNSWAdd, LLVMConstNSWMul, LLVMConstNSWNeg, LLVMConstNSWSub, LLVMConstNUWAdd, LLVMConstNUWMul, |
5 | | LLVMConstNUWNeg, LLVMConstNUWSub, LLVMConstNeg, LLVMConstNot, LLVMConstOr, LLVMConstSExt, LLVMConstSExtOrBitCast, |
6 | | LLVMConstSIToFP, LLVMConstSelect, LLVMConstShl, LLVMConstSub, LLVMConstTrunc, LLVMConstTruncOrBitCast, |
7 | | LLVMConstUIToFP, LLVMConstXor, LLVMConstZExt, LLVMConstZExtOrBitCast, LLVMIsAConstantInt, |
8 | | }; |
9 | | use llvm_sys::prelude::LLVMValueRef; |
10 | | |
11 | | use std::convert::TryFrom; |
12 | | use std::ffi::CStr; |
13 | | use std::fmt::{self, Display}; |
14 | | |
15 | | use crate::types::{AsTypeRef, FloatType, IntType, PointerType}; |
16 | | use crate::values::traits::AsValueRef; |
17 | | use crate::values::{BasicValue, BasicValueEnum, FloatValue, InstructionValue, PointerValue, Value}; |
18 | | use crate::IntPredicate; |
19 | | |
20 | | use super::AnyValue; |
21 | | |
22 | | #[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)] |
23 | | pub struct IntValue<'ctx> { |
24 | | int_value: Value<'ctx>, |
25 | | } |
26 | | |
27 | | impl<'ctx> IntValue<'ctx> { |
28 | 11.8M | pub(crate) unsafe fn new(value: LLVMValueRef) -> Self { |
29 | 11.8M | assert!(!value.is_null()); |
30 | | |
31 | 11.8M | IntValue { |
32 | 11.8M | int_value: Value::new(value), |
33 | 11.8M | } |
34 | 11.8M | } |
35 | | |
36 | | /// Gets the name of an `IntValue`. If the value is a constant, this will |
37 | | /// return an empty string. |
38 | 0 | pub fn get_name(&self) -> &CStr { |
39 | 0 | self.int_value.get_name() |
40 | 0 | } |
41 | | |
42 | | /// Set name of the `IntValue`. |
43 | 0 | pub fn set_name(&self, name: &str) { |
44 | 0 | self.int_value.set_name(name) |
45 | 0 | } |
46 | | |
47 | 12.5k | pub fn get_type(self) -> IntType<'ctx> { |
48 | 12.5k | unsafe { IntType::new(self.int_value.get_type()) } |
49 | 12.5k | } |
50 | | |
51 | 0 | pub fn is_null(self) -> bool { |
52 | 0 | self.int_value.is_null() |
53 | 0 | } |
54 | | |
55 | 0 | pub fn is_undef(self) -> bool { |
56 | 0 | self.int_value.is_undef() |
57 | 0 | } |
58 | | |
59 | 0 | pub fn print_to_stderr(self) { |
60 | 0 | self.int_value.print_to_stderr() |
61 | 0 | } |
62 | | |
63 | 0 | pub fn as_instruction(self) -> Option<InstructionValue<'ctx>> { |
64 | 0 | self.int_value.as_instruction() |
65 | 0 | } |
66 | | |
67 | 0 | pub fn const_not(self) -> Self { |
68 | 0 | unsafe { IntValue::new(LLVMConstNot(self.as_value_ref())) } |
69 | 0 | } |
70 | | |
71 | | // REVIEW: What happens when not using a const value? This and other fns |
72 | 0 | pub fn const_neg(self) -> Self { |
73 | 0 | unsafe { IntValue::new(LLVMConstNeg(self.as_value_ref())) } |
74 | 0 | } |
75 | | |
76 | 0 | pub fn const_nsw_neg(self) -> Self { |
77 | 0 | unsafe { IntValue::new(LLVMConstNSWNeg(self.as_value_ref())) } |
78 | 0 | } |
79 | | |
80 | 0 | pub fn const_nuw_neg(self) -> Self { |
81 | 0 | unsafe { IntValue::new(LLVMConstNUWNeg(self.as_value_ref())) } |
82 | 0 | } |
83 | | |
84 | 0 | pub fn const_add(self, rhs: IntValue<'ctx>) -> Self { |
85 | 0 | unsafe { IntValue::new(LLVMConstAdd(self.as_value_ref(), rhs.as_value_ref())) } |
86 | 0 | } |
87 | | |
88 | 0 | pub fn const_nsw_add(self, rhs: IntValue<'ctx>) -> Self { |
89 | 0 | unsafe { IntValue::new(LLVMConstNSWAdd(self.as_value_ref(), rhs.as_value_ref())) } |
90 | 0 | } |
91 | | |
92 | 0 | pub fn const_nuw_add(self, rhs: IntValue<'ctx>) -> Self { |
93 | 0 | unsafe { IntValue::new(LLVMConstNUWAdd(self.as_value_ref(), rhs.as_value_ref())) } |
94 | 0 | } |
95 | | |
96 | 0 | pub fn const_sub(self, rhs: IntValue<'ctx>) -> Self { |
97 | 0 | unsafe { IntValue::new(LLVMConstSub(self.as_value_ref(), rhs.as_value_ref())) } |
98 | 0 | } |
99 | | |
100 | 0 | pub fn const_nsw_sub(self, rhs: IntValue<'ctx>) -> Self { |
101 | 0 | unsafe { IntValue::new(LLVMConstNSWSub(self.as_value_ref(), rhs.as_value_ref())) } |
102 | 0 | } |
103 | | |
104 | 0 | pub fn const_nuw_sub(self, rhs: IntValue<'ctx>) -> Self { |
105 | 0 | unsafe { IntValue::new(LLVMConstNUWSub(self.as_value_ref(), rhs.as_value_ref())) } |
106 | 0 | } |
107 | | |
108 | 0 | pub fn const_mul(self, rhs: IntValue<'ctx>) -> Self { |
109 | 0 | unsafe { IntValue::new(LLVMConstMul(self.as_value_ref(), rhs.as_value_ref())) } |
110 | 0 | } |
111 | | |
112 | 0 | pub fn const_nsw_mul(self, rhs: IntValue<'ctx>) -> Self { |
113 | 0 | unsafe { IntValue::new(LLVMConstNSWMul(self.as_value_ref(), rhs.as_value_ref())) } |
114 | 0 | } |
115 | | |
116 | 0 | pub fn const_nuw_mul(self, rhs: IntValue<'ctx>) -> Self { |
117 | 0 | unsafe { IntValue::new(LLVMConstNUWMul(self.as_value_ref(), rhs.as_value_ref())) } |
118 | 0 | } |
119 | | |
120 | | #[llvm_versions(4.0..=14.0)] |
121 | | pub fn const_unsigned_div(self, rhs: IntValue<'ctx>) -> Self { |
122 | | use llvm_sys::core::LLVMConstUDiv; |
123 | | |
124 | | unsafe { IntValue::new(LLVMConstUDiv(self.as_value_ref(), rhs.as_value_ref())) } |
125 | | } |
126 | | |
127 | | #[llvm_versions(4.0..=14.0)] |
128 | | pub fn const_signed_div(self, rhs: IntValue<'ctx>) -> Self { |
129 | | use llvm_sys::core::LLVMConstSDiv; |
130 | | |
131 | | unsafe { IntValue::new(LLVMConstSDiv(self.as_value_ref(), rhs.as_value_ref())) } |
132 | | } |
133 | | |
134 | | #[llvm_versions(4.0..=14.0)] |
135 | | pub fn const_exact_signed_div(self, rhs: IntValue<'ctx>) -> Self { |
136 | | use llvm_sys::core::LLVMConstExactSDiv; |
137 | | |
138 | | unsafe { IntValue::new(LLVMConstExactSDiv(self.as_value_ref(), rhs.as_value_ref())) } |
139 | | } |
140 | | |
141 | | #[llvm_versions(4.0..=14.0)] |
142 | | pub fn const_exact_unsigned_div(self, rhs: IntValue<'ctx>) -> Self { |
143 | | use llvm_sys::core::LLVMConstExactUDiv; |
144 | | |
145 | | unsafe { IntValue::new(LLVMConstExactUDiv(self.as_value_ref(), rhs.as_value_ref())) } |
146 | | } |
147 | | |
148 | | #[llvm_versions(4.0..=14.0)] |
149 | | pub fn const_unsigned_remainder(self, rhs: IntValue<'ctx>) -> Self { |
150 | | use llvm_sys::core::LLVMConstURem; |
151 | | |
152 | | unsafe { IntValue::new(LLVMConstURem(self.as_value_ref(), rhs.as_value_ref())) } |
153 | | } |
154 | | |
155 | | #[llvm_versions(4.0..=14.0)] |
156 | | pub fn const_signed_remainder(self, rhs: IntValue<'ctx>) -> Self { |
157 | | use llvm_sys::core::LLVMConstSRem; |
158 | | |
159 | | unsafe { IntValue::new(LLVMConstSRem(self.as_value_ref(), rhs.as_value_ref())) } |
160 | | } |
161 | | |
162 | 0 | pub fn const_and(self, rhs: IntValue<'ctx>) -> Self { |
163 | 0 | unsafe { IntValue::new(LLVMConstAnd(self.as_value_ref(), rhs.as_value_ref())) } |
164 | 0 | } |
165 | | |
166 | 0 | pub fn const_or(self, rhs: IntValue<'ctx>) -> Self { |
167 | 0 | unsafe { IntValue::new(LLVMConstOr(self.as_value_ref(), rhs.as_value_ref())) } |
168 | 0 | } |
169 | | |
170 | 0 | pub fn const_xor(self, rhs: IntValue<'ctx>) -> Self { |
171 | 0 | unsafe { IntValue::new(LLVMConstXor(self.as_value_ref(), rhs.as_value_ref())) } |
172 | 0 | } |
173 | | |
174 | | // TODO: Could infer is_signed from type (one day)? |
175 | 0 | pub fn const_cast(self, int_type: IntType<'ctx>, is_signed: bool) -> Self { |
176 | 0 | unsafe { |
177 | 0 | IntValue::new(LLVMConstIntCast( |
178 | 0 | self.as_value_ref(), |
179 | 0 | int_type.as_type_ref(), |
180 | 0 | is_signed as i32, |
181 | 0 | )) |
182 | 0 | } |
183 | 0 | } |
184 | | |
185 | | // TODO: Give shift methods more descriptive names |
186 | 0 | pub fn const_shl(self, rhs: IntValue<'ctx>) -> Self { |
187 | 0 | unsafe { IntValue::new(LLVMConstShl(self.as_value_ref(), rhs.as_value_ref())) } |
188 | 0 | } |
189 | | |
190 | 0 | pub fn const_rshr(self, rhs: IntValue<'ctx>) -> Self { |
191 | 0 | unsafe { IntValue::new(LLVMConstLShr(self.as_value_ref(), rhs.as_value_ref())) } |
192 | 0 | } |
193 | | |
194 | 0 | pub fn const_ashr(self, rhs: IntValue<'ctx>) -> Self { |
195 | 0 | unsafe { IntValue::new(LLVMConstAShr(self.as_value_ref(), rhs.as_value_ref())) } |
196 | 0 | } |
197 | | |
198 | | // SubType: const_to_float impl only for unsigned types |
199 | 0 | pub fn const_unsigned_to_float(self, float_type: FloatType<'ctx>) -> FloatValue<'ctx> { |
200 | 0 | unsafe { FloatValue::new(LLVMConstUIToFP(self.as_value_ref(), float_type.as_type_ref())) } |
201 | 0 | } |
202 | | |
203 | | // SubType: const_to_float impl only for signed types |
204 | 0 | pub fn const_signed_to_float(self, float_type: FloatType<'ctx>) -> FloatValue<'ctx> { |
205 | 0 | unsafe { FloatValue::new(LLVMConstSIToFP(self.as_value_ref(), float_type.as_type_ref())) } |
206 | 0 | } |
207 | | |
208 | 0 | pub fn const_to_pointer(self, ptr_type: PointerType<'ctx>) -> PointerValue<'ctx> { |
209 | 0 | unsafe { PointerValue::new(LLVMConstIntToPtr(self.as_value_ref(), ptr_type.as_type_ref())) } |
210 | 0 | } |
211 | | |
212 | 0 | pub fn const_truncate(self, int_type: IntType<'ctx>) -> IntValue<'ctx> { |
213 | 0 | unsafe { IntValue::new(LLVMConstTrunc(self.as_value_ref(), int_type.as_type_ref())) } |
214 | 0 | } |
215 | | |
216 | | // TODO: More descriptive name |
217 | 0 | pub fn const_s_extend(self, int_type: IntType<'ctx>) -> IntValue<'ctx> { |
218 | 0 | unsafe { IntValue::new(LLVMConstSExt(self.as_value_ref(), int_type.as_type_ref())) } |
219 | 0 | } |
220 | | |
221 | | // TODO: More descriptive name |
222 | 0 | pub fn const_z_ext(self, int_type: IntType<'ctx>) -> IntValue<'ctx> { |
223 | 0 | unsafe { IntValue::new(LLVMConstZExt(self.as_value_ref(), int_type.as_type_ref())) } |
224 | 0 | } |
225 | | |
226 | 0 | pub fn const_truncate_or_bit_cast(self, int_type: IntType<'ctx>) -> IntValue<'ctx> { |
227 | 0 | unsafe { IntValue::new(LLVMConstTruncOrBitCast(self.as_value_ref(), int_type.as_type_ref())) } |
228 | 0 | } |
229 | | |
230 | | // TODO: More descriptive name |
231 | 0 | pub fn const_s_extend_or_bit_cast(self, int_type: IntType<'ctx>) -> IntValue<'ctx> { |
232 | 0 | unsafe { IntValue::new(LLVMConstSExtOrBitCast(self.as_value_ref(), int_type.as_type_ref())) } |
233 | 0 | } |
234 | | |
235 | | // TODO: More descriptive name |
236 | 0 | pub fn const_z_ext_or_bit_cast(self, int_type: IntType<'ctx>) -> IntValue<'ctx> { |
237 | 0 | unsafe { IntValue::new(LLVMConstZExtOrBitCast(self.as_value_ref(), int_type.as_type_ref())) } |
238 | 0 | } |
239 | | |
240 | 0 | pub fn const_bit_cast(self, int_type: IntType) -> IntValue<'ctx> { |
241 | 0 | unsafe { IntValue::new(LLVMConstBitCast(self.as_value_ref(), int_type.as_type_ref())) } |
242 | 0 | } |
243 | | |
244 | | // SubType: rhs same as lhs; return IntValue<bool> |
245 | 0 | pub fn const_int_compare(self, op: IntPredicate, rhs: IntValue<'ctx>) -> IntValue<'ctx> { |
246 | 0 | unsafe { IntValue::new(LLVMConstICmp(op.into(), self.as_value_ref(), rhs.as_value_ref())) } |
247 | 0 | } |
248 | | |
249 | | // SubTypes: self can only be IntValue<bool> |
250 | 0 | pub fn const_select<BV: BasicValue<'ctx>>(self, then: BV, else_: BV) -> BasicValueEnum<'ctx> { |
251 | 0 | unsafe { |
252 | 0 | BasicValueEnum::new(LLVMConstSelect( |
253 | 0 | self.as_value_ref(), |
254 | 0 | then.as_value_ref(), |
255 | 0 | else_.as_value_ref(), |
256 | 0 | )) |
257 | 0 | } |
258 | 0 | } |
259 | | |
260 | | /// Determines whether or not an `IntValue` is an `llvm::Constant`. |
261 | | /// |
262 | | /// Constants includes values that are not known at compile time, for |
263 | | /// example the address of a function casted to an integer. |
264 | | /// |
265 | | /// # Example |
266 | | /// |
267 | | /// ```no_run |
268 | | /// use inkwell::context::Context; |
269 | | /// |
270 | | /// let context = Context::create(); |
271 | | /// let i64_type = context.i64_type(); |
272 | | /// let i64_val = i64_type.const_int(12, false); |
273 | | /// |
274 | | /// assert!(i64_val.is_const()); |
275 | | /// ``` |
276 | 0 | pub fn is_const(self) -> bool { |
277 | 0 | self.int_value.is_const() |
278 | 0 | } |
279 | | |
280 | | /// Determines whether or not an `IntValue` is an `llvm::ConstantInt`. |
281 | | /// |
282 | | /// ConstantInt only includes values that are known at compile time. |
283 | | /// |
284 | | /// # Example |
285 | | /// |
286 | | /// ```no_run |
287 | | /// use inkwell::context::Context; |
288 | | /// |
289 | | /// let context = Context::create(); |
290 | | /// let i64_type = context.i64_type(); |
291 | | /// let i64_val = i64_type.const_int(12, false); |
292 | | /// |
293 | | /// assert!(i64_val.is_constant_int()); |
294 | | /// ``` |
295 | 0 | pub fn is_constant_int(self) -> bool { |
296 | 0 | !unsafe { LLVMIsAConstantInt(self.as_value_ref()) }.is_null() |
297 | 0 | } |
298 | | |
299 | | /// Obtains a constant `IntValue`'s zero extended value. |
300 | | /// |
301 | | /// # Example |
302 | | /// |
303 | | /// ```no_run |
304 | | /// use inkwell::context::Context; |
305 | | /// |
306 | | /// let context = Context::create(); |
307 | | /// let i8_type = context.i8_type(); |
308 | | /// let i8_all_ones = i8_type.const_all_ones(); |
309 | | /// |
310 | | /// assert_eq!(i8_all_ones.get_zero_extended_constant(), Some(255)); |
311 | | /// ``` |
312 | 0 | pub fn get_zero_extended_constant(self) -> Option<u64> { |
313 | 0 | // Garbage values are produced on non constant values |
314 | 0 | if !self.is_constant_int() { |
315 | 0 | return None; |
316 | 0 | } |
317 | 0 | if self.get_type().get_bit_width() > 64 { |
318 | 0 | return None; |
319 | 0 | } |
320 | 0 |
|
321 | 0 | unsafe { Some(LLVMConstIntGetZExtValue(self.as_value_ref())) } |
322 | 0 | } |
323 | | |
324 | | /// Obtains a constant `IntValue`'s sign extended value. |
325 | | /// |
326 | | /// # Example |
327 | | /// |
328 | | /// ```no_run |
329 | | /// use inkwell::context::Context; |
330 | | /// |
331 | | /// let context = Context::create(); |
332 | | /// let i8_type = context.i8_type(); |
333 | | /// let i8_all_ones = i8_type.const_all_ones(); |
334 | | /// |
335 | | /// assert_eq!(i8_all_ones.get_sign_extended_constant(), Some(-1)); |
336 | | /// ``` |
337 | 0 | pub fn get_sign_extended_constant(self) -> Option<i64> { |
338 | 0 | // Garbage values are produced on non constant values |
339 | 0 | if !self.is_constant_int() { |
340 | 0 | return None; |
341 | 0 | } |
342 | 0 | if self.get_type().get_bit_width() > 64 { |
343 | 0 | return None; |
344 | 0 | } |
345 | 0 |
|
346 | 0 | unsafe { Some(LLVMConstIntGetSExtValue(self.as_value_ref())) } |
347 | 0 | } |
348 | | |
349 | 0 | pub fn replace_all_uses_with(self, other: IntValue<'ctx>) { |
350 | 0 | self.int_value.replace_all_uses_with(other.as_value_ref()) |
351 | 0 | } |
352 | | } |
353 | | |
354 | | unsafe impl AsValueRef for IntValue<'_> { |
355 | 7.66M | fn as_value_ref(&self) -> LLVMValueRef { |
356 | 7.66M | self.int_value.value |
357 | 7.66M | } <inkwell::values::int_value::IntValue as inkwell::values::traits::AsValueRef>::as_value_ref Line | Count | Source | 355 | 5.95M | fn as_value_ref(&self) -> LLVMValueRef { | 356 | 5.95M | self.int_value.value | 357 | 5.95M | } |
<inkwell::values::int_value::IntValue as inkwell::values::traits::AsValueRef>::as_value_ref Line | Count | Source | 355 | 1.70M | fn as_value_ref(&self) -> LLVMValueRef { | 356 | 1.70M | self.int_value.value | 357 | 1.70M | } |
|
358 | | } |
359 | | |
360 | | impl Display for IntValue<'_> { |
361 | 0 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
362 | 0 | write!(f, "{}", self.print_to_string()) |
363 | 0 | } |
364 | | } |
365 | | |
366 | | impl<'ctx> TryFrom<InstructionValue<'ctx>> for IntValue<'ctx> { |
367 | | type Error = (); |
368 | | |
369 | 0 | fn try_from(value: InstructionValue) -> Result<Self, Self::Error> { |
370 | 0 | if value.get_type().is_int_type() { |
371 | 0 | unsafe { Ok(IntValue::new(value.as_value_ref())) } |
372 | | } else { |
373 | 0 | Err(()) |
374 | | } |
375 | 0 | } |
376 | | } |