1 //! Memory operation flags.
2 
3 use core::fmt;
4 
5 enum FlagBit {
6     Notrap,
7     Aligned,
8     Readonly,
9 }
10 
11 const NAMES: [&str; 3] = ["notrap", "aligned", "readonly"];
12 
13 /// Flags for memory operations like load/store.
14 ///
15 /// Each of these flags introduce a limited form of undefined behavior. The flags each enable
16 /// certain optimizations that need to make additional assumptions. Generally, the semantics of a
17 /// program does not change when a flag is removed, but adding a flag will.
18 #[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
19 pub struct MemFlags {
20     bits: u8,
21 }
22 
23 impl MemFlags {
24     /// Create a new empty set of flags.
new() -> Self25     pub fn new() -> Self {
26         Self { bits: 0 }
27     }
28 
29     /// Create a set of flags representing an access from a "trusted" address, meaning it's
30     /// known to be aligned and non-trapping.
trusted() -> Self31     pub fn trusted() -> Self {
32         let mut result = Self::new();
33         result.set_notrap();
34         result.set_aligned();
35         result
36     }
37 
38     /// Read a flag bit.
read(self, bit: FlagBit) -> bool39     fn read(self, bit: FlagBit) -> bool {
40         self.bits & (1 << bit as usize) != 0
41     }
42 
43     /// Set a flag bit.
set(&mut self, bit: FlagBit)44     fn set(&mut self, bit: FlagBit) {
45         self.bits |= 1 << bit as usize
46     }
47 
48     /// Set a flag bit by name.
49     ///
50     /// Returns true if the flag was found and set, false for an unknown flag name.
set_by_name(&mut self, name: &str) -> bool51     pub fn set_by_name(&mut self, name: &str) -> bool {
52         match NAMES.iter().position(|&s| s == name) {
53             Some(bit) => {
54                 self.bits |= 1 << bit;
55                 true
56             }
57             None => false,
58         }
59     }
60 
61     /// Test if the `notrap` flag is set.
62     ///
63     /// Normally, trapping is part of the semantics of a load/store operation. If the platform
64     /// would cause a trap when accessing the effective address, the Cranelift memory operation is
65     /// also required to trap.
66     ///
67     /// The `notrap` flag tells Cranelift that the memory is *accessible*, which means that
68     /// accesses will not trap. This makes it possible to delete an unused load or a dead store
69     /// instruction.
notrap(self) -> bool70     pub fn notrap(self) -> bool {
71         self.read(FlagBit::Notrap)
72     }
73 
74     /// Set the `notrap` flag.
set_notrap(&mut self)75     pub fn set_notrap(&mut self) {
76         self.set(FlagBit::Notrap)
77     }
78 
79     /// Test if the `aligned` flag is set.
80     ///
81     /// By default, Cranelift memory instructions work with any unaligned effective address. If the
82     /// `aligned` flag is set, the instruction is permitted to trap or return a wrong result if the
83     /// effective address is misaligned.
aligned(self) -> bool84     pub fn aligned(self) -> bool {
85         self.read(FlagBit::Aligned)
86     }
87 
88     /// Set the `aligned` flag.
set_aligned(&mut self)89     pub fn set_aligned(&mut self) {
90         self.set(FlagBit::Aligned)
91     }
92 
93     /// Test if the `readonly` flag is set.
94     ///
95     /// Loads with this flag have no memory dependencies.
96     /// This results in undefined behavior if the dereferenced memory is mutated at any time
97     /// between when the function is called and when it is exited.
readonly(self) -> bool98     pub fn readonly(self) -> bool {
99         self.read(FlagBit::Readonly)
100     }
101 
102     /// Set the `readonly` flag.
set_readonly(&mut self)103     pub fn set_readonly(&mut self) {
104         self.set(FlagBit::Readonly)
105     }
106 }
107 
108 impl fmt::Display for MemFlags {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result109     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
110         for (i, n) in NAMES.iter().enumerate() {
111             if self.bits & (1 << i) != 0 {
112                 write!(f, " {}", n)?;
113             }
114         }
115         Ok(())
116     }
117 }
118