use pliron::{
combine::Parser,
context::Context,
derive::pliron_attr,
identifier::Identifier,
irfmt::parsers::delimited_list_parser,
parsable::{IntoParseResult, Parsable, ParseResult, StateStream, StreamLocation},
printable::{self, Printable},
};
use std::fmt;
mod enums;
pub use enums::{EnumParseError, EnumValueError};
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
#[repr(u32)]
pub enum CmpFPredicate {
AlwaysFalse = 0,
Oeq = 1,
Ogt = 2,
Oge = 3,
Olt = 4,
Ole = 5,
One = 6,
Ord = 7,
Ueq = 8,
Ugt = 9,
Uge = 10,
Ult = 11,
Ule = 12,
Une = 13,
Uno = 14,
AlwaysTrue = 15,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
#[repr(u32)]
pub enum CmpIPredicate {
Eq = 0,
Ne = 1,
Slt = 2,
Sle = 3,
Sgt = 4,
Sge = 5,
Ult = 6,
Ule = 7,
Ugt = 8,
Uge = 9,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
#[repr(u32)]
pub enum RoundingMode {
ToNearestEven = 0,
Downward = 1,
Upward = 2,
TowardZero = 3,
ToNearestAway = 4,
}
#[pliron_attr(name = "arith.roundingmode", format = "$value", verifier = "succ")]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct RoundingModeAttr {
pub value: RoundingMode,
}
impl RoundingModeAttr {
pub const fn new(value: RoundingMode) -> Self {
Self { value }
}
}
#[pliron_attr(name = "arith.cmpf_predicate", format = "$value", verifier = "succ")]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct CmpFPredicateAttr {
pub value: CmpFPredicate,
}
impl CmpFPredicateAttr {
pub const fn new(value: CmpFPredicate) -> Self {
Self { value }
}
}
#[pliron_attr(name = "arith.cmpi_predicate", format = "$value", verifier = "succ")]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct CmpIPredicateAttr {
pub value: CmpIPredicate,
}
impl CmpIPredicateAttr {
pub const fn new(value: CmpIPredicate) -> Self {
Self { value }
}
}
macro_rules! flag_set {
(
$(#[$meta:meta])*
$type:ident, $name:literal, $separator:literal, $all:expr,
{ $($(#[$fmeta:meta])* $flag:ident = $bit:literal => $spelling:literal),+ $(,)? }
) => {
$(#[$meta])*
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
pub struct $type {
bits: u8,
}
impl $type {
pub const NAME: &'static str = $name;
pub const NONE: Self = Self { bits: 0 };
$(
$(#[$fmeta])*
pub const $flag: Self = Self { bits: $bit };
)+
const ALL_BITS: u8 = $all;
pub const fn bits(self) -> u8 {
self.bits
}
pub const fn from_bits(bits: u8) -> Option<Self> {
if bits & !Self::ALL_BITS == 0 {
Some(Self { bits })
} else {
None
}
}
pub const fn is_none(self) -> bool {
self.bits == 0
}
pub const fn contains(self, other: Self) -> bool {
self.bits & other.bits == other.bits
}
#[must_use]
pub const fn union(self, other: Self) -> Self {
Self { bits: self.bits | other.bits }
}
fn names(self) -> Vec<&'static str> {
let mut names = Vec::new();
$(
if self.contains(Self::$flag) {
names.push($spelling);
}
)+
names
}
pub fn mlir_spelling(self) -> String {
if self.is_none() {
"none".to_owned()
} else {
self.names().join($separator)
}
}
fn from_name(name: &str) -> Result<Self, EnumParseError> {
match name {
"none" => Ok(Self::NONE),
$($spelling => Ok(Self::$flag),)+
_ => Err(EnumParseError {
enum_name: $name,
spelling: name.to_owned(),
}),
}
}
}
impl std::ops::BitOr for $type {
type Output = Self;
fn bitor(self, rhs: Self) -> Self {
self.union(rhs)
}
}
impl fmt::Display for $type {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str(&self.mlir_spelling())
}
}
impl Printable for $type {
fn fmt(
&self,
_: &Context,
_: &printable::State,
formatter: &mut fmt::Formatter<'_>,
) -> fmt::Result {
let names = if self.is_none() { vec!["none"] } else { self.names() };
write!(formatter, "<{}>", names.join(","))
}
}
impl Parsable for $type {
type Arg = ();
type Parsed = Self;
fn parse<'a>(
state_stream: &mut StateStream<'a>,
_: Self::Arg,
) -> ParseResult<'a, Self::Parsed> {
let loc = state_stream.loc();
let names = delimited_list_parser('<', '>', ',', Identifier::parser(()))
.parse_stream(state_stream)
.into_result()?
.0;
let mut flags = Self::NONE;
for name in names {
match Self::from_name(&name.to_string()) {
Ok(flag) => flags = flags.union(flag),
Err(error) => return pliron::input_err!(loc, error).into_parse_result(),
}
}
Ok(flags).into_parse_result()
}
}
};
}
flag_set!(
FastMathFlags, "fastmath", ",", 0x7f, {
REASSOC = 1 => "reassoc",
NNAN = 2 => "nnan",
NINF = 4 => "ninf",
NSZ = 8 => "nsz",
ARCP = 16 => "arcp",
CONTRACT = 32 => "contract",
AFN = 64 => "afn",
}
);
impl FastMathFlags {
pub const FAST: Self = Self { bits: 0x7f };
}
flag_set!(
IntegerOverflowFlags, "overflow", ", ", 0x3, {
NSW = 1 => "nsw",
NUW = 2 => "nuw",
}
);
#[pliron_attr(name = "arith.fastmath", format = "$value", verifier = "succ")]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct FastMathFlagsAttr {
pub value: FastMathFlags,
}
impl FastMathFlagsAttr {
pub const fn new(value: FastMathFlags) -> Self {
Self { value }
}
}
#[pliron_attr(name = "arith.overflow", format = "$value", verifier = "succ")]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct IntegerOverflowFlagsAttr {
pub value: IntegerOverflowFlags,
}
impl IntegerOverflowFlagsAttr {
pub const fn new(value: IntegerOverflowFlags) -> Self {
Self { value }
}
}