1 //! This module gives users to instantiate values that Cranelift understands. These values are used,
2 //! for example, during interpretation and for wrapping immediates.
3 use crate::ir::immediates::{Ieee32, Ieee64, Offset32};
4 use crate::ir::{types, ConstantData, Type};
5 use core::convert::TryInto;
6 use core::fmt::{self, Display, Formatter};
7 
8 /// Represent a data value. Where [Value] is an SSA reference, [DataValue] is the type + value
9 /// that would be referred to by a [Value].
10 ///
11 /// [Value]: crate::ir::Value
12 #[allow(missing_docs)]
13 #[derive(Clone, Debug, PartialEq, PartialOrd)]
14 pub enum DataValue {
15     B(bool),
16     I8(i8),
17     I16(i16),
18     I32(i32),
19     I64(i64),
20     I128(i128),
21     U8(u8),
22     U16(u16),
23     U32(u32),
24     U64(u64),
25     U128(u128),
26     F32(Ieee32),
27     F64(Ieee64),
28     V128([u8; 16]),
29 }
30 
31 impl DataValue {
32     /// Try to cast an immediate integer (a wrapped `i64` on most Cranelift instructions) to the
33     /// given Cranelift [Type].
34     pub fn from_integer(imm: i128, ty: Type) -> Result<DataValue, DataValueCastFailure> {
35         match ty {
36             types::I8 => Ok(DataValue::I8(imm as i8)),
37             types::I16 => Ok(DataValue::I16(imm as i16)),
38             types::I32 => Ok(DataValue::I32(imm as i32)),
39             types::I64 => Ok(DataValue::I64(imm as i64)),
40             types::I128 => Ok(DataValue::I128(imm)),
41             _ => Err(DataValueCastFailure::FromInteger(imm, ty)),
42         }
43     }
44 
45     /// Return the Cranelift IR [Type] for this [DataValue].
46     pub fn ty(&self) -> Type {
47         match self {
48             DataValue::B(_) => types::B8, // A default type.
49             DataValue::I8(_) | DataValue::U8(_) => types::I8,
50             DataValue::I16(_) | DataValue::U16(_) => types::I16,
51             DataValue::I32(_) | DataValue::U32(_) => types::I32,
52             DataValue::I64(_) | DataValue::U64(_) => types::I64,
53             DataValue::I128(_) | DataValue::U128(_) => types::I128,
54             DataValue::F32(_) => types::F32,
55             DataValue::F64(_) => types::F64,
56             DataValue::V128(_) => types::I8X16, // A default type.
57         }
58     }
59 
60     /// Return true if the value is a vector (i.e. `DataValue::V128`).
61     pub fn is_vector(&self) -> bool {
62         match self {
63             DataValue::V128(_) => true,
64             _ => false,
65         }
66     }
67 
68     /// Return true if the value is a bool (i.e. `DataValue::B`).
69     pub fn is_bool(&self) -> bool {
70         match self {
71             DataValue::B(_) => true,
72             _ => false,
73         }
74     }
75 
76     /// Write a [DataValue] to a slice.
77     ///
78     /// # Panics:
79     ///
80     /// Panics if the slice does not have enough space to accommodate the [DataValue]
81     pub fn write_to_slice(&self, dst: &mut [u8]) {
82         match self {
83             DataValue::B(true) => dst[..16].copy_from_slice(&[u8::MAX; 16][..]),
84             DataValue::B(false) => dst[..16].copy_from_slice(&[0; 16][..]),
85             DataValue::I8(i) => dst[..1].copy_from_slice(&i.to_ne_bytes()[..]),
86             DataValue::I16(i) => dst[..2].copy_from_slice(&i.to_ne_bytes()[..]),
87             DataValue::I32(i) => dst[..4].copy_from_slice(&i.to_ne_bytes()[..]),
88             DataValue::I64(i) => dst[..8].copy_from_slice(&i.to_ne_bytes()[..]),
89             DataValue::I128(i) => dst[..16].copy_from_slice(&i.to_ne_bytes()[..]),
90             DataValue::F32(f) => dst[..4].copy_from_slice(&f.bits().to_ne_bytes()[..]),
91             DataValue::F64(f) => dst[..8].copy_from_slice(&f.bits().to_ne_bytes()[..]),
92             DataValue::V128(v) => dst[..16].copy_from_slice(&v[..]),
93             _ => unimplemented!(),
94         };
95     }
96 
97     /// Read a [DataValue] from a slice using a given [Type].
98     ///
99     /// # Panics:
100     ///
101     /// Panics if the slice does not have enough space to accommodate the [DataValue]
102     pub fn read_from_slice(src: &[u8], ty: Type) -> Self {
103         match ty {
104             types::I8 => DataValue::I8(i8::from_ne_bytes(src[..1].try_into().unwrap())),
105             types::I16 => DataValue::I16(i16::from_ne_bytes(src[..2].try_into().unwrap())),
106             types::I32 => DataValue::I32(i32::from_ne_bytes(src[..4].try_into().unwrap())),
107             types::I64 => DataValue::I64(i64::from_ne_bytes(src[..8].try_into().unwrap())),
108             types::I128 => DataValue::I128(i128::from_ne_bytes(src[..16].try_into().unwrap())),
109             types::F32 => DataValue::F32(Ieee32::with_bits(u32::from_ne_bytes(
110                 src[..4].try_into().unwrap(),
111             ))),
112             types::F64 => DataValue::F64(Ieee64::with_bits(u64::from_ne_bytes(
113                 src[..8].try_into().unwrap(),
114             ))),
115             _ if ty.is_bool() => {
116                 // Only `ty.bytes()` are guaranteed to be written
117                 // so we can only test the first n bytes of `src`
118 
119                 let size = ty.bytes() as usize;
120                 DataValue::B(src[..size].iter().any(|&i| i != 0))
121             }
122             _ if ty.is_vector() && ty.bytes() == 16 => {
123                 DataValue::V128(src[..16].try_into().unwrap())
124             }
125             _ => unimplemented!(),
126         }
127     }
128 
129     /// Write a [DataValue] to a memory location.
130     pub unsafe fn write_value_to(&self, p: *mut u128) {
131         // Since `DataValue` does not have type info for bools we always
132         // write out a full 16 byte slot.
133         let size = match self.ty() {
134             ty if ty.is_bool() => 16,
135             ty => ty.bytes() as usize,
136         };
137 
138         self.write_to_slice(std::slice::from_raw_parts_mut(p as *mut u8, size));
139     }
140 
141     /// Read a [DataValue] from a memory location using a given [Type].
142     pub unsafe fn read_value_from(p: *const u128, ty: Type) -> Self {
143         DataValue::read_from_slice(
144             std::slice::from_raw_parts(p as *const u8, ty.bytes() as usize),
145             ty,
146         )
147     }
148 }
149 
150 /// Record failures to cast [DataValue].
151 #[derive(Debug, PartialEq)]
152 #[allow(missing_docs)]
153 pub enum DataValueCastFailure {
154     TryInto(Type, Type),
155     FromInteger(i128, Type),
156 }
157 
158 // This is manually implementing Error and Display instead of using thiserror to reduce the amount
159 // of dependencies used by Cranelift.
160 impl std::error::Error for DataValueCastFailure {}
161 
162 impl Display for DataValueCastFailure {
163     fn fmt(&self, f: &mut Formatter) -> fmt::Result {
164         match self {
165             DataValueCastFailure::TryInto(from, to) => {
166                 write!(
167                     f,
168                     "unable to cast data value of type {} to type {}",
169                     from, to
170                 )
171             }
172             DataValueCastFailure::FromInteger(val, to) => {
173                 write!(
174                     f,
175                     "unable to cast i64({}) to a data value of type {}",
176                     val, to
177                 )
178             }
179         }
180     }
181 }
182 
183 /// Helper for creating conversion implementations for [DataValue].
184 macro_rules! build_conversion_impl {
185     ( $rust_ty:ty, $data_value_ty:ident, $cranelift_ty:ident ) => {
186         impl From<$rust_ty> for DataValue {
187             fn from(data: $rust_ty) -> Self {
188                 DataValue::$data_value_ty(data)
189             }
190         }
191 
192         impl TryInto<$rust_ty> for DataValue {
193             type Error = DataValueCastFailure;
194             fn try_into(self) -> Result<$rust_ty, Self::Error> {
195                 if let DataValue::$data_value_ty(v) = self {
196                     Ok(v)
197                 } else {
198                     Err(DataValueCastFailure::TryInto(
199                         self.ty(),
200                         types::$cranelift_ty,
201                     ))
202                 }
203             }
204         }
205     };
206 }
207 build_conversion_impl!(bool, B, B8);
208 build_conversion_impl!(i8, I8, I8);
209 build_conversion_impl!(i16, I16, I16);
210 build_conversion_impl!(i32, I32, I32);
211 build_conversion_impl!(i64, I64, I64);
212 build_conversion_impl!(i128, I128, I128);
213 build_conversion_impl!(u8, U8, I8);
214 build_conversion_impl!(u16, U16, I16);
215 build_conversion_impl!(u32, U32, I32);
216 build_conversion_impl!(u64, U64, I64);
217 build_conversion_impl!(u128, U128, I128);
218 build_conversion_impl!(Ieee32, F32, F32);
219 build_conversion_impl!(Ieee64, F64, F64);
220 build_conversion_impl!([u8; 16], V128, I8X16);
221 impl From<Offset32> for DataValue {
222     fn from(o: Offset32) -> Self {
223         DataValue::from(Into::<i32>::into(o))
224     }
225 }
226 
227 impl Display for DataValue {
228     fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
229         match self {
230             DataValue::B(dv) => write!(f, "{}", dv),
231             DataValue::I8(dv) => write!(f, "{}", dv),
232             DataValue::I16(dv) => write!(f, "{}", dv),
233             DataValue::I32(dv) => write!(f, "{}", dv),
234             DataValue::I64(dv) => write!(f, "{}", dv),
235             DataValue::I128(dv) => write!(f, "{}", dv),
236             DataValue::U8(dv) => write!(f, "{}", dv),
237             DataValue::U16(dv) => write!(f, "{}", dv),
238             DataValue::U32(dv) => write!(f, "{}", dv),
239             DataValue::U64(dv) => write!(f, "{}", dv),
240             DataValue::U128(dv) => write!(f, "{}", dv),
241             // The Ieee* wrappers here print the expected syntax.
242             DataValue::F32(dv) => write!(f, "{}", dv),
243             DataValue::F64(dv) => write!(f, "{}", dv),
244             // Again, for syntax consistency, use ConstantData, which in this case displays as hex.
245             DataValue::V128(dv) => write!(f, "{}", ConstantData::from(&dv[..])),
246         }
247     }
248 }
249 
250 /// Helper structure for printing bracket-enclosed vectors of [DataValue]s.
251 /// - for empty vectors, display `[]`
252 /// - for single item vectors, display `42`, e.g.
253 /// - for multiple item vectors, display `[42, 43, 44]`, e.g.
254 pub struct DisplayDataValues<'a>(pub &'a [DataValue]);
255 
256 impl<'a> Display for DisplayDataValues<'a> {
257     fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
258         if self.0.len() == 1 {
259             write!(f, "{}", self.0[0])
260         } else {
261             write!(f, "[")?;
262             write_data_value_list(f, &self.0)?;
263             write!(f, "]")
264         }
265     }
266 }
267 
268 /// Helper function for displaying `Vec<DataValue>`.
269 pub fn write_data_value_list(f: &mut Formatter<'_>, list: &[DataValue]) -> fmt::Result {
270     match list.len() {
271         0 => Ok(()),
272         1 => write!(f, "{}", list[0]),
273         _ => {
274             write!(f, "{}", list[0])?;
275             for dv in list.iter().skip(1) {
276                 write!(f, ", {}", dv)?;
277             }
278             Ok(())
279         }
280     }
281 }
282 
283 #[cfg(test)]
284 mod test {
285     use super::*;
286 
287     #[test]
288     fn type_conversions() {
289         assert_eq!(DataValue::B(true).ty(), types::B8);
290         assert_eq!(
291             TryInto::<bool>::try_into(DataValue::B(false)).unwrap(),
292             false
293         );
294         assert_eq!(
295             TryInto::<i32>::try_into(DataValue::B(false)).unwrap_err(),
296             DataValueCastFailure::TryInto(types::B8, types::I32)
297         );
298 
299         assert_eq!(DataValue::V128([0; 16]).ty(), types::I8X16);
300         assert_eq!(
301             TryInto::<[u8; 16]>::try_into(DataValue::V128([0; 16])).unwrap(),
302             [0; 16]
303         );
304         assert_eq!(
305             TryInto::<i32>::try_into(DataValue::V128([0; 16])).unwrap_err(),
306             DataValueCastFailure::TryInto(types::I8X16, types::I32)
307         );
308     }
309 }
310