1use libc::c_void;
5use std::arch::x86_64::{
6 __m128, _mm_castpd_ps, _mm_castps_pd, _mm_load_pd1, _mm_load_ps1, _mm_setzero_ps,
7 _mm_storeu_pd, _mm_storeu_ps,
8};
9
10use lucet_module::ValueType;
11
12impl Val {
13 pub fn value_type(&self) -> ValueType {
14 match self {
15 Val::USize(_) | Val::ISize(_) | Val::CPtr(_) => ValueType::I32,
18 Val::GuestPtr(_) => ValueType::I32,
19 Val::I8(_) | Val::U8(_) | Val::I16(_) | Val::U16(_) | Val::I32(_) | Val::U32(_) => {
20 ValueType::I32
21 }
22 Val::I64(_) | Val::U64(_) => ValueType::I64,
23 Val::Bool(_) => ValueType::I32,
24 Val::F32(_) => ValueType::F32,
25 Val::F64(_) => ValueType::F64,
26 }
27 }
28}
29
30#[derive(Clone, Copy, Debug)]
32pub enum Val {
33 CPtr(*const c_void),
34 GuestPtr(u32),
36 U8(u8),
37 U16(u16),
38 U32(u32),
39 U64(u64),
40 I8(i8),
41 I16(i16),
42 I32(i32),
43 I64(i64),
44 USize(usize),
45 ISize(isize),
46 Bool(bool),
47 F32(f32),
48 F64(f64),
49}
50
51unsafe impl Send for Val {}
54unsafe impl Sync for Val {}
55
56impl<T> From<*const T> for Val {
57 fn from(x: *const T) -> Val {
58 Val::CPtr(x as *const c_void)
59 }
60}
61
62impl<T> From<*mut T> for Val {
63 fn from(x: *mut T) -> Val {
64 Val::CPtr(x as *mut c_void)
65 }
66}
67
68macro_rules! impl_from_scalars {
69 ( { $( $ctor:ident : $ty:ty ),* } ) => {
70 $(
71 impl From<$ty> for Val {
72 fn from(x: $ty) -> Val {
73 Val::$ctor(x)
74 }
75 }
76 )*
77 };
78}
79
80impl_from_scalars!({
83 U8: u8,
84 U16: u16,
85 U32: u32,
86 U64: u64,
87 I8: i8,
88 I16: i16,
89 I32: i32,
90 I64: i64,
91 USize: usize,
92 ISize: isize,
93 Bool: bool,
94 F32: f32,
95 F64: f64
96});
97
98pub enum RegVal {
104 GpReg(u64),
105 FpReg(__m128),
106}
107
108pub fn val_to_reg(val: &Val) -> RegVal {
111 use self::RegVal::*;
112 use self::Val::*;
113 match *val {
114 CPtr(v) => GpReg(v as u64),
115 GuestPtr(v) => GpReg(v as u64),
116 U8(v) => GpReg(v as u64),
117 U16(v) => GpReg(v as u64),
118 U32(v) => GpReg(v as u64),
119 U64(v) => GpReg(v as u64),
120 I8(v) => GpReg(v as u64),
121 I16(v) => GpReg(v as u64),
122 I32(v) => GpReg(v as u64),
123 I64(v) => GpReg(v as u64),
124 USize(v) => GpReg(v as u64),
125 ISize(v) => GpReg(v as u64),
126 Bool(false) => GpReg(0u64),
127 Bool(true) => GpReg(1u64),
128 Val::F32(v) => FpReg(unsafe { _mm_load_ps1(&v as *const f32) }),
129 Val::F64(v) => FpReg(unsafe { _mm_castpd_ps(_mm_load_pd1(&v as *const f64)) }),
130 }
131}
132
133pub fn val_to_stack(val: &Val) -> u64 {
136 use self::Val::*;
137 match *val {
138 CPtr(v) => v as u64,
139 GuestPtr(v) => v as u64,
140 U8(v) => v as u64,
141 U16(v) => v as u64,
142 U32(v) => v as u64,
143 U64(v) => v as u64,
144 I8(v) => v as u64,
145 I16(v) => v as u64,
146 I32(v) => v as u64,
147 I64(v) => v as u64,
148 USize(v) => v as u64,
149 ISize(v) => v as u64,
150 Bool(false) => 0u64,
151 Bool(true) => 1u64,
152 F32(v) => v.to_bits() as u64,
153 F64(v) => v.to_bits(),
154 }
155}
156
157#[derive(Clone, Copy, Debug)]
162pub struct UntypedRetVal {
163 fp: __m128,
164 gp: u64,
165}
166
167impl std::fmt::Display for UntypedRetVal {
168 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
169 write!(f, "<untyped return value>")
170 }
171}
172
173impl UntypedRetVal {
174 pub(crate) fn new(gp: u64, fp: __m128) -> UntypedRetVal {
175 UntypedRetVal { gp, fp }
176 }
177}
178
179impl From<RegVal> for UntypedRetVal {
180 fn from(reg: RegVal) -> UntypedRetVal {
181 match reg {
182 RegVal::GpReg(r) => UntypedRetVal::new(r, unsafe { _mm_setzero_ps() }),
183 RegVal::FpReg(r) => UntypedRetVal::new(0, r),
184 }
185 }
186}
187
188impl<T: Into<Val>> From<T> for UntypedRetVal {
189 fn from(v: T) -> UntypedRetVal {
190 val_to_reg(&v.into()).into()
191 }
192}
193
194macro_rules! impl_from_fp {
195 ( $ty:ty, $f:ident, $as:ident ) => {
196 impl From<UntypedRetVal> for $ty {
197 fn from(retval: UntypedRetVal) -> $ty {
198 $f(retval.fp)
199 }
200 }
201
202 impl From<&UntypedRetVal> for $ty {
203 fn from(retval: &UntypedRetVal) -> $ty {
204 $f(retval.fp)
205 }
206 }
207
208 impl UntypedRetVal {
209 pub fn $as(&self) -> $ty {
210 $f(self.fp)
211 }
212 }
213 };
214}
215
216impl_from_fp!(f32, __m128_as_f32, as_f32);
217impl_from_fp!(f64, __m128_as_f64, as_f64);
218
219macro_rules! impl_from_gp {
220 ( $ty:ty, $as:ident ) => {
221 impl From<UntypedRetVal> for $ty {
222 fn from(retval: UntypedRetVal) -> $ty {
223 retval.gp as $ty
224 }
225 }
226
227 impl From<&UntypedRetVal> for $ty {
228 fn from(retval: &UntypedRetVal) -> $ty {
229 retval.gp as $ty
230 }
231 }
232
233 impl UntypedRetVal {
234 pub fn $as(&self) -> $ty {
235 self.gp as $ty
236 }
237 }
238 };
239}
240
241impl_from_gp!(u8, as_u8);
242impl_from_gp!(u16, as_u16);
243impl_from_gp!(u32, as_u32);
244impl_from_gp!(u64, as_u64);
245
246impl_from_gp!(i8, as_i8);
247impl_from_gp!(i16, as_i16);
248impl_from_gp!(i32, as_i32);
249impl_from_gp!(i64, as_i64);
250
251impl From<UntypedRetVal> for bool {
252 fn from(retval: UntypedRetVal) -> bool {
253 retval.gp != 0
254 }
255}
256
257impl From<&UntypedRetVal> for bool {
258 fn from(retval: &UntypedRetVal) -> bool {
259 retval.gp != 0
260 }
261}
262
263impl UntypedRetVal {
264 pub fn as_bool(&self) -> bool {
265 self.gp != 0
266 }
267
268 pub fn as_ptr<T>(&self) -> *const T {
269 self.gp as *const T
270 }
271
272 pub fn as_mut<T>(&self) -> *mut T {
273 self.gp as *mut T
274 }
275}
276
277impl Default for UntypedRetVal {
278 fn default() -> UntypedRetVal {
279 let fp = unsafe { _mm_setzero_ps() };
280 UntypedRetVal { fp, gp: 0 }
281 }
282}
283
284pub trait UntypedRetValInternal {
285 fn fp(&self) -> __m128;
286 fn gp(&self) -> u64;
287}
288
289impl UntypedRetValInternal for UntypedRetVal {
290 fn fp(&self) -> __m128 {
291 self.fp
292 }
293
294 fn gp(&self) -> u64 {
295 self.gp
296 }
297}
298
299pub fn __m128_as_f32(v: __m128) -> f32 {
303 let mut out: [f32; 4] = [0.0; 4];
304 unsafe {
305 _mm_storeu_ps(&mut out[0] as *mut f32, v);
306 }
307 out[0]
308}
309
310pub fn __m128_as_f64(v: __m128) -> f64 {
312 let mut out: [f64; 2] = [0.0; 2];
313 unsafe {
314 let vd = _mm_castps_pd(v);
315 _mm_storeu_pd(&mut out[0] as *mut f64, vd);
316 }
317 out[0]
318}