inkwell/values/
float_value.rs

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