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*/