1use core::cmp::Ordering;
5
6use crate::{
7 attribute::Attribute,
8 context::{Context, Ptr},
9 operation::Operation,
10 result::Result,
11 r#type::TypeHandle,
12 utils::apfloat::{Category, DynFloat, ExpInt, Round, Semantics, StatusAnd},
13};
14use alloc::boxed::Box;
15use pliron::derive::attr_interface;
16
17#[attr_interface]
20pub trait TypedAttrInterface {
21 fn get_type(&self, ctx: &Context) -> TypeHandle;
23
24 fn verify(_attr: &dyn Attribute, _ctx: &Context) -> Result<()>
25 where
26 Self: Sized,
27 {
28 Ok(())
29 }
30}
31
32#[attr_interface]
37pub trait OutlinedAttr {
38 fn verify(_attr: &dyn Attribute, _ctx: &Context) -> Result<()>
39 where
40 Self: Sized,
41 {
42 Ok(())
43 }
44}
45
46#[attr_interface]
49pub trait PrintOnceAttr: OutlinedAttr {
50 fn verify(_attr: &dyn Attribute, _ctx: &Context) -> Result<()>
51 where
52 Self: Sized,
53 {
54 Ok(())
55 }
56}
57
58#[attr_interface]
71pub trait FloatAttr: TypedAttrInterface {
72 fn get_inner(&self) -> &dyn DynFloat;
74 fn build_from(&self, df: Box<dyn DynFloat>) -> Box<dyn FloatAttr>;
76 fn get_semantics(&self) -> Semantics;
78 fn get_semantics_static() -> Semantics
80 where
81 Self: Sized;
82
83 fn build_qnan(&self, payload: Option<u128>) -> Box<dyn FloatAttr> {
85 let df = self.get_inner();
86 let qnan = df.build_qnan(payload);
87 self.build_from(qnan)
88 }
89 fn build_snan(&self, payload: Option<u128>) -> Box<dyn FloatAttr> {
91 let df = self.get_inner();
92 let snan = df.build_snan(payload);
93 self.build_from(snan)
94 }
95 fn build_largest(&self) -> Box<dyn FloatAttr> {
97 let df = self.get_inner();
98 let largest = df.build_largest();
99 self.build_from(largest)
100 }
101 fn build_smallest_normalized(&self) -> Box<dyn FloatAttr> {
103 let df = self.get_inner();
104 let smallest_normalized = df.build_smallest_normalized();
105 self.build_from(smallest_normalized)
106 }
107 fn build_from_bits(&self, bits: u128) -> Box<dyn FloatAttr> {
109 let df = self.get_inner();
110 let from_bits = df.build_from_bits(bits);
111 self.build_from(from_bits)
112 }
113 fn build_from_u128_r(&self, value: u128, round: Round) -> StatusAnd<Box<dyn FloatAttr>> {
115 let df = self.get_inner();
116 df.build_from_u128_r(value, round)
117 .map(|df| self.build_from(df))
118 }
119 fn build_from_str_r(&self, s: &str, round: Round) -> Result<StatusAnd<Box<dyn FloatAttr>>> {
121 let df = self.get_inner();
122 let res = df.build_from_str_r(s, round)?;
123 Ok(res.map(|df| self.build_from(df)))
124 }
125 fn build_from_i128_r(&self, value: i128, round: Round) -> StatusAnd<Box<dyn FloatAttr>> {
127 let df = self.get_inner();
128 df.build_from_i128_r(value, round)
129 .map(|from_i128_r| self.build_from(from_i128_r))
130 }
131 fn build_from_i128(&self, value: i128) -> StatusAnd<Box<dyn FloatAttr>> {
133 let df = self.get_inner();
134 df.build_from_i128(value)
135 .map(|from_i128| self.build_from(from_i128))
136 }
137 fn build_from_u128(&self, value: u128) -> StatusAnd<Box<dyn FloatAttr>> {
139 let df = self.get_inner();
140 df.build_from_u128(value)
141 .map(|from_u128| self.build_from(from_u128))
142 }
143
144 fn neg(&self) -> Box<dyn FloatAttr> {
146 let df = self.get_inner();
147 let negated = df.neg();
148 self.build_from(negated)
149 }
150 fn add(&self, rhs: &dyn FloatAttr) -> StatusAnd<Box<dyn FloatAttr>> {
152 let df = self.get_inner();
153 let rhs_df = rhs.get_inner();
154 df.add(rhs_df).map(|add| self.build_from(add))
155 }
156 fn sub(&self, rhs: &dyn FloatAttr) -> StatusAnd<Box<dyn FloatAttr>> {
158 let df = self.get_inner();
159 let rhs_df = rhs.get_inner();
160 df.sub(rhs_df).map(|sub| self.build_from(sub))
161 }
162 fn mul(&self, rhs: &dyn FloatAttr) -> StatusAnd<Box<dyn FloatAttr>> {
164 let df = self.get_inner();
165 let rhs_df = rhs.get_inner();
166 df.mul(rhs_df).map(|mul| self.build_from(mul))
167 }
168 fn div(&self, rhs: &dyn FloatAttr) -> StatusAnd<Box<dyn FloatAttr>> {
170 let df = self.get_inner();
171 let rhs_df = rhs.get_inner();
172 df.div(rhs_df).map(|div| self.build_from(div))
173 }
174 fn rem(&self, rhs: &dyn FloatAttr) -> StatusAnd<Box<dyn FloatAttr>> {
176 let df = self.get_inner();
177 let rhs_df = rhs.get_inner();
178 df.rem(rhs_df).map(|rem| self.build_from(rem))
179 }
180 fn add_r(&self, rhs: &dyn FloatAttr, round: Round) -> StatusAnd<Box<dyn FloatAttr>> {
182 let df = self.get_inner();
183 let rhs_df = rhs.get_inner();
184 df.add_r(rhs_df, round).map(|add_r| self.build_from(add_r))
185 }
186 fn mul_r(&self, rhs: &dyn FloatAttr, round: Round) -> StatusAnd<Box<dyn FloatAttr>> {
188 let df = self.get_inner();
189 let rhs_df = rhs.get_inner();
190 df.mul_r(rhs_df, round).map(|mul_r| self.build_from(mul_r))
191 }
192 fn mul_add_r(
194 &self,
195 rhs: &dyn FloatAttr,
196 addend: &dyn FloatAttr,
197 round: Round,
198 ) -> StatusAnd<Box<dyn FloatAttr>> {
199 let df = self.get_inner();
200 let rhs_df = rhs.get_inner();
201 let addend_df = addend.get_inner();
202 df.mul_add_r(rhs_df, addend_df, round)
203 .map(|mul_add_r| self.build_from(mul_add_r))
204 }
205 fn div_r(&self, rhs: &dyn FloatAttr, round: Round) -> StatusAnd<Box<dyn FloatAttr>> {
207 let df = self.get_inner();
208 let rhs_df = rhs.get_inner();
209 df.div_r(rhs_df, round).map(|div_r| self.build_from(div_r))
210 }
211 fn ieee_rem(&self, rhs: &dyn FloatAttr) -> StatusAnd<Box<dyn FloatAttr>> {
213 let df = self.get_inner();
214 let rhs_df = rhs.get_inner();
215 df.ieee_rem(rhs_df)
216 .map(|ieee_rem| self.build_from(ieee_rem))
217 }
218 fn c_fmod(&self, rhs: &dyn FloatAttr) -> StatusAnd<Box<dyn FloatAttr>> {
220 let df = self.get_inner();
221 let rhs_df = rhs.get_inner();
222 df.c_fmod(rhs_df).map(|c_fmod| self.build_from(c_fmod))
223 }
224 fn round_to_integral(&self, round: Round) -> StatusAnd<Box<dyn FloatAttr>> {
226 let df = self.get_inner();
227 df.round_to_integral(round)
228 .map(|round_to_integral| self.build_from(round_to_integral))
229 }
230 fn next_up(&self) -> StatusAnd<Box<dyn FloatAttr>> {
232 let df = self.get_inner();
233 df.next_up().map(|next_up| self.build_from(next_up))
234 }
235 fn to_bits(&self) -> u128 {
237 let df = self.get_inner();
238 df.to_bits()
239 }
240 fn to_u128_r(&self, width: usize, round: Round, is_exact: &mut bool) -> StatusAnd<u128> {
242 let df = self.get_inner();
243 df.to_u128_r(width, round, is_exact)
244 }
245 fn cmp_abs_normal(&self, other: &dyn FloatAttr) -> Ordering {
247 let df = self.get_inner();
248 df.cmp_abs_normal(other.get_inner())
249 }
250 fn bitwise_eq(&self, other: &dyn FloatAttr) -> bool {
252 let df = self.get_inner();
253 df.bitwise_eq(other.get_inner())
254 }
255 fn is_negative(&self) -> bool {
257 let df = self.get_inner();
258 df.is_negative()
259 }
260 fn is_denormal(&self) -> bool {
262 let df = self.get_inner();
263 df.is_denormal()
264 }
265 fn is_signaling(&self) -> bool {
267 let df = self.get_inner();
268 df.is_signaling()
269 }
270 fn category(&self) -> Category {
272 let df = self.get_inner();
273 df.category()
274 }
275 fn get_exact_inverse(&self) -> Option<Box<dyn FloatAttr>> {
277 let df = self.get_inner();
278 df.get_exact_inverse()
279 .map(|inverse| self.build_from(inverse))
280 }
281 fn ilogb(&self) -> ExpInt {
283 let df = self.get_inner();
284 df.ilogb()
285 }
286 fn scalbn_r(&self, n: ExpInt, round: Round) -> Box<dyn FloatAttr> {
288 let df = self.get_inner();
289 self.build_from(df.scalbn_r(n, round))
290 }
291 fn frexp_r(&self, exp: &mut ExpInt, round: Round) -> Box<dyn FloatAttr> {
293 let df = self.get_inner();
294 let frexp_r = df.frexp_r(exp, round);
295 self.build_from(frexp_r)
296 }
297 fn sub_r(&self, rhs: &dyn FloatAttr, round: Round) -> StatusAnd<Box<dyn FloatAttr>> {
299 let df = self.get_inner();
300 let rhs_df = rhs.get_inner();
301 df.sub_r(rhs_df, round).map(|sub_r| self.build_from(sub_r))
302 }
303 fn mul_add(
305 &self,
306 multiplicand: &dyn FloatAttr,
307 addend: &dyn FloatAttr,
308 ) -> StatusAnd<Box<dyn FloatAttr>> {
309 let df = self.get_inner();
310 let multiplicand_df = multiplicand.get_inner();
311 let addend_df = addend.get_inner();
312 df.mul_add(multiplicand_df, addend_df)
313 .map(|mul_add| self.build_from(mul_add))
314 }
315 fn next_down(&self) -> StatusAnd<Box<dyn FloatAttr>> {
317 let df = self.get_inner();
318 df.next_down().map(|next_down| self.build_from(next_down))
319 }
320 fn abs(&self) -> Box<dyn FloatAttr> {
322 let df = self.get_inner();
323 let abs = df.abs();
324 self.build_from(abs)
325 }
326 fn copy_sign(&self, other: &dyn FloatAttr) -> Box<dyn FloatAttr> {
328 let df = self.get_inner();
329 let other_df = other.get_inner();
330 self.build_from(df.copy_sign(other_df))
331 }
332 fn to_i128_r(&self, width: usize, round: Round, is_exact: &mut bool) -> StatusAnd<i128> {
334 let df = self.get_inner();
335 df.to_i128_r(width, round, is_exact)
336 }
337 fn to_i128(&self, width: usize) -> StatusAnd<i128> {
339 let df = self.get_inner();
340 df.to_i128(width)
341 }
342 fn to_u128(&self, width: usize) -> StatusAnd<u128> {
344 let df = self.get_inner();
345 df.to_u128(width)
346 }
347 fn min(&self, other: &dyn FloatAttr) -> Box<dyn FloatAttr> {
349 let df = self.get_inner();
350 let other_df = other.get_inner();
351 self.build_from(df.min(other_df))
352 }
353 fn max(&self, other: &dyn FloatAttr) -> Box<dyn FloatAttr> {
355 let df = self.get_inner();
356 let other_df = other.get_inner();
357 self.build_from(df.max(other_df))
358 }
359 fn minimum(&self, other: &dyn FloatAttr) -> Box<dyn FloatAttr> {
361 let df = self.get_inner();
362 let other_df = other.get_inner();
363 self.build_from(df.minimum(other_df))
364 }
365 fn maximum(&self, other: &dyn FloatAttr) -> Box<dyn FloatAttr> {
367 let df = self.get_inner();
368 let other_df = other.get_inner();
369 self.build_from(df.maximum(other_df))
370 }
371 fn is_normal(&self) -> bool {
373 let df = self.get_inner();
374 df.is_normal()
375 }
376 fn is_finite(&self) -> bool {
378 let df = self.get_inner();
379 df.is_finite()
380 }
381 fn is_zero(&self) -> bool {
383 let df = self.get_inner();
384 df.is_zero()
385 }
386 fn is_infinite(&self) -> bool {
388 let df = self.get_inner();
389 df.is_infinite()
390 }
391 fn is_nan(&self) -> bool {
393 let df = self.get_inner();
394 df.is_nan()
395 }
396 fn is_non_zero(&self) -> bool {
398 let df = self.get_inner();
399 df.is_non_zero()
400 }
401 fn is_finite_non_zero(&self) -> bool {
403 let df = self.get_inner();
404 df.is_finite_non_zero()
405 }
406 fn is_pos_zero(&self) -> bool {
408 let df = self.get_inner();
409 df.is_pos_zero()
410 }
411 fn is_neg_zero(&self) -> bool {
413 let df = self.get_inner();
414 df.is_neg_zero()
415 }
416 fn is_pos_infinity(&self) -> bool {
418 let df = self.get_inner();
419 df.is_pos_infinity()
420 }
421 fn is_neg_infinity(&self) -> bool {
423 let df = self.get_inner();
424 df.is_neg_infinity()
425 }
426 fn is_smallest(&self) -> bool {
428 let df = self.get_inner();
429 df.is_smallest()
430 }
431 fn is_smallest_normalized(&self) -> bool {
433 let df = self.get_inner();
434 df.is_smallest_normalized()
435 }
436 fn is_largest(&self) -> bool {
438 let df = self.get_inner();
439 df.is_largest()
440 }
441 fn is_integer(&self) -> bool {
443 let df = self.get_inner();
444 df.is_integer()
445 }
446 fn scalbn(&self, n: ExpInt) -> Box<dyn FloatAttr> {
448 let df = self.get_inner();
449 let scalbn = df.scalbn(n);
450 self.build_from(scalbn)
451 }
452 fn frexp(&self, exp: &mut ExpInt) -> Box<dyn FloatAttr> {
454 let df = self.get_inner();
455 let frexp_r = df.frexp(exp);
456 self.build_from(frexp_r)
457 }
458
459 fn verify(_attr: &dyn Attribute, _ctx: &Context) -> Result<()>
460 where
461 Self: Sized,
462 {
463 Ok(())
464 }
465}
466
467#[attr_interface]
470pub trait MaterializableAttr: TypedAttrInterface {
471 fn materialize(&self, ctx: &mut Context) -> Ptr<Operation>;
473
474 fn verify(_attr: &dyn Attribute, _ctx: &Context) -> Result<()>
475 where
476 Self: Sized,
477 {
478 Ok(())
479 }
480}
481
482#[cfg(test)]
483mod tests {
484 use core::str::FromStr;
485
486 use rustc_apfloat::ieee::Single;
487
488 use super::*;
489 use crate::builtin::attributes::FPSingleAttr;
490
491 #[test]
492 fn test_float_attr_give_build_qnan_neg() {
493 let attr = FPSingleAttr(Single::from_str("1.0").unwrap());
494
495 let qnan = attr.build_qnan(Some(42));
496 assert!(qnan.get_inner().is_nan());
497
498 let neg = attr.neg();
499 assert!(
500 (&*neg as &dyn Attribute)
501 .downcast_ref::<FPSingleAttr>()
502 .unwrap()
503 != &attr
504 );
505 let neg_neg = neg.neg();
506 assert!(
507 (&*neg_neg as &dyn Attribute)
508 .downcast_ref::<FPSingleAttr>()
509 .is_some_and(|n| n == &attr)
510 );
511 }
512}