fugue_ir/
float_format.rs

1//use crate::bits;
2use crate::deserialise::error::Error;
3use crate::deserialise::parse::XmlExt;
4
5//use std::num::FpCategory;
6//use std::mem::size_of;
7
8#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
9#[derive(serde::Deserialize, serde::Serialize)]
10pub struct FloatFormat {
11    pub size: usize,
12    pub sign_pos: u32,
13    pub frac_pos: u32,
14    pub frac_size: u32,
15    pub exp_pos: u32,
16    pub exp_max: i32,
17    pub exp_size: u32,
18    pub bias: i32,
19    pub j_bit_implied: bool,
20}
21
22impl FloatFormat {
23    pub const fn float2() -> Self {
24        FloatFormat {
25            size: 2,
26            sign_pos: 15,
27            frac_pos: 0,
28            frac_size: 10,
29            exp_pos: 10,
30            exp_size: 5,
31            exp_max: (1 << 5) - 1,
32            bias: 15,
33            j_bit_implied: true,
34        }
35    }
36
37    pub const fn float4() -> Self {
38        FloatFormat {
39            size: 4,
40            sign_pos: 31,
41            frac_pos: 0,
42            frac_size: 23,
43            exp_pos: 23,
44            exp_size: 8,
45            exp_max: (1 << 8) - 1,
46            bias: 127,
47            j_bit_implied: true,
48        }
49    }
50
51    pub const fn float8() -> Self {
52        FloatFormat {
53            size: 8,
54            sign_pos: 63,
55            frac_pos: 0,
56            frac_size: 52,
57            exp_pos: 52,
58            exp_size: 11,
59            exp_max: (1 << 11) - 1,
60            bias: 1023,
61            j_bit_implied: true,
62        }
63    }
64
65    pub const fn float10() -> Self {
66        FloatFormat {
67            size: 10,
68            sign_pos: 79,
69            exp_pos: 64,
70            exp_size: 15,
71            exp_max: (1 << 15) - 1,
72            frac_pos: 0,
73            frac_size: 64,
74            bias: 16383,
75            j_bit_implied: true,
76        }
77    }
78
79    pub const fn float16() -> Self {
80        FloatFormat {
81            size: 16,
82            sign_pos: 127,
83            exp_pos: 112,
84            exp_size: 15,
85            exp_max: (1 << 15) - 1,
86            frac_pos: 0,
87            frac_size: 112,
88            bias: 16383,
89            j_bit_implied: true,
90        }
91    }
92
93    /*
94    pub fn from_parts(sign: bool, signif: u64, exp: i32) -> f64 {
95        let signif = signif.checked_shr(1).unwrap_or(0);
96        let precis = 8 * size_of::<u64>() as i32 - 1;
97        let expchg = exp - precis + 1;
98
99        let res = ldexp(signif as f64, expchg);
100        if sign {
101            res * -1.0f64
102        } else {
103            res
104        }
105    }
106
107    pub fn into_parts(x: f64) -> (FpCategory, bool, u64, i32) {
108        let kind = x.classify();
109        let (mut norm, e) = frexp(x);
110        norm = ldexp(norm, 8 * size_of::<u64>() as i32 - 1);
111
112        let sign = x.is_sign_negative();
113        let signif = (norm as u64).checked_shl(1).unwrap_or(0);
114        let exp = e.wrapping_sub(1);
115
116        (kind, sign, signif, exp)
117    }
118
119    pub fn fractional_code(&self, x: u64) -> u64 {
120        let y = x.checked_shr(self.frac_pos).unwrap_or(0);
121        let z = y.checked_shl(8 * size_of::<u64>() as u32 - self.frac_size).unwrap_or(0);
122        z
123    }
124
125    pub fn with_fractional_code(&self, x: u64, code: u64) -> u64 {
126        let y = code.checked_shr(8 * size_of::<u64>() as u32 - self.frac_size)
127            .unwrap_or(0);
128        let z = y.checked_shl(self.frac_pos).unwrap_or(0);
129        x | z
130    }
131
132    pub fn sign(&self, x: u64) -> bool {
133        let y = x.checked_shr(self.sign_pos).unwrap_or(0);
134        (y & 1) != 0
135    }
136
137    pub fn with_sign(&self, x: u64, sign: bool) -> u64 {
138        if !sign {
139            x
140        } else {
141            x | 1u64.checked_shl(self.sign_pos).unwrap_or(0)
142        }
143    }
144
145    pub fn exponent_code(&self, x: u64) -> i32 {
146        let y = x.checked_shr(self.exp_pos).unwrap_or(0);
147        let mask = 1u64.checked_shl(self.exp_size)
148            .unwrap_or(0)
149            .wrapping_sub(1);
150
151        (y & mask) as i32
152    }
153
154    pub fn with_exponent_code(&self, x: u64, code: u64) -> u64 {
155        x | code.checked_shl(self.exp_pos).unwrap_or(0)
156    }
157
158    pub fn zero_encoding(&self, sign: bool) -> u64 {
159        let mut res = 0;
160        res = self.with_fractional_code(res, 0);
161        res = self.with_exponent_code(res, 0);
162        self.with_sign(res, sign)
163    }
164
165    pub fn infinity_encoding(&self, sign: bool) -> u64 {
166        let mut res = 0;
167        res = self.with_fractional_code(res, 0);
168        res = self.with_exponent_code(res, self.exp_max as u64);
169        self.with_sign(res, sign)
170    }
171
172    pub fn nan_encoding(&self, sign: bool) -> u64 {
173        let mut res = 0;
174        let mask = 1u64.checked_shl(8 * size_of::<u64>() as u32 - 1)
175            .unwrap_or(0);
176        res = self.with_fractional_code(res, mask);
177        res = self.with_exponent_code(res, self.exp_max as u64);
178        self.with_sign(res, sign)
179    }
180
181    pub fn host_float(&self, encoding: u64) -> (FpCategory, f64) {
182        let sign = self.sign(encoding);
183        let frac = self.fractional_code(encoding);
184        let exp = self.exponent_code(encoding);
185        let mut normal = true;
186
187        let kind = if exp == 0 {
188            if frac == 0 {
189                return (FpCategory::Zero, if sign { -0.0f64 } else { 0.0f64 })
190            }
191            normal = false;
192            FpCategory::Subnormal
193        } else if exp == self.exp_max {
194            if frac == 0 {
195                return (FpCategory::Infinite, if sign { f64::NEG_INFINITY } else { f64::INFINITY })
196            } else {
197                return (FpCategory::Nan, if sign { -f64::NAN } else { f64::NAN })
198            }
199        } else {
200            FpCategory::Normal
201        };
202
203        let exp = exp.wrapping_sub(self.bias);
204
205        if normal && self.j_bit_implied {
206            let frac = frac.checked_shr(1).unwrap_or(0);
207            let highbit = 1u64.checked_shl(8 * size_of::<u64>() as u32 - 1)
208                .unwrap_or(0);
209            let frac = frac | highbit;
210            (kind, Self::from_parts(sign, frac, exp))
211        } else {
212            (kind, Self::from_parts(sign, frac, exp))
213        }
214    }
215
216    pub fn encoding(&self, host: f64) -> u64 {
217        let (kind, sign, signif, exp) = Self::into_parts(host);
218        match kind {
219            FpCategory::Zero => return self.zero_encoding(sign),
220            FpCategory::Infinite => return self.infinity_encoding(sign),
221            FpCategory::Nan => return self.nan_encoding(sign),
222            _ => {
223                let exp = exp.wrapping_add(self.bias);
224                if exp < 0 {
225                    return self.zero_encoding(sign)
226                } else if exp > self.exp_max {
227                    return self.infinity_encoding(sign)
228                }
229
230                let signif = if self.j_bit_implied && exp != 0 {
231                    signif.checked_shl(1).unwrap_or(0)
232                } else {
233                    signif
234                };
235
236                let mut res = 0;
237                res = self.with_fractional_code(res, signif);
238                res = self.with_exponent_code(res, exp as u64);
239                self.with_sign(res, sign)
240            }
241        }
242    }
243
244    pub fn convert_encoding(&self, other: &FloatFormat, encoding: u64) -> u64 {
245        let sign = self.sign(encoding);
246        let frac = self.fractional_code(encoding);
247        let exp = self.exponent_code(encoding);
248
249        let exp = if exp == other.exp_max {
250            self.exp_max
251        } else {
252            let exp = exp.wrapping_sub(other.bias);
253            let exp = exp.wrapping_add(self.bias);
254            if exp < 0 {
255                return self.zero_encoding(sign)
256            } else if exp > self.exp_max {
257                return self.infinity_encoding(sign)
258            }
259            exp
260        };
261
262        let frac = if self.j_bit_implied && !other.j_bit_implied {
263            frac.checked_shl(1).unwrap_or(0)
264        } else if other.j_bit_implied && !self.j_bit_implied {
265            let frac = frac.checked_shl(1).unwrap_or(0);
266            let highbit = 1u64.checked_shl(8 * size_of::<u64>() as u32 - 1)
267                .unwrap_or(0);
268            frac | highbit
269        } else {
270            frac
271        };
272
273        let mut res = 0;
274        res = self.with_fractional_code(res, frac);
275        res = self.with_exponent_code(res, exp as u64);
276        self.with_sign(res, sign)
277    }
278
279    pub fn op_equal(&self, a: u64, b: u64) -> u64 {
280        let (_, a1) = self.host_float(a);
281        let (_, b1) = self.host_float(b);
282        if a1 == b1 { 1 } else { 0 }
283    }
284
285    pub fn op_not_equal(&self, a: u64, b: u64) -> u64 {
286        let (_, a1) = self.host_float(a);
287        let (_, b1) = self.host_float(b);
288        if a1 != b1 { 1 } else { 0 }
289    }
290
291    pub fn op_less(&self, a: u64, b: u64) -> u64 {
292        let (_, a1) = self.host_float(a);
293        let (_, b1) = self.host_float(b);
294        if a1 < b1 { 1 } else { 0 }
295    }
296
297    pub fn op_less_equal(&self, a: u64, b: u64) -> u64 {
298        let (_, a1) = self.host_float(a);
299        let (_, b1) = self.host_float(b);
300        if a1 <= b1 { 1 } else { 0 }
301    }
302
303    pub fn op_add(&self, a: u64, b: u64) -> u64 {
304        let (_, a1) = self.host_float(a);
305        let (_, b1) = self.host_float(b);
306        self.encoding(a1 + b1)
307    }
308
309    pub fn op_sub(&self, a: u64, b: u64) -> u64 {
310        let (_, a1) = self.host_float(a);
311        let (_, b1) = self.host_float(b);
312        self.encoding(a1 - b1)
313    }
314
315    pub fn op_mult(&self, a: u64, b: u64) -> u64 {
316        let (_, a1) = self.host_float(a);
317        let (_, b1) = self.host_float(b);
318        self.encoding(a1 * b1)
319    }
320
321    pub fn op_div(&self, a: u64, b: u64) -> u64 {
322        let (_, a1) = self.host_float(a);
323        let (_, b1) = self.host_float(b);
324        self.encoding(a1 * b1)
325    }
326
327    pub fn op_is_nan(&self, a: u64) -> u64 {
328        let (k, _) = self.host_float(a);
329        if k == FpCategory::Nan { 1 } else { 0 }
330    }
331
332    pub fn op_neg(&self, a: u64) -> u64 {
333        let (_, a1) = self.host_float(a);
334        self.encoding(-a1)
335    }
336
337    pub fn op_abs(&self, a: u64) -> u64 {
338        let (_, a1) = self.host_float(a);
339        self.encoding(a1.abs())
340    }
341
342    pub fn op_sqrt(&self, a: u64) -> u64 {
343        let (_, a1) = self.host_float(a);
344        self.encoding(a1.sqrt())
345    }
346
347    pub fn op_float_of_int(&self, a: u64, size: usize) -> u64 {
348        self.encoding(bits::sign_extend(a as i64, size) as f64)
349    }
350
351    pub fn op_float_of_float(&self, other: &FloatFormat, a: u64) -> u64 {
352        let (_, a1) = self.host_float(a);
353        other.encoding(a1)
354    }
355
356    pub fn op_truncate(&self, a: u64, size: usize) -> u64 {
357        let (_, a1) = self.host_float(a);
358        let res = a1 as i64 as u64;
359        res & bits::calculate_mask(size)
360    }
361
362    pub fn op_ceiling(&self, a: u64) -> u64 {
363        let (_, a1) = self.host_float(a);
364        self.encoding(a1.ceil())
365    }
366
367    pub fn op_floor(&self, a: u64) -> u64 {
368        let (_, a1) = self.host_float(a);
369        self.encoding(a1.floor())
370    }
371
372    pub fn op_round(&self, a: u64) -> u64 {
373        let (_, a1) = self.host_float(a);
374        self.encoding(a1.round())
375    }
376    */
377
378    pub fn size(&self) -> usize {
379        self.size
380    }
381
382    pub fn bits(&self) -> usize {
383        self.size * 8
384    }
385
386    pub fn from_xml(input: xml::Node) -> Result<Self, Error> {
387        let size = input.attribute_int("size")?;
388        let sign_pos = input.attribute_int("signpos")?;
389        let frac_pos = input.attribute_int("fracpos")?;
390        let frac_size = input.attribute_int("fracsize")?;
391        let exp_pos = input.attribute_int("exppos")?;
392        let exp_size = input.attribute_int("expsize")?;
393        let exp_max = (1i32 << exp_size) - 1;
394
395        let bias = input.attribute_int("bias")?;
396        let j_bit_implied = input.attribute_bool("jbitimpled")?;
397
398        Ok(FloatFormat {
399            size,
400            sign_pos,
401            frac_pos,
402            frac_size,
403            exp_pos,
404            exp_size,
405            exp_max,
406            bias,
407            j_bit_implied,
408        })
409    }
410}
411
412/*
413fn frexp(x: f64) -> (f64, i32) {
414    extern "C" {
415        fn frexp(x: f64, exp: *mut i32) -> f64;
416    }
417    let mut exp = 0;
418    let r = unsafe {
419        frexp(x, &mut exp as *mut i32)
420    };
421    (r, exp)
422}
423
424fn ldexp(x: f64, exp: i32) -> f64 {
425    extern "C" {
426        fn ldexp(x: f64, exp: i32) -> f64;
427    }
428    unsafe {
429        ldexp(x, exp)
430    }
431}
432*/