use crate::ast::SlotShape;
use crate::ast::{PortType, Value};
pub(crate) fn borrow_pair(v: &Value) -> Option<(u64, u64)> {
Some(match v {
Value::Str(s) => (s.as_ptr() as usize as u64, s.len() as u64),
Value::Bytes(b) => (b.as_ptr() as usize as u64, b.len() as u64),
Value::Json(_) | Value::Ext(_) | Value::Handle(_) => (v as *const Value as usize as u64, 1),
Value::VecF32(v) => slice_pair(v.as_slice()),
Value::VecF64(v) => slice_pair(v.as_slice()),
Value::VecF16(v) => slice_pair(v.as_slice()),
Value::VecI8(v) => slice_pair(v.as_slice()),
Value::VecI16(v) => slice_pair(v.as_slice()),
Value::VecI32(v) => slice_pair(v.as_slice()),
Value::VecI64(v) => slice_pair(v.as_slice()),
_ => return None,
})
}
#[inline]
pub(crate) fn slice_pair<T>(s: &[T]) -> (u64, u64) {
(s.as_ptr() as usize as u64, s.len() as u64)
}
#[inline]
pub(crate) fn empty_pair() -> (u64, u64) {
(
std::ptr::NonNull::<u8>::dangling().as_ptr() as usize as u64,
0,
)
}
#[cfg(feature = "jit")]
pub(crate) fn encode_slots(v: &Value, ty: PortType, out: &mut [u64]) -> Option<()> {
if ty == PortType::Dyn {
(out[0], out[1]) = match v {
Value::None => empty_pair(),
v => (v as *const Value as usize as u64, 1),
};
return Some(());
}
match v {
Value::U64(x) => out[0] = *x,
Value::I64(x) => out[0] = *x as u64,
Value::F64(x) => out[0] = x.to_bits(),
Value::Bool(b) => out[0] = *b as u64,
_ => {
let (p, l) = borrow_pair(v)?;
out[0] = p;
out[1] = l;
}
}
Some(())
}
pub(crate) unsafe fn decode_pair(ty: PortType, ptr: u64, len: u64) -> Value {
use crate::ast::SliceArc;
let (p, n) = (ptr as usize, len as usize);
unsafe {
match ty {
PortType::Str => Value::Str(std::sync::Arc::from(std::str::from_utf8_unchecked(
std::slice::from_raw_parts(p as *const u8, n),
))),
PortType::Bytes => Value::Bytes(std::sync::Arc::from(std::slice::from_raw_parts(
p as *const u8,
n,
))),
PortType::Json | PortType::Ext | PortType::Handle | PortType::Dyn => {
if n == 0 {
Value::None
} else {
(*(p as *const Value)).clone()
}
}
PortType::VecF32 => Value::VecF32(SliceArc::from_vec(
std::slice::from_raw_parts(p as *const f32, n).to_vec(),
)),
PortType::VecF64 => Value::VecF64(SliceArc::from_vec(
std::slice::from_raw_parts(p as *const f64, n).to_vec(),
)),
PortType::VecF16 => Value::VecF16(SliceArc::from_vec(
std::slice::from_raw_parts(p as *const half::f16, n).to_vec(),
)),
PortType::VecI8 => Value::VecI8(SliceArc::from_vec(
std::slice::from_raw_parts(p as *const i8, n).to_vec(),
)),
PortType::VecI16 => Value::VecI16(SliceArc::from_vec(
std::slice::from_raw_parts(p as *const i16, n).to_vec(),
)),
PortType::VecI32 => Value::VecI32(SliceArc::from_vec(
std::slice::from_raw_parts(p as *const i32, n).to_vec(),
)),
PortType::VecI64 => Value::VecI64(SliceArc::from_vec(
std::slice::from_raw_parts(p as *const i64, n).to_vec(),
)),
other => panic!("{other:?} is not a Ref2-colored port type"),
}
}
}
pub(crate) fn carrier_port(ty: PortType) -> PortType {
match ty {
PortType::I8 | PortType::I16 | PortType::I32 => PortType::I64,
PortType::U32 | PortType::U16 | PortType::U8 | PortType::F32 | PortType::F16 => {
PortType::U64
}
other => other,
}
}
pub(crate) fn decode_slot(slots: &[u64], ty: PortType) -> Value {
use crate::ast::{Bits128, RegLanes, SlotColor};
match ty.slot_color() {
SlotColor::Imm1 => match ty {
PortType::F64 => Value::F64(f64::from_bits(slots[0])),
PortType::Bool => Value::Bool(slots[0] != 0),
PortType::I64 | PortType::I8 | PortType::I16 | PortType::I32 => {
Value::I64(slots[0] as i64)
}
PortType::U64
| PortType::U32
| PortType::U16
| PortType::U8
| PortType::F32
| PortType::F16 => Value::U64(slots[0]),
other => unreachable!("{other:?} is colored Imm1 but has no one-slot carrier"),
},
SlotColor::Imm2 => {
let limbs = Bits128([slots[0], slots[1]]);
match ty {
PortType::U128 => Value::U128(limbs),
PortType::I128 => Value::I128(limbs),
PortType::Reg128 => Value::Reg128(limbs, RegLanes::Raw),
PortType::RegI8x16 => Value::Reg128(limbs, RegLanes::I8x16),
PortType::RegI16x8 => Value::Reg128(limbs, RegLanes::I16x8),
PortType::RegI32x4 => Value::Reg128(limbs, RegLanes::I32x4),
PortType::RegI64x2 => Value::Reg128(limbs, RegLanes::I64x2),
PortType::RegF16x8 => Value::Reg128(limbs, RegLanes::F16x8),
PortType::RegF32x4 => Value::Reg128(limbs, RegLanes::F32x4),
PortType::RegF64x2 => Value::Reg128(limbs, RegLanes::F64x2),
other => unreachable!("{other:?} is colored Imm2 but is not a 128-bit value"),
}
}
SlotColor::Ref2 => unsafe { decode_pair(ty, slots[0], slots[1]) },
}
}
pub fn decode_output(buffer: &[u64], slot: usize, ty: PortType) -> Value {
decode_slot(&buffer[slot..], ty)
}
pub unsafe fn arg_ref<'a>(ty: PortType, slots: &'a [u64]) -> crate::ast::ValueRef<'a> {
use crate::ast::ValueRef;
let (p, n) = (
slots.first().copied().unwrap_or(0) as usize,
slots.get(1).copied().unwrap_or(0) as usize,
);
unsafe {
match ty {
PortType::U64 => ValueRef::U64(slots[0]),
PortType::I64 | PortType::I8 | PortType::I16 | PortType::I32 => {
ValueRef::I64(slots[0] as i64)
}
PortType::F64 => ValueRef::F64(f64::from_bits(slots[0])),
PortType::Bool => ValueRef::Bool(slots[0] != 0),
PortType::Str => ValueRef::Str(std::str::from_utf8_unchecked(
std::slice::from_raw_parts(p as *const u8, n),
)),
PortType::Bytes => ValueRef::Bytes(std::slice::from_raw_parts(p as *const u8, n)),
PortType::Json | PortType::Ext | PortType::Handle | PortType::Dyn => {
if n == 0 {
ValueRef::None
} else {
ValueRef::from(&*(p as *const Value))
}
}
_ => ValueRef::U64(slots[0]),
}
}
}