1#[llvm_versions(..=17)]
2use llvm_sys::core::{
3 LLVMConstAShr, LLVMConstAnd, LLVMConstIntCast, LLVMConstLShr, LLVMConstOr, LLVMConstSExt, LLVMConstSExtOrBitCast,
4 LLVMConstSIToFP, LLVMConstUIToFP, LLVMConstZExt, LLVMConstZExtOrBitCast,
5};
6use llvm_sys::core::{
7 LLVMConstAdd, LLVMConstBitCast, LLVMConstIntGetSExtValue, LLVMConstIntGetZExtValue, LLVMConstIntToPtr,
8 LLVMConstNSWAdd, LLVMConstNSWNeg, LLVMConstNSWSub, LLVMConstNUWAdd, LLVMConstNUWSub, LLVMConstNeg, LLVMConstNot,
9 LLVMConstSub, LLVMConstTrunc, LLVMConstTruncOrBitCast, LLVMConstXor, LLVMIsAConstantInt,
10};
11#[llvm_versions(..=16)]
12use llvm_sys::core::{LLVMConstNUWNeg, LLVMConstSelect};
13
14#[llvm_versions(17..)]
15use llvm_sys::core::LLVMSetNUW;
16
17#[llvm_versions(..=18)]
18use llvm_sys::core::{LLVMConstICmp, LLVMConstShl};
19
20#[llvm_versions(..21)]
21use llvm_sys::core::{LLVMConstMul, LLVMConstNSWMul, LLVMConstNUWMul};
22
23use llvm_sys::prelude::LLVMValueRef;
24
25use std::convert::TryFrom;
26use std::ffi::CStr;
27use std::fmt::{self, Display};
28
29#[llvm_versions(..=17)]
30use crate::types::FloatType;
31use crate::types::{AsTypeRef, IntType, PointerType};
32use crate::values::traits::AsValueRef;
33#[llvm_versions(..=17)]
34use crate::values::FloatValue;
35#[llvm_versions(..=16)]
36use crate::values::{BasicValue, BasicValueEnum};
37use crate::values::{InstructionValue, PointerValue, Value};
38
39#[llvm_versions(..=18)]
40use crate::IntPredicate;
41
42use super::AnyValue;
43
44#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
45pub struct IntValue<'ctx> {
46 int_value: Value<'ctx>,
47}
48
49impl<'ctx> IntValue<'ctx> {
50 pub unsafe fn new(value: LLVMValueRef) -> Self {
56 assert!(!value.is_null());
57
58 IntValue {
59 int_value: Value::new(value),
60 }
61 }
62
63 pub fn get_name(&self) -> &CStr {
66 self.int_value.get_name()
67 }
68
69 pub fn set_name(&self, name: &str) {
71 self.int_value.set_name(name)
72 }
73
74 pub fn get_type(self) -> IntType<'ctx> {
75 unsafe { IntType::new(self.int_value.get_type()) }
76 }
77
78 pub fn is_null(self) -> bool {
79 self.int_value.is_null()
80 }
81
82 pub fn is_undef(self) -> bool {
83 self.int_value.is_undef()
84 }
85
86 pub fn print_to_stderr(self) {
87 self.int_value.print_to_stderr()
88 }
89
90 pub fn as_instruction(self) -> Option<InstructionValue<'ctx>> {
91 self.int_value.as_instruction()
92 }
93
94 pub fn const_not(self) -> Self {
95 unsafe { IntValue::new(LLVMConstNot(self.as_value_ref())) }
96 }
97
98 pub fn const_neg(self) -> Self {
100 unsafe { IntValue::new(LLVMConstNeg(self.as_value_ref())) }
101 }
102
103 pub fn const_nsw_neg(self) -> Self {
104 unsafe { IntValue::new(LLVMConstNSWNeg(self.as_value_ref())) }
105 }
106
107 #[llvm_versions(..17)]
108 pub fn const_nuw_neg(self) -> Self {
109 unsafe { IntValue::new(LLVMConstNUWNeg(self.as_value_ref())) }
110 }
111
112 #[llvm_versions(17..)]
113 pub fn const_nuw_neg(self) -> Self {
114 let value = unsafe { LLVMConstNeg(self.as_value_ref()) };
115 unsafe {
116 LLVMSetNUW(value, true.into());
117 }
118 unsafe { IntValue::new(value) }
119 }
120
121 pub fn const_add(self, rhs: IntValue<'ctx>) -> Self {
122 unsafe { IntValue::new(LLVMConstAdd(self.as_value_ref(), rhs.as_value_ref())) }
123 }
124
125 pub fn const_nsw_add(self, rhs: IntValue<'ctx>) -> Self {
126 unsafe { IntValue::new(LLVMConstNSWAdd(self.as_value_ref(), rhs.as_value_ref())) }
127 }
128
129 pub fn const_nuw_add(self, rhs: IntValue<'ctx>) -> Self {
130 unsafe { IntValue::new(LLVMConstNUWAdd(self.as_value_ref(), rhs.as_value_ref())) }
131 }
132
133 pub fn const_sub(self, rhs: IntValue<'ctx>) -> Self {
134 unsafe { IntValue::new(LLVMConstSub(self.as_value_ref(), rhs.as_value_ref())) }
135 }
136
137 pub fn const_nsw_sub(self, rhs: IntValue<'ctx>) -> Self {
138 unsafe { IntValue::new(LLVMConstNSWSub(self.as_value_ref(), rhs.as_value_ref())) }
139 }
140
141 pub fn const_nuw_sub(self, rhs: IntValue<'ctx>) -> Self {
142 unsafe { IntValue::new(LLVMConstNUWSub(self.as_value_ref(), rhs.as_value_ref())) }
143 }
144
145 #[llvm_versions(..21)]
146 pub fn const_mul(self, rhs: IntValue<'ctx>) -> Self {
147 unsafe { IntValue::new(LLVMConstMul(self.as_value_ref(), rhs.as_value_ref())) }
148 }
149
150 #[llvm_versions(..21)]
151 pub fn const_nsw_mul(self, rhs: IntValue<'ctx>) -> Self {
152 unsafe { IntValue::new(LLVMConstNSWMul(self.as_value_ref(), rhs.as_value_ref())) }
153 }
154
155 #[llvm_versions(..21)]
156 pub fn const_nuw_mul(self, rhs: IntValue<'ctx>) -> Self {
157 unsafe { IntValue::new(LLVMConstNUWMul(self.as_value_ref(), rhs.as_value_ref())) }
158 }
159
160 #[llvm_versions(..=14)]
161 pub fn const_unsigned_div(self, rhs: IntValue<'ctx>) -> Self {
162 use llvm_sys::core::LLVMConstUDiv;
163
164 unsafe { IntValue::new(LLVMConstUDiv(self.as_value_ref(), rhs.as_value_ref())) }
165 }
166
167 #[llvm_versions(..=14)]
168 pub fn const_signed_div(self, rhs: IntValue<'ctx>) -> Self {
169 use llvm_sys::core::LLVMConstSDiv;
170
171 unsafe { IntValue::new(LLVMConstSDiv(self.as_value_ref(), rhs.as_value_ref())) }
172 }
173
174 #[llvm_versions(..=14)]
175 pub fn const_exact_signed_div(self, rhs: IntValue<'ctx>) -> Self {
176 use llvm_sys::core::LLVMConstExactSDiv;
177
178 unsafe { IntValue::new(LLVMConstExactSDiv(self.as_value_ref(), rhs.as_value_ref())) }
179 }
180
181 #[llvm_versions(..=14)]
182 pub fn const_exact_unsigned_div(self, rhs: IntValue<'ctx>) -> Self {
183 use llvm_sys::core::LLVMConstExactUDiv;
184
185 unsafe { IntValue::new(LLVMConstExactUDiv(self.as_value_ref(), rhs.as_value_ref())) }
186 }
187
188 #[llvm_versions(..=14)]
189 pub fn const_unsigned_remainder(self, rhs: IntValue<'ctx>) -> Self {
190 use llvm_sys::core::LLVMConstURem;
191
192 unsafe { IntValue::new(LLVMConstURem(self.as_value_ref(), rhs.as_value_ref())) }
193 }
194
195 #[llvm_versions(..=14)]
196 pub fn const_signed_remainder(self, rhs: IntValue<'ctx>) -> Self {
197 use llvm_sys::core::LLVMConstSRem;
198
199 unsafe { IntValue::new(LLVMConstSRem(self.as_value_ref(), rhs.as_value_ref())) }
200 }
201
202 #[llvm_versions(..=17)]
203 pub fn const_and(self, rhs: IntValue<'ctx>) -> Self {
204 unsafe { IntValue::new(LLVMConstAnd(self.as_value_ref(), rhs.as_value_ref())) }
205 }
206
207 #[llvm_versions(..=17)]
208 pub fn const_or(self, rhs: IntValue<'ctx>) -> Self {
209 unsafe { IntValue::new(LLVMConstOr(self.as_value_ref(), rhs.as_value_ref())) }
210 }
211
212 pub fn const_xor(self, rhs: IntValue<'ctx>) -> Self {
213 unsafe { IntValue::new(LLVMConstXor(self.as_value_ref(), rhs.as_value_ref())) }
214 }
215
216 #[llvm_versions(..=17)]
218 pub fn const_cast(self, int_type: IntType<'ctx>, is_signed: bool) -> Self {
219 unsafe {
220 IntValue::new(LLVMConstIntCast(
221 self.as_value_ref(),
222 int_type.as_type_ref(),
223 is_signed as i32,
224 ))
225 }
226 }
227
228 #[llvm_versions(..=18)]
230 pub fn const_shl(self, rhs: IntValue<'ctx>) -> Self {
231 unsafe { IntValue::new(LLVMConstShl(self.as_value_ref(), rhs.as_value_ref())) }
232 }
233
234 #[llvm_versions(..=17)]
235 pub fn const_rshr(self, rhs: IntValue<'ctx>) -> Self {
236 unsafe { IntValue::new(LLVMConstLShr(self.as_value_ref(), rhs.as_value_ref())) }
237 }
238
239 #[llvm_versions(..=17)]
240 pub fn const_ashr(self, rhs: IntValue<'ctx>) -> Self {
241 unsafe { IntValue::new(LLVMConstAShr(self.as_value_ref(), rhs.as_value_ref())) }
242 }
243
244 #[llvm_versions(..=17)]
246 pub fn const_unsigned_to_float(self, float_type: FloatType<'ctx>) -> FloatValue<'ctx> {
247 unsafe { FloatValue::new(LLVMConstUIToFP(self.as_value_ref(), float_type.as_type_ref())) }
248 }
249
250 #[llvm_versions(..=17)]
252 pub fn const_signed_to_float(self, float_type: FloatType<'ctx>) -> FloatValue<'ctx> {
253 unsafe { FloatValue::new(LLVMConstSIToFP(self.as_value_ref(), float_type.as_type_ref())) }
254 }
255
256 pub fn const_to_pointer(self, ptr_type: PointerType<'ctx>) -> PointerValue<'ctx> {
257 unsafe { PointerValue::new(LLVMConstIntToPtr(self.as_value_ref(), ptr_type.as_type_ref())) }
258 }
259
260 pub fn const_truncate(self, int_type: IntType<'ctx>) -> IntValue<'ctx> {
261 unsafe { IntValue::new(LLVMConstTrunc(self.as_value_ref(), int_type.as_type_ref())) }
262 }
263
264 #[llvm_versions(..=17)]
266 pub fn const_s_extend(self, int_type: IntType<'ctx>) -> IntValue<'ctx> {
267 unsafe { IntValue::new(LLVMConstSExt(self.as_value_ref(), int_type.as_type_ref())) }
268 }
269
270 #[llvm_versions(..=17)]
272 pub fn const_z_ext(self, int_type: IntType<'ctx>) -> IntValue<'ctx> {
273 unsafe { IntValue::new(LLVMConstZExt(self.as_value_ref(), int_type.as_type_ref())) }
274 }
275
276 pub fn const_truncate_or_bit_cast(self, int_type: IntType<'ctx>) -> IntValue<'ctx> {
277 unsafe { IntValue::new(LLVMConstTruncOrBitCast(self.as_value_ref(), int_type.as_type_ref())) }
278 }
279
280 #[llvm_versions(..=17)]
282 pub fn const_s_extend_or_bit_cast(self, int_type: IntType<'ctx>) -> IntValue<'ctx> {
283 unsafe { IntValue::new(LLVMConstSExtOrBitCast(self.as_value_ref(), int_type.as_type_ref())) }
284 }
285
286 #[llvm_versions(..=17)]
288 pub fn const_z_ext_or_bit_cast(self, int_type: IntType<'ctx>) -> IntValue<'ctx> {
289 unsafe { IntValue::new(LLVMConstZExtOrBitCast(self.as_value_ref(), int_type.as_type_ref())) }
290 }
291
292 pub fn const_bit_cast(self, int_type: IntType) -> IntValue<'ctx> {
293 unsafe { IntValue::new(LLVMConstBitCast(self.as_value_ref(), int_type.as_type_ref())) }
294 }
295
296 #[llvm_versions(..=18)]
298 pub fn const_int_compare(self, op: IntPredicate, rhs: IntValue<'ctx>) -> IntValue<'ctx> {
299 unsafe { IntValue::new(LLVMConstICmp(op.into(), self.as_value_ref(), rhs.as_value_ref())) }
300 }
301
302 #[llvm_versions(..=16)]
304 pub fn const_select<BV: BasicValue<'ctx>>(self, then: BV, else_: BV) -> BasicValueEnum<'ctx> {
305 unsafe {
306 BasicValueEnum::new(LLVMConstSelect(
307 self.as_value_ref(),
308 then.as_value_ref(),
309 else_.as_value_ref(),
310 ))
311 }
312 }
313
314 pub fn is_const(self) -> bool {
331 self.int_value.is_const()
332 }
333
334 pub fn is_constant_int(self) -> bool {
350 !unsafe { LLVMIsAConstantInt(self.as_value_ref()) }.is_null()
351 }
352
353 pub fn get_zero_extended_constant(self) -> Option<u64> {
367 if !self.is_constant_int() {
369 return None;
370 }
371 if self.get_type().get_bit_width() > 64 {
372 return None;
373 }
374
375 unsafe { Some(LLVMConstIntGetZExtValue(self.as_value_ref())) }
376 }
377
378 pub fn get_sign_extended_constant(self) -> Option<i64> {
392 if !self.is_constant_int() {
394 return None;
395 }
396 if self.get_type().get_bit_width() > 64 {
397 return None;
398 }
399
400 unsafe { Some(LLVMConstIntGetSExtValue(self.as_value_ref())) }
401 }
402
403 pub fn replace_all_uses_with(self, other: IntValue<'ctx>) {
404 self.int_value.replace_all_uses_with(other.as_value_ref())
405 }
406}
407
408unsafe impl AsValueRef for IntValue<'_> {
409 fn as_value_ref(&self) -> LLVMValueRef {
410 self.int_value.value
411 }
412}
413
414impl Display for IntValue<'_> {
415 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
416 write!(f, "{}", self.print_to_string())
417 }
418}
419
420impl<'ctx> TryFrom<InstructionValue<'ctx>> for IntValue<'ctx> {
421 type Error = ();
422
423 fn try_from(value: InstructionValue) -> Result<Self, Self::Error> {
424 if value.get_type().is_int_type() {
425 unsafe { Ok(IntValue::new(value.as_value_ref())) }
426 } else {
427 Err(())
428 }
429 }
430}