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)
89 #[fields_ty = LocFields]
90 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
94 pub reg_len: NonZeroU32,
99 pub const fn ty(self) -> Result<Ty> {
101 base_ty: self.kind.base_ty(),
102 reg_len: self.reg_len,
105 pub const fn stop(self) -> NonZeroU32 {
106 const_unwrap_opt!(self.reg_len.checked_add(self.start), "overflow")
111 pub const fn ty(self) -> Ty {
112 const_unwrap_res!(self.0.ty(), "Loc can only be constructed with valid fields")
114 pub const fn max_start(kind: LocKind, reg_len: NonZeroU32) -> Result<u32, Error> {
116 const_try!(Ty::new(TyFields {
117 base_ty: kind.base_ty(),
120 let loc_count: u32 = kind.loc_count().get();
121 let Some(max_start) = loc_count.checked_sub(reg_len.get()) else {
122 return Err(Error::InvalidRegLen)
126 pub const fn new(fields: LocFields) -> Result<Loc> {
133 if start > const_try!(Self::max_start(kind, reg_len)) {
134 Err(Error::StartNotInValidRange)
139 pub const fn conflicts(self, other: Loc) -> bool {
140 self.0.kind.const_eq(other.0.kind)
141 && self.0.start < other.0.stop().get()
142 && other.0.start < self.0.stop().get()
144 pub const fn get_sub_loc_at_offset(self, sub_loc_ty: Ty, offset: u32) -> Result<Self> {
145 if !sub_loc_ty.get().base_ty.const_eq(self.get().kind.base_ty()) {
146 return Err(Error::BaseTyMismatch);
148 let Some(stop) = sub_loc_ty.get().reg_len.checked_add(offset) else {
149 return Err(Error::InvalidSubLocOutOfRange)
151 if stop.get() > self.get().reg_len.get() {
152 Err(Error::InvalidSubLocOutOfRange)
154 Self::new(LocFields {
155 kind: self.get().kind,
156 start: self.get().start + offset,
157 reg_len: sub_loc_ty.get().reg_len,
161 /// get the Loc containing `self` such that:
162 /// `retval.get_sub_loc_at_offset(self.ty(), offset) == self`
163 /// and `retval.ty() == super_loc_ty`
164 pub const fn get_super_loc_with_self_at_offset(
172 .const_eq(self.get().kind.base_ty())
174 return Err(Error::BaseTyMismatch);
176 let Some(stop) = self.get().reg_len.checked_add(offset) else {
177 return Err(Error::InvalidSubLocOutOfRange)
179 if stop.get() > super_loc_ty.get().reg_len.get() {
180 Err(Error::InvalidSubLocOutOfRange)
182 Self::new(LocFields {
183 kind: self.get().kind,
184 start: self.get().start - offset,
185 reg_len: super_loc_ty.get().reg_len,
189 pub const SPECIAL_GPRS: &[Loc] = &[
193 reg_len: nzu32_lit!(1),
198 reg_len: nzu32_lit!(1),
203 reg_len: nzu32_lit!(1),
208 reg_len: nzu32_lit!(1),