1use super::TrapCode;
4use crate::HashMap;
5use crate::entity::{self, PrimaryMap};
6pub use crate::machinst::MachMemFlags;
7use alloc::borrow::Cow;
8use core::fmt;
9use core::hash::{Hash, Hasher};
10use core::ops::Index;
11use core::str::FromStr;
12use cranelift_entity::{entity_impl, packed_option::PackedOption};
13
14#[cfg(feature = "enable-serde")]
15use serde_derive::{Deserialize, Serialize};
16
17#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
19pub enum Endianness {
20 Little,
22 Big,
24}
25
26#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
31#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
32pub struct AliasRegion(u32);
33entity_impl!(AliasRegion, "region");
34
35#[derive(Clone, Debug, PartialEq, Eq, Hash)]
37#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
38pub struct AliasRegionData {
39 pub user_id: u32,
49
50 pub description: Cow<'static, str>,
55}
56
57#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
64#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
65pub struct MemFlags(u16);
66
67impl MemFlags {
68 pub fn with_number(n: u32) -> Option<Self> {
72 let val = u16::try_from(n).ok()?;
73 if val == u16::MAX {
74 None
75 } else {
76 Some(Self(val))
77 }
78 }
79}
80
81impl entity::EntityRef for MemFlags {
82 #[inline]
83 fn new(index: usize) -> Self {
84 let val = u16::try_from(index).expect("MemFlags index overflow");
85 Self(val)
86 }
87
88 #[inline]
89 fn index(self) -> usize {
90 usize::from(self.0)
91 }
92}
93
94impl entity::packed_option::ReservedValue for MemFlags {
95 #[inline]
96 fn reserved_value() -> Self {
97 Self(u16::MAX)
98 }
99
100 #[inline]
101 fn is_reserved_value(&self) -> bool {
102 self.0 == u16::MAX
103 }
104}
105
106impl MemFlags {
107 #[inline]
109 pub fn from_u32(x: u32) -> Self {
110 Self(u16::try_from(x).unwrap())
111 }
112
113 #[inline]
115 pub fn as_u32(self) -> u32 {
116 u32::from(self.0)
117 }
118
119 #[inline]
121 pub fn as_bits(self) -> u32 {
122 u32::from(self.0)
123 }
124
125 #[inline]
127 pub fn from_bits(x: u32) -> Self {
128 Self(u16::try_from(x).unwrap())
129 }
130}
131
132impl fmt::Display for MemFlags {
133 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
134 write!(f, "memflags{}", self.0)
135 }
136}
137
138impl fmt::Debug for MemFlags {
139 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
140 (self as &dyn fmt::Display).fmt(f)
141 }
142}
143
144#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
155#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
156pub struct MemFlagsData {
157 flags: MachMemFlags,
159
160 region: PackedOption<AliasRegion>,
162}
163
164const fn no_alias_region() -> PackedOption<AliasRegion> {
165 PackedOption::new(AliasRegion(u32::MAX))
166}
167
168impl MemFlagsData {
169 pub const fn new() -> Self {
171 Self {
172 flags: MachMemFlags::new(),
173 region: no_alias_region(),
174 }
175 }
176
177 pub const fn trusted() -> Self {
180 Self::new().with_notrap().with_aligned(true)
181 }
182
183 pub fn alias_region(self) -> Option<AliasRegion> {
185 self.region.expand()
186 }
187
188 pub fn with_alias_region(mut self, region: Option<AliasRegion>) -> Self {
190 self.region = region.into();
191 self
192 }
193
194 pub fn set_alias_region(&mut self, region: Option<AliasRegion>) {
196 self.region = region.into();
197 }
198
199 pub fn set_by_name(&mut self, name: &str) -> Result<bool, &'static str> {
209 *self = match name {
210 "notrap" => self.with_trap_code(None),
211 "aligned" => self.with_aligned(true),
212 "readonly" => self.with_readonly(true),
213 "little" => {
214 if self.flags.explicit_endianness() == Some(Endianness::Big) {
215 return Err("cannot set both big and little endian bits");
216 }
217 self.with_endianness(Endianness::Little)
218 }
219 "big" => {
220 if self.flags.explicit_endianness() == Some(Endianness::Little) {
221 return Err("cannot set both big and little endian bits");
222 }
223 self.with_endianness(Endianness::Big)
224 }
225 "can_move" => self.with_can_move(true),
226 "volatile" => self.with_volatile(true),
227
228 other => match TrapCode::from_str(other) {
229 Ok(code) => self.with_trap_code(Some(code)),
230 Err(()) => return Ok(false),
231 },
232 };
233 Ok(true)
234 }
235
236 pub const fn endianness(self, native_endianness: Endianness) -> Endianness {
242 self.flags.endianness(native_endianness)
243 }
244
245 pub const fn explicit_endianness(self) -> Option<Endianness> {
250 self.flags.explicit_endianness()
251 }
252
253 pub fn set_endianness(&mut self, endianness: Endianness) {
255 *self = self.with_endianness(endianness);
256 }
257
258 pub const fn with_endianness(mut self, endianness: Endianness) -> Self {
260 self.flags = self.flags.with_endianness(endianness);
261 self
262 }
263
264 pub const fn notrap(self) -> bool {
281 self.trap_code().is_none()
282 }
283
284 pub fn set_notrap(&mut self) {
286 *self = self.with_notrap();
287 }
288
289 pub const fn with_notrap(self) -> Self {
292 self.with_trap_code(None)
293 }
294
295 pub const fn can_move(self) -> bool {
311 self.flags.can_move()
312 }
313
314 pub const fn set_can_move(&mut self, enabled: bool) {
316 *self = self.with_can_move(enabled);
317 }
318
319 pub const fn with_can_move(mut self, enabled: bool) -> Self {
321 self.flags = self.flags.with_can_move(enabled);
322 self
323 }
324
325 pub const fn aligned(self) -> bool {
331 self.flags.aligned()
332 }
333
334 pub fn set_aligned(&mut self, enabled: bool) {
336 *self = self.with_aligned(enabled);
337 }
338
339 pub const fn with_aligned(mut self, enabled: bool) -> Self {
341 self.flags = self.flags.with_aligned(enabled);
342 self
343 }
344
345 pub const fn readonly(self) -> bool {
356 self.flags.readonly()
357 }
358
359 pub fn set_readonly(&mut self, enabled: bool) {
361 *self = self.with_readonly(enabled);
362 }
363
364 pub const fn with_readonly(mut self, enabled: bool) -> Self {
366 self.flags = self.flags.with_readonly(enabled);
367 self
368 }
369
370 pub const fn volatile(self) -> bool {
384 self.flags.volatile()
385 }
386
387 pub fn set_volatile(&mut self, enabled: bool) {
389 *self = self.with_volatile(enabled);
390 }
391
392 pub const fn with_volatile(mut self, enabled: bool) -> Self {
394 self.flags = self.flags.with_volatile(enabled);
395 self
396 }
397
398 pub const fn trap_code(self) -> Option<TrapCode> {
402 self.flags.trap_code()
403 }
404
405 pub const fn with_trap_code(mut self, code: Option<TrapCode>) -> Self {
412 self.flags = self.flags.with_trap_code(code);
413 self
414 }
415}
416
417impl From<MemFlagsData> for MachMemFlags {
418 fn from(flags: MemFlagsData) -> Self {
419 flags.flags
420 }
421}
422
423impl From<MachMemFlags> for MemFlagsData {
424 fn from(flags: MachMemFlags) -> Self {
425 Self {
426 flags,
427 region: no_alias_region(),
428 }
429 }
430}
431
432impl fmt::Display for MemFlagsData {
433 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
434 write!(f, "{}", self.flags)?;
435 match self.alias_region() {
436 None => {}
437 Some(region) => write!(f, " {region}")?,
438 }
439 Ok(())
440 }
441}
442
443#[derive(Clone, Copy, Debug, PartialEq, Eq)]
444pub struct MemFlagsSetOverflow;
445
446#[derive(Clone, Debug)]
448#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
449pub struct MemFlagsSet {
450 mem_flags: PrimaryMap<MemFlags, MemFlagsData>,
451 dedupe_map: HashMap<MemFlagsData, MemFlags>,
452}
453
454impl PartialEq for MemFlagsSet {
455 fn eq(&self, other: &Self) -> bool {
456 self.mem_flags == other.mem_flags
457 }
458}
459
460impl Eq for MemFlagsSet {}
461
462impl Hash for MemFlagsSet {
463 fn hash<H: Hasher>(&self, state: &mut H) {
464 self.mem_flags.hash(state);
465 }
466}
467
468impl MemFlagsSet {
469 pub fn new() -> Self {
471 Self {
472 mem_flags: PrimaryMap::new(),
473 dedupe_map: HashMap::new(),
474 }
475 }
476
477 pub fn insert(&mut self, data: MemFlagsData) -> Result<MemFlags, MemFlagsSetOverflow> {
481 if let Some(&existing) = self.dedupe_map.get(&data) {
482 return Ok(existing);
483 }
484 let next = u32::try_from(self.mem_flags.len())
485 .ok()
486 .and_then(MemFlags::with_number)
487 .ok_or(MemFlagsSetOverflow)?;
488 let key = self.mem_flags.push(data);
489 debug_assert_eq!(key, next);
490 self.dedupe_map.insert(data, key);
491 Ok(key)
492 }
493
494 pub fn insert_unchecked(&mut self, data: MemFlagsData) -> MemFlags {
496 match self.insert(data) {
497 Ok(flags) => flags,
498 Err(_) => panic!("MemFlags index overflow"),
499 }
500 }
501
502 pub fn is_valid(&self, mf: MemFlags) -> bool {
504 self.mem_flags.is_valid(mf)
505 }
506
507 pub fn clear(&mut self) {
509 *self = Self::new();
510 }
511
512 pub fn get(&self, data: MemFlagsData) -> Option<MemFlags> {
514 self.dedupe_map.get(&data).copied()
515 }
516}
517
518impl Index<MemFlags> for MemFlagsSet {
521 type Output = MemFlagsData;
522
523 fn index(&self, mf: MemFlags) -> &MemFlagsData {
524 &self.mem_flags[mf]
525 }
526}
527
528#[derive(Clone, PartialEq)]
533#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
534pub struct AliasRegionSet {
535 alias_regions: PrimaryMap<AliasRegion, AliasRegionData>,
536 dedupe_map: HashMap<u32, AliasRegion>,
537}
538
539impl Hash for AliasRegionSet {
540 fn hash<H: Hasher>(&self, state: &mut H) {
541 self.alias_regions.hash(state);
542 }
543}
544
545impl AliasRegionSet {
546 pub fn new() -> Self {
548 Self {
549 alias_regions: PrimaryMap::new(),
550 dedupe_map: HashMap::new(),
551 }
552 }
553
554 pub fn insert(&mut self, data: AliasRegionData) -> AliasRegion {
559 if let Some(&existing) = self.dedupe_map.get(&data.user_id) {
560 return existing;
561 }
562 let user_id = data.user_id;
563 let key = self.alias_regions.push(data);
564 self.dedupe_map.insert(user_id, key);
565 key
566 }
567
568 pub fn push(&mut self, data: AliasRegionData) -> AliasRegion {
573 let user_id = data.user_id;
574 let key = self.alias_regions.push(data);
575 self.dedupe_map.insert(user_id, key);
576 key
577 }
578
579 pub fn contains(&self, user_id: u32) -> bool {
582 self.dedupe_map.contains_key(&user_id)
583 }
584
585 pub fn get(&self, user_id: u32) -> Option<AliasRegion> {
587 self.dedupe_map.get(&user_id).copied()
588 }
589
590 pub fn is_valid(&self, ar: AliasRegion) -> bool {
592 self.alias_regions.is_valid(ar)
593 }
594
595 pub fn len(&self) -> usize {
597 self.alias_regions.len()
598 }
599
600 pub fn iter(&self) -> impl Iterator<Item = (AliasRegion, &AliasRegionData)> {
602 self.alias_regions.iter()
603 }
604
605 pub fn clear(&mut self) {
607 self.alias_regions.clear();
608 self.dedupe_map.clear();
609 }
610}
611
612impl Index<AliasRegion> for AliasRegionSet {
615 type Output = AliasRegionData;
616
617 fn index(&self, ar: AliasRegion) -> &AliasRegionData {
618 &self.alias_regions[ar]
619 }
620}
621
622#[cfg(test)]
623mod tests {
624 use super::*;
625 use cranelift_entity::EntityRef;
626
627 #[test]
628 fn roundtrip_traps() {
629 for trap in TrapCode::non_user_traps().iter().copied() {
630 let _flags = MemFlagsData::new().with_trap_code(Some(trap));
631 }
632 let _flags = MemFlagsData::new().with_trap_code(None);
633 }
634
635 #[test]
636 fn cannot_set_big_and_little() {
637 let _big = MemFlagsData::new().with_endianness(Endianness::Big);
638
639 let _little = MemFlagsData::new().with_endianness(Endianness::Little);
640 }
641
642 #[test]
643 fn only_one_region() {
644 let region0 = AliasRegion::new(0);
645 let region1 = AliasRegion::new(1);
646 let flags = MemFlagsData::new().with_alias_region(Some(region0));
647 assert_eq!(flags.alias_region(), Some(region0));
648
649 let flags = flags.with_alias_region(Some(region1));
650 assert_eq!(flags.alias_region(), Some(region1));
651
652 let flags = flags.with_alias_region(None);
653 assert_eq!(flags.alias_region(), None);
654 }
655
656 #[test]
657 fn clear_removes_entries() {
658 let mut set = MemFlagsSet::new();
659 let trusted = set.insert(MemFlagsData::trusted()).unwrap();
660 let custom = MemFlagsData::new()
661 .with_endianness(Endianness::Big)
662 .with_alias_region(Some(AliasRegion::new(0)));
663 let custom_key = set.insert(custom).unwrap();
664 assert!(set.is_valid(trusted));
665 assert!(set.is_valid(custom_key));
666
667 set.clear();
668
669 assert!(!set.is_valid(trusted));
670 assert!(!set.is_valid(custom_key));
671 let trusted = set.insert(MemFlagsData::trusted()).unwrap();
672 assert_eq!(set[trusted], MemFlagsData::trusted());
673 }
674}