1use pliron::{
8 combine::Parser,
9 context::Context,
10 derive::pliron_attr,
11 identifier::Identifier,
12 irfmt::parsers::delimited_list_parser,
13 parsable::{IntoParseResult, Parsable, ParseResult, StateStream, StreamLocation},
14 printable::{self, Printable},
15};
16use std::fmt;
17
18mod enums;
19pub use enums::{EnumParseError, EnumValueError};
20
21#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
26#[repr(u32)]
27pub enum CmpFPredicate {
28 AlwaysFalse = 0,
30 Oeq = 1,
32 Ogt = 2,
34 Oge = 3,
36 Olt = 4,
38 Ole = 5,
40 One = 6,
42 Ord = 7,
44 Ueq = 8,
46 Ugt = 9,
48 Uge = 10,
50 Ult = 11,
52 Ule = 12,
54 Une = 13,
56 Uno = 14,
58 AlwaysTrue = 15,
60}
61
62#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
64#[repr(u32)]
65pub enum CmpIPredicate {
66 Eq = 0,
68 Ne = 1,
70 Slt = 2,
72 Sle = 3,
74 Sgt = 4,
76 Sge = 5,
78 Ult = 6,
80 Ule = 7,
82 Ugt = 8,
84 Uge = 9,
86}
87
88#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
92#[repr(u32)]
93pub enum RoundingMode {
94 ToNearestEven = 0,
96 Downward = 1,
98 Upward = 2,
100 TowardZero = 3,
102 ToNearestAway = 4,
104}
105
106#[pliron_attr(name = "arith.roundingmode", format = "$value", verifier = "succ")]
109#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
110pub struct RoundingModeAttr {
111 pub value: RoundingMode,
113}
114
115impl RoundingModeAttr {
116 pub const fn new(value: RoundingMode) -> Self {
118 Self { value }
119 }
120}
121
122#[pliron_attr(name = "arith.cmpf_predicate", format = "$value", verifier = "succ")]
124#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
125pub struct CmpFPredicateAttr {
126 pub value: CmpFPredicate,
128}
129
130impl CmpFPredicateAttr {
131 pub const fn new(value: CmpFPredicate) -> Self {
133 Self { value }
134 }
135}
136
137#[pliron_attr(name = "arith.cmpi_predicate", format = "$value", verifier = "succ")]
139#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
140pub struct CmpIPredicateAttr {
141 pub value: CmpIPredicate,
143}
144
145impl CmpIPredicateAttr {
146 pub const fn new(value: CmpIPredicate) -> Self {
148 Self { value }
149 }
150}
151
152macro_rules! flag_set {
153 (
154 $(#[$meta:meta])*
155 $type:ident, $name:literal, $separator:literal, $all:expr,
156 { $($(#[$fmeta:meta])* $flag:ident = $bit:literal => $spelling:literal),+ $(,)? }
157 ) => {
158 $(#[$meta])*
159 #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
160 pub struct $type {
161 bits: u8,
162 }
163
164 impl $type {
165 pub const NAME: &'static str = $name;
167 pub const NONE: Self = Self { bits: 0 };
169 $(
170 $(#[$fmeta])*
171 pub const $flag: Self = Self { bits: $bit };
172 )+
173 const ALL_BITS: u8 = $all;
174
175 pub const fn bits(self) -> u8 {
177 self.bits
178 }
179
180 pub const fn from_bits(bits: u8) -> Option<Self> {
182 if bits & !Self::ALL_BITS == 0 {
183 Some(Self { bits })
184 } else {
185 None
186 }
187 }
188
189 pub const fn is_none(self) -> bool {
191 self.bits == 0
192 }
193
194 pub const fn contains(self, other: Self) -> bool {
196 self.bits & other.bits == other.bits
197 }
198
199 #[must_use]
201 pub const fn union(self, other: Self) -> Self {
202 Self { bits: self.bits | other.bits }
203 }
204
205 fn names(self) -> Vec<&'static str> {
206 let mut names = Vec::new();
207 $(
208 if self.contains(Self::$flag) {
209 names.push($spelling);
210 }
211 )+
212 names
213 }
214
215 pub fn mlir_spelling(self) -> String {
217 if self.is_none() {
218 "none".to_owned()
219 } else {
220 self.names().join($separator)
221 }
222 }
223
224 fn from_name(name: &str) -> Result<Self, EnumParseError> {
225 match name {
226 "none" => Ok(Self::NONE),
227 $($spelling => Ok(Self::$flag),)+
228 _ => Err(EnumParseError {
229 enum_name: $name,
230 spelling: name.to_owned(),
231 }),
232 }
233 }
234 }
235
236 impl std::ops::BitOr for $type {
237 type Output = Self;
238
239 fn bitor(self, rhs: Self) -> Self {
240 self.union(rhs)
241 }
242 }
243
244 impl fmt::Display for $type {
245 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
246 formatter.write_str(&self.mlir_spelling())
247 }
248 }
249
250 impl Printable for $type {
251 fn fmt(
252 &self,
253 _: &Context,
254 _: &printable::State,
255 formatter: &mut fmt::Formatter<'_>,
256 ) -> fmt::Result {
257 let names = if self.is_none() { vec!["none"] } else { self.names() };
258 write!(formatter, "<{}>", names.join(","))
259 }
260 }
261
262 impl Parsable for $type {
263 type Arg = ();
264 type Parsed = Self;
265
266 fn parse<'a>(
267 state_stream: &mut StateStream<'a>,
268 _: Self::Arg,
269 ) -> ParseResult<'a, Self::Parsed> {
270 let loc = state_stream.loc();
271 let names = delimited_list_parser('<', '>', ',', Identifier::parser(()))
272 .parse_stream(state_stream)
273 .into_result()?
274 .0;
275 let mut flags = Self::NONE;
276 for name in names {
277 match Self::from_name(&name.to_string()) {
278 Ok(flag) => flags = flags.union(flag),
279 Err(error) => return pliron::input_err!(loc, error).into_parse_result(),
280 }
281 }
282 Ok(flags).into_parse_result()
283 }
284 }
285 };
286}
287
288flag_set!(
289 FastMathFlags, "fastmath", ",", 0x7f, {
293 REASSOC = 1 => "reassoc",
295 NNAN = 2 => "nnan",
297 NINF = 4 => "ninf",
299 NSZ = 8 => "nsz",
301 ARCP = 16 => "arcp",
303 CONTRACT = 32 => "contract",
305 AFN = 64 => "afn",
307 }
308);
309
310impl FastMathFlags {
311 pub const FAST: Self = Self { bits: 0x7f };
313}
314
315flag_set!(
316 IntegerOverflowFlags, "overflow", ", ", 0x3, {
320 NSW = 1 => "nsw",
322 NUW = 2 => "nuw",
324 }
325);
326
327#[pliron_attr(name = "arith.fastmath", format = "$value", verifier = "succ")]
329#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
330pub struct FastMathFlagsAttr {
331 pub value: FastMathFlags,
333}
334
335impl FastMathFlagsAttr {
336 pub const fn new(value: FastMathFlags) -> Self {
338 Self { value }
339 }
340}
341
342#[pliron_attr(name = "arith.overflow", format = "$value", verifier = "succ")]
344#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
345pub struct IntegerOverflowFlagsAttr {
346 pub value: IntegerOverflowFlags,
348}
349
350impl IntegerOverflowFlagsAttr {
351 pub const fn new(value: IntegerOverflowFlags) -> Self {
353 Self { value }
354 }
355}