1 use crate::error::{Error, Result};
3 use serde::{Deserialize, Serialize};
4 use std::num::NonZeroU32;
7 Serialize, Deserialize, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash, Enum,
18 /// since `==` doesn't work with enums in const context
19 pub const fn const_eq(self, other: Self) -> bool {
20 self as u8 == other as u8
22 pub const fn base_ty(self) -> BaseTy {
24 Self::Gpr | Self::StackBits64 => BaseTy::Bits64,
25 Self::Ca => BaseTy::Ca,
26 Self::VlMaxvl => BaseTy::VlMaxvl,
30 pub const fn loc_count(self) -> NonZeroU32 {
32 Self::StackBits64 => nzu32_lit!(512),
33 Self::Gpr | Self::Ca | Self::VlMaxvl => self.base_ty().max_reg_len(),
39 Serialize, Deserialize, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash, Enum,
49 /// since `==` doesn't work with enums in const context
50 pub const fn const_eq(self, other: Self) -> bool {
51 self as u8 == other as u8
54 pub const fn only_scalar(self) -> bool {
55 self.max_reg_len().get() == 1
58 pub const fn max_reg_len(self) -> NonZeroU32 {
60 Self::Bits64 => nzu32_lit!(128),
61 Self::Ca | Self::VlMaxvl => nzu32_lit!(1),
67 #[fields_ty = TyFields]
68 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
71 pub reg_len: NonZeroU32,
76 pub const fn new(fields: TyFields) -> Result<Ty> {
77 let TyFields { base_ty, reg_len } = fields;
78 if base_ty.only_scalar() && reg_len.get() != 1 {
79 Err(Error::TriedToCreateVectorOfOnlyScalarType { base_ty })
80 } else if reg_len.get() > base_ty.max_reg_len().get() {
81 Err(Error::RegLenOutOfRange)
86 /// returns the `Ty` for `fields` or if there was an error, returns the corresponding scalar type (where `reg_len` is `1`)
87 pub const fn new_or_scalar(fields: TyFields) -> Self {
88 match Self::new(fields) {
90 Err(_) => Self::scalar(fields.base_ty),
93 pub const fn scalar(base_ty: BaseTy) -> Self {
96 reg_len: nzu32_lit!(1),
99 pub const fn bits64(reg_len: NonZeroU32) -> Self {
101 base_ty: BaseTy::Bits64,
105 pub const fn try_concat(self, rhs: Self) -> Result<Ty> {
106 if !self.get().base_ty.const_eq(rhs.get().base_ty) {
107 Err(Error::BaseTyMismatch)
109 let Some(reg_len) = self.get().reg_len.checked_add(rhs.get().reg_len.get()) else {
110 return Err(Error::RegLenOutOfRange);
113 base_ty: self.get().base_ty,
121 #[fields_ty = LocFields]
122 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
126 pub reg_len: NonZeroU32,
131 pub const fn ty(self) -> Result<Ty> {
133 base_ty: self.kind.base_ty(),
134 reg_len: self.reg_len,
137 pub const fn stop(self) -> NonZeroU32 {
138 const_unwrap_opt!(self.reg_len.checked_add(self.start), "overflow")
143 pub const fn ty(self) -> Ty {
144 const_unwrap_res!(self.0.ty(), "Loc can only be constructed with valid fields")
146 pub const fn max_start(kind: LocKind, reg_len: NonZeroU32) -> Result<u32, Error> {
148 const_try!(Ty::new(TyFields {
149 base_ty: kind.base_ty(),
152 let loc_count: u32 = kind.loc_count().get();
153 let Some(max_start) = loc_count.checked_sub(reg_len.get()) else {
154 return Err(Error::InvalidRegLen)
158 pub const fn new(fields: LocFields) -> Result<Loc> {
165 if start > const_try!(Self::max_start(kind, reg_len)) {
166 Err(Error::StartNotInValidRange)
171 pub const fn conflicts(self, other: Loc) -> bool {
172 self.0.kind.const_eq(other.0.kind)
173 && self.0.start < other.0.stop().get()
174 && other.0.start < self.0.stop().get()
176 pub const fn get_sub_loc_at_offset(self, sub_loc_ty: Ty, offset: u32) -> Result<Self> {
177 if !sub_loc_ty.get().base_ty.const_eq(self.get().kind.base_ty()) {
178 return Err(Error::BaseTyMismatch);
180 let Some(stop) = sub_loc_ty.get().reg_len.checked_add(offset) else {
181 return Err(Error::InvalidSubLocOutOfRange)
183 if stop.get() > self.get().reg_len.get() {
184 Err(Error::InvalidSubLocOutOfRange)
186 Self::new(LocFields {
187 kind: self.get().kind,
188 start: self.get().start + offset,
189 reg_len: sub_loc_ty.get().reg_len,
193 /// get the Loc containing `self` such that:
194 /// `retval.get_sub_loc_at_offset(self.ty(), offset) == self`
195 /// and `retval.ty() == super_loc_ty`
196 pub const fn get_super_loc_with_self_at_offset(
204 .const_eq(self.get().kind.base_ty())
206 return Err(Error::BaseTyMismatch);
208 let Some(stop) = self.get().reg_len.checked_add(offset) else {
209 return Err(Error::InvalidSubLocOutOfRange)
211 if stop.get() > super_loc_ty.get().reg_len.get() {
212 Err(Error::InvalidSubLocOutOfRange)
214 Self::new(LocFields {
215 kind: self.get().kind,
216 start: self.get().start - offset,
217 reg_len: super_loc_ty.get().reg_len,
221 pub const SPECIAL_GPRS: &[Loc] = &[
225 reg_len: nzu32_lit!(1),
230 reg_len: nzu32_lit!(1),
235 reg_len: nzu32_lit!(1),
240 reg_len: nzu32_lit!(1),