llvm_plugin_inkwell/values/
float_value.rs

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