Skip to main content

pliron/builtin/
attr_interfaces.rs

1// SPDX-License-Identifier: Apache-2.0
2// Copyright (c) The pliron contributors
3
4use 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/// [Attribute]s that have an associated [Type](crate::type::Type).
18/// This serves the same purpose as MLIR's `TypedAttrInterface`.
19#[attr_interface]
20pub trait TypedAttrInterface {
21    /// Get this attribute's type.
22    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/// [Attribute]s that should be printed after the top level [Operation](crate::operation::Operation)
33/// is printed. An [Op](crate::op::Op) may choose to print such an attribute as part of its
34/// syntax specification. This will be unknown to the outline attributes printer and will be
35/// printed nevertheless while printing all outline attributes.
36#[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/// [Attribute]s that should be printed only once, and some form of "reference" to be
47/// used for repeated printing. These must be outlined attributes.
48#[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/// [Attribute]s that represent a floating point value.
59///
60/// This trait provides operations on floating point values
61/// from the [DynFloat] trait.
62///
63/// The `build_*` methods can be used to construct a new [FloatAttr]
64/// with the same type as the argument. This can be useful when doing
65/// folding optimizations, where we have some dyn instance and want to build
66/// another one of the same type but with a different value.
67/// The `self` argument is ignored in these methods. In the absense of
68/// of an object (but when the concrete type is known), then the static (`Self: Sized`)
69/// methods on the [Float](rustc_apfloat::Float) trait can be used instead.
70#[attr_interface]
71pub trait FloatAttr: TypedAttrInterface {
72    /// Get the underlying floating point value as a [DynFloat] trait object.
73    fn get_inner(&self) -> &dyn DynFloat;
74    /// Build a [FloatAttr] with the same concrete type as `Self`, from the given trait object.
75    fn build_from(&self, df: Box<dyn DynFloat>) -> Box<dyn FloatAttr>;
76    /// Get semantics of the underlying floating point type.
77    fn get_semantics(&self) -> Semantics;
78    /// Static version of `get_semantics`.
79    fn get_semantics_static() -> Semantics
80    where
81        Self: Sized;
82
83    /// [Float::qnan](rustc_apfloat::Float::qnan), `self` is ignored
84    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    /// [Float::snan](rustc_apfloat::Float::snan), `self` is ignored
90    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    /// [Float::largest](rustc_apfloat::Float::largest), `self` is ignored
96    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    /// [Float::smallest_normalized](rustc_apfloat::Float::smallest_normalized), `self` is ignored
102    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    /// [Float::from_bits](rustc_apfloat::Float::from_bits), `self` is ignored
108    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    /// [Float::from_u128_r](rustc_apfloat::Float::from_u128_r), `self` is ignored
114    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    /// [Float::from_str_r](rustc_apfloat::Float::from_str_r), `self` is ignored
120    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    /// [Float::from_i128_r](rustc_apfloat::Float::from_i128_r), `self` is ignored
126    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    /// [Float::from_i128](rustc_apfloat::Float::from_i128), `self` is ignored
132    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    /// [Float::from_u128](rustc_apfloat::Float::from_u128), `self` is ignored
138    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    /// [Neg::neg](core::ops::Neg::neg)
145    fn neg(&self) -> Box<dyn FloatAttr> {
146        let df = self.get_inner();
147        let negated = df.neg();
148        self.build_from(negated)
149    }
150    /// [Add::add](core::ops::Add::add)
151    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    /// [Sub::sub](core::ops::Sub::sub)
157    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    /// [Mul::mul](core::ops::Mul::mul)
163    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    /// [Div::div](core::ops::Div::div)
169    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    /// [Rem::rem](core::ops::Rem::rem)
175    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    /// [Float::add_r](rustc_apfloat::Float::add_r)
181    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    /// [Float::mul_r](rustc_apfloat::Float::mul_r)
187    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    /// [Float::mul_add_r](rustc_apfloat::Float::mul_add_r)
193    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    /// [Float::div_r](rustc_apfloat::Float::div_r)
206    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    /// [Float::ieee_rem](rustc_apfloat::Float::ieee_rem)
212    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    /// [Float::c_fmod](rustc_apfloat::Float::c_fmod)
219    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    /// [Float::round_to_integral](rustc_apfloat::Float::round_to_integral)
225    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    /// [Float::next_up](rustc_apfloat::Float::next_up)
231    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    /// [Float::to_bits](rustc_apfloat::Float::to_bits)
236    fn to_bits(&self) -> u128 {
237        let df = self.get_inner();
238        df.to_bits()
239    }
240    /// [Float::to_u128_r](rustc_apfloat::Float::to_u128_r)
241    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    /// [Float::cmp_abs_normal](rustc_apfloat::Float::cmp_abs_normal)
246    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    /// [Float::bitwise_eq](rustc_apfloat::Float::bitwise_eq)
251    fn bitwise_eq(&self, other: &dyn FloatAttr) -> bool {
252        let df = self.get_inner();
253        df.bitwise_eq(other.get_inner())
254    }
255    /// [Float::is_negative](rustc_apfloat::Float::is_negative)
256    fn is_negative(&self) -> bool {
257        let df = self.get_inner();
258        df.is_negative()
259    }
260    /// [Float::is_denormal](rustc_apfloat::Float::is_denormal)
261    fn is_denormal(&self) -> bool {
262        let df = self.get_inner();
263        df.is_denormal()
264    }
265    /// [Float::is_signaling](rustc_apfloat::Float::is_signaling)
266    fn is_signaling(&self) -> bool {
267        let df = self.get_inner();
268        df.is_signaling()
269    }
270    /// [Float::category](rustc_apfloat::Float::category)
271    fn category(&self) -> Category {
272        let df = self.get_inner();
273        df.category()
274    }
275    /// [Float::get_exact_inverse](rustc_apfloat::Float::get_exact_inverse)
276    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    /// [Float::ilogb](rustc_apfloat::Float::ilogb)
282    fn ilogb(&self) -> ExpInt {
283        let df = self.get_inner();
284        df.ilogb()
285    }
286    /// [Float::scalbn_r](rustc_apfloat::Float::scalbn_r)
287    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    /// [Float::frexp_r](rustc_apfloat::Float::frexp_r)
292    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    /// [Float::sub_r](rustc_apfloat::Float::sub_r)
298    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    /// [Float::mul_add](rustc_apfloat::Float::mul_add)
304    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    /// [Float::next_down](rustc_apfloat::Float::next_down)
316    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    /// [Float::abs](rustc_apfloat::Float::abs)
321    fn abs(&self) -> Box<dyn FloatAttr> {
322        let df = self.get_inner();
323        let abs = df.abs();
324        self.build_from(abs)
325    }
326    /// [Float::copy_sign](rustc_apfloat::Float::copy_sign)
327    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    /// [Float::to_i128_r](rustc_apfloat::Float::to_i128_r)
333    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    /// [Float::to_i128](rustc_apfloat::Float::to_i128)
338    fn to_i128(&self, width: usize) -> StatusAnd<i128> {
339        let df = self.get_inner();
340        df.to_i128(width)
341    }
342    /// [Float::to_u128](rustc_apfloat::Float::to_u128)
343    fn to_u128(&self, width: usize) -> StatusAnd<u128> {
344        let df = self.get_inner();
345        df.to_u128(width)
346    }
347    /// [Float::min](rustc_apfloat::Float::min)
348    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    /// [Float::max](rustc_apfloat::Float::max)
354    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    /// [Float::minimum](rustc_apfloat::Float::minimum)
360    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    /// [Float::maximum](rustc_apfloat::Float::maximum)
366    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    /// [Float::is_normal](rustc_apfloat::Float::is_normal)
372    fn is_normal(&self) -> bool {
373        let df = self.get_inner();
374        df.is_normal()
375    }
376    /// [Float::is_finite](rustc_apfloat::Float::is_finite)
377    fn is_finite(&self) -> bool {
378        let df = self.get_inner();
379        df.is_finite()
380    }
381    /// [Float::is_zero](rustc_apfloat::Float::is_zero)
382    fn is_zero(&self) -> bool {
383        let df = self.get_inner();
384        df.is_zero()
385    }
386    /// [Float::is_infinite](rustc_apfloat::Float::is_infinite)
387    fn is_infinite(&self) -> bool {
388        let df = self.get_inner();
389        df.is_infinite()
390    }
391    /// [Float::is_nan](rustc_apfloat::Float::is_nan)
392    fn is_nan(&self) -> bool {
393        let df = self.get_inner();
394        df.is_nan()
395    }
396    /// [Float::is_non_zero](rustc_apfloat::Float::is_non_zero)
397    fn is_non_zero(&self) -> bool {
398        let df = self.get_inner();
399        df.is_non_zero()
400    }
401    /// [Float::is_finite_non_zero](rustc_apfloat::Float::is_finite_non_zero)
402    fn is_finite_non_zero(&self) -> bool {
403        let df = self.get_inner();
404        df.is_finite_non_zero()
405    }
406    /// [Float::is_pos_zero](rustc_apfloat::Float::is_pos_zero)
407    fn is_pos_zero(&self) -> bool {
408        let df = self.get_inner();
409        df.is_pos_zero()
410    }
411    /// [Float::is_neg_zero](rustc_apfloat::Float::is_neg_zero)
412    fn is_neg_zero(&self) -> bool {
413        let df = self.get_inner();
414        df.is_neg_zero()
415    }
416    /// [Float::is_pos_infinity](rustc_apfloat::Float::is_pos_infinity)
417    fn is_pos_infinity(&self) -> bool {
418        let df = self.get_inner();
419        df.is_pos_infinity()
420    }
421    /// [Float::is_neg_infinity](rustc_apfloat::Float::is_neg_infinity)
422    fn is_neg_infinity(&self) -> bool {
423        let df = self.get_inner();
424        df.is_neg_infinity()
425    }
426    /// [Float::is_smallest](rustc_apfloat::Float::is_smallest)
427    fn is_smallest(&self) -> bool {
428        let df = self.get_inner();
429        df.is_smallest()
430    }
431    /// [Float::is_smallest_normalized](rustc_apfloat::Float::is_smallest_normalized)
432    fn is_smallest_normalized(&self) -> bool {
433        let df = self.get_inner();
434        df.is_smallest_normalized()
435    }
436    /// [Float::is_largest](rustc_apfloat::Float::is_largest)
437    fn is_largest(&self) -> bool {
438        let df = self.get_inner();
439        df.is_largest()
440    }
441    /// [Float::is_integer](rustc_apfloat::Float::is_integer)
442    fn is_integer(&self) -> bool {
443        let df = self.get_inner();
444        df.is_integer()
445    }
446    /// [Float::scalbn](rustc_apfloat::Float::scalbn)
447    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    /// [Float::frexp](rustc_apfloat::Float::frexp)
453    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/// [Attribute]s for which we can generate pliron code to store the attribute value
468/// into an pliron value
469#[attr_interface]
470pub trait MaterializableAttr: TypedAttrInterface {
471    /// Returns an operation that assigns a materialization of `self` to some result
472    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}