Skip to main content

inkwell/values/
float_value.rs

1#[llvm_versions(..=17)]
2use crate::types::IntType;
3#[llvm_versions(..=18)]
4use llvm_sys::core::LLVMConstFCmp;
5#[llvm_versions(..=15)]
6use llvm_sys::core::LLVMConstFNeg;
7use llvm_sys::core::LLVMConstRealGetDouble;
8#[llvm_versions(..=17)]
9use llvm_sys::core::{LLVMConstFPCast, LLVMConstFPExt, LLVMConstFPToSI, LLVMConstFPToUI, LLVMConstFPTrunc};
10use llvm_sys::prelude::LLVMValueRef;
11
12use std::convert::TryFrom;
13use std::ffi::CStr;
14use std::fmt::{self, Display};
15
16#[llvm_versions(..=17)]
17use crate::types::AsTypeRef;
18use crate::types::FloatType;
19use crate::values::traits::AsValueRef;
20use crate::values::{InstructionValue, Value};
21
22#[llvm_versions(..=18)]
23use crate::{values::IntValue, FloatPredicate};
24
25use super::AnyValue;
26
27#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
28pub struct FloatValue<'ctx> {
29    float_value: Value<'ctx>,
30}
31
32impl<'ctx> FloatValue<'ctx> {
33    /// Get a value from an [LLVMValueRef].
34    ///
35    /// # Safety
36    ///
37    /// The ref must be valid and of type float.
38    pub unsafe fn new(value: LLVMValueRef) -> Self {
39        assert!(!value.is_null());
40
41        FloatValue {
42            float_value: Value::new(value),
43        }
44    }
45
46    /// Gets name of the `FloatValue`. If the value is a constant, this will
47    /// return an empty string.
48    pub fn get_name(&self) -> &CStr {
49        self.float_value.get_name()
50    }
51
52    /// Set name of the `FloatValue`.
53    pub fn set_name(&self, name: &str) {
54        self.float_value.set_name(name)
55    }
56
57    pub fn get_type(self) -> FloatType<'ctx> {
58        unsafe { FloatType::new(self.float_value.get_type()) }
59    }
60
61    pub fn is_null(self) -> bool {
62        self.float_value.is_null()
63    }
64
65    pub fn is_undef(self) -> bool {
66        self.float_value.is_undef()
67    }
68
69    pub fn print_to_stderr(self) {
70        self.float_value.print_to_stderr()
71    }
72
73    pub fn as_instruction(self) -> Option<InstructionValue<'ctx>> {
74        self.float_value.as_instruction()
75    }
76
77    #[llvm_versions(..=15)]
78    pub fn const_neg(self) -> Self {
79        unsafe { FloatValue::new(LLVMConstFNeg(self.as_value_ref())) }
80    }
81
82    #[llvm_versions(..=14)]
83    pub fn const_add(self, rhs: FloatValue<'ctx>) -> Self {
84        use llvm_sys::core::LLVMConstFAdd;
85
86        unsafe { FloatValue::new(LLVMConstFAdd(self.as_value_ref(), rhs.as_value_ref())) }
87    }
88
89    #[llvm_versions(..=14)]
90    pub fn const_sub(self, rhs: FloatValue<'ctx>) -> Self {
91        use llvm_sys::core::LLVMConstFSub;
92
93        unsafe { FloatValue::new(LLVMConstFSub(self.as_value_ref(), rhs.as_value_ref())) }
94    }
95
96    #[llvm_versions(..=14)]
97    pub fn const_mul(self, rhs: FloatValue<'ctx>) -> Self {
98        use llvm_sys::core::LLVMConstFMul;
99
100        unsafe { FloatValue::new(LLVMConstFMul(self.as_value_ref(), rhs.as_value_ref())) }
101    }
102
103    #[llvm_versions(..=14)]
104    pub fn const_div(self, rhs: FloatValue<'ctx>) -> Self {
105        use llvm_sys::core::LLVMConstFDiv;
106
107        unsafe { FloatValue::new(LLVMConstFDiv(self.as_value_ref(), rhs.as_value_ref())) }
108    }
109
110    #[llvm_versions(..=14)]
111    pub fn const_remainder(self, rhs: FloatValue<'ctx>) -> Self {
112        use llvm_sys::core::LLVMConstFRem;
113
114        unsafe { FloatValue::new(LLVMConstFRem(self.as_value_ref(), rhs.as_value_ref())) }
115    }
116
117    #[llvm_versions(..=17)]
118    pub fn const_cast(self, float_type: FloatType<'ctx>) -> Self {
119        unsafe { FloatValue::new(LLVMConstFPCast(self.as_value_ref(), float_type.as_type_ref())) }
120    }
121
122    #[llvm_versions(..=17)]
123    pub fn const_to_unsigned_int(self, int_type: IntType<'ctx>) -> IntValue<'ctx> {
124        unsafe { IntValue::new(LLVMConstFPToUI(self.as_value_ref(), int_type.as_type_ref())) }
125    }
126
127    #[llvm_versions(..=17)]
128    pub fn const_to_signed_int(self, int_type: IntType<'ctx>) -> IntValue<'ctx> {
129        unsafe { IntValue::new(LLVMConstFPToSI(self.as_value_ref(), int_type.as_type_ref())) }
130    }
131
132    #[llvm_versions(..=17)]
133    pub fn const_truncate(self, float_type: FloatType<'ctx>) -> FloatValue<'ctx> {
134        unsafe { FloatValue::new(LLVMConstFPTrunc(self.as_value_ref(), float_type.as_type_ref())) }
135    }
136
137    #[llvm_versions(..=17)]
138    pub fn const_extend(self, float_type: FloatType<'ctx>) -> FloatValue<'ctx> {
139        unsafe { FloatValue::new(LLVMConstFPExt(self.as_value_ref(), float_type.as_type_ref())) }
140    }
141
142    // SubType: rhs same as lhs; return IntValue<bool>
143    #[llvm_versions(..=18)]
144    pub fn const_compare(self, op: FloatPredicate, rhs: FloatValue<'ctx>) -> IntValue<'ctx> {
145        unsafe { IntValue::new(LLVMConstFCmp(op.into(), self.as_value_ref(), rhs.as_value_ref())) }
146    }
147
148    /// Determines whether or not a `FloatValue` is a constant.
149    ///
150    /// # Example
151    ///
152    /// ```no_run
153    /// use inkwell::context::Context;
154    ///
155    /// let context = Context::create();
156    /// let f64_type = context.f64_type();
157    /// let f64_val = f64_type.const_float(1.2);
158    ///
159    /// assert!(f64_val.is_const());
160    /// ```
161    pub fn is_const(self) -> bool {
162        self.float_value.is_const()
163    }
164
165    /// Obtains a constant `FloatValue`'s value and whether or not it lost info.
166    ///
167    /// # Example
168    ///
169    /// ```no_run
170    /// use inkwell::context::Context;
171    ///
172    /// let context = Context::create();
173    /// let f64_type = context.f64_type();
174    /// let f64_1_2 = f64_type.const_float(1.2);
175    ///
176    /// assert_eq!(f64_1_2.get_constant(), Some((1.2, false)));
177    /// ```
178    pub fn get_constant(self) -> Option<(f64, bool)> {
179        // Nothing bad happens as far as I can tell if we don't check if const
180        // unlike the int versions, but just doing this just in case and for consistency
181        if !self.is_const() {
182            return None;
183        }
184
185        let mut lossy = 0;
186        let constant = unsafe { LLVMConstRealGetDouble(self.as_value_ref(), &mut lossy) };
187
188        Some((constant, lossy == 1))
189    }
190
191    pub fn replace_all_uses_with(self, other: FloatValue<'ctx>) {
192        self.float_value.replace_all_uses_with(other.as_value_ref())
193    }
194}
195
196unsafe impl AsValueRef for FloatValue<'_> {
197    fn as_value_ref(&self) -> LLVMValueRef {
198        self.float_value.value
199    }
200}
201
202impl Display for FloatValue<'_> {
203    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
204        write!(f, "{}", self.print_to_string())
205    }
206}
207
208impl<'ctx> TryFrom<InstructionValue<'ctx>> for FloatValue<'ctx> {
209    type Error = ();
210
211    fn try_from(value: InstructionValue) -> Result<Self, Self::Error> {
212        if value.get_type().is_float_type() {
213            unsafe { Ok(FloatValue::new(value.as_value_ref())) }
214        } else {
215            Err(())
216        }
217    }
218}