cranelift: Add big and little endian memory accesses to interpreter (#5893)
* Added `mem_flags` parameter to `State::checked_{load,store}` as the means
for determining the endianness, typically derived from an instruction.
* Added `native_endianness` property to `InterpreterState` as fallback when
determining endianness, such as in cases where there are no memory flags
avaiable or set.
* Added `to_be` and `to_le` methods to `DataValue`.
* Added `AtomicCas` and `AtomicRmw` to list of instructions with retrievable
memory flags for `InstructionData::memflags`.
* Enabled `atomic-{cas,rmw}-subword-{big,little}.clif` for interpreter run
tests.
This commit is contained in:
committed by
GitHub
parent
9984e959cd
commit
db8fe0108f
@@ -101,12 +101,55 @@ impl DataValue {
|
||||
}
|
||||
}
|
||||
|
||||
/// Write a [DataValue] to a slice.
|
||||
fn swap_bytes(self) -> Self {
|
||||
match self {
|
||||
DataValue::I8(i) => DataValue::I8(i.swap_bytes()),
|
||||
DataValue::I16(i) => DataValue::I16(i.swap_bytes()),
|
||||
DataValue::I32(i) => DataValue::I32(i.swap_bytes()),
|
||||
DataValue::I64(i) => DataValue::I64(i.swap_bytes()),
|
||||
DataValue::I128(i) => DataValue::I128(i.swap_bytes()),
|
||||
DataValue::U8(i) => DataValue::U8(i.swap_bytes()),
|
||||
DataValue::U16(i) => DataValue::U16(i.swap_bytes()),
|
||||
DataValue::U32(i) => DataValue::U32(i.swap_bytes()),
|
||||
DataValue::U64(i) => DataValue::U64(i.swap_bytes()),
|
||||
DataValue::U128(i) => DataValue::U128(i.swap_bytes()),
|
||||
DataValue::F32(f) => DataValue::F32(Ieee32::with_bits(f.bits().swap_bytes())),
|
||||
DataValue::F64(f) => DataValue::F64(Ieee64::with_bits(f.bits().swap_bytes())),
|
||||
DataValue::V128(mut v) => {
|
||||
v.reverse();
|
||||
DataValue::V128(v)
|
||||
}
|
||||
DataValue::V64(mut v) => {
|
||||
v.reverse();
|
||||
DataValue::V64(v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts `self` to big endian from target's endianness.
|
||||
pub fn to_be(self) -> Self {
|
||||
if cfg!(target_endian = "big") {
|
||||
self
|
||||
} else {
|
||||
self.swap_bytes()
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts `self` to little endian from target's endianness.
|
||||
pub fn to_le(self) -> Self {
|
||||
if cfg!(target_endian = "little") {
|
||||
self
|
||||
} else {
|
||||
self.swap_bytes()
|
||||
}
|
||||
}
|
||||
|
||||
/// Write a [DataValue] to a slice in native-endian byte order.
|
||||
///
|
||||
/// # Panics:
|
||||
///
|
||||
/// Panics if the slice does not have enough space to accommodate the [DataValue]
|
||||
pub fn write_to_slice(&self, dst: &mut [u8]) {
|
||||
pub fn write_to_slice_ne(&self, dst: &mut [u8]) {
|
||||
match self {
|
||||
DataValue::I8(i) => dst[..1].copy_from_slice(&i.to_ne_bytes()[..]),
|
||||
DataValue::I16(i) => dst[..2].copy_from_slice(&i.to_ne_bytes()[..]),
|
||||
@@ -121,12 +164,30 @@ impl DataValue {
|
||||
};
|
||||
}
|
||||
|
||||
/// Read a [DataValue] from a slice using a given [Type].
|
||||
/// Write a [DataValue] to a slice in big-endian byte order.
|
||||
///
|
||||
/// # Panics:
|
||||
///
|
||||
/// Panics if the slice does not have enough space to accommodate the [DataValue]
|
||||
pub fn read_from_slice(src: &[u8], ty: Type) -> Self {
|
||||
pub fn write_to_slice_be(&self, dst: &mut [u8]) {
|
||||
self.clone().to_be().write_to_slice_ne(dst);
|
||||
}
|
||||
|
||||
/// Write a [DataValue] to a slice in little-endian byte order.
|
||||
///
|
||||
/// # Panics:
|
||||
///
|
||||
/// Panics if the slice does not have enough space to accommodate the [DataValue]
|
||||
pub fn write_to_slice_le(&self, dst: &mut [u8]) {
|
||||
self.clone().to_le().write_to_slice_ne(dst);
|
||||
}
|
||||
|
||||
/// Read a [DataValue] from a slice using a given [Type] with native-endian byte order.
|
||||
///
|
||||
/// # Panics:
|
||||
///
|
||||
/// Panics if the slice does not have enough space to accommodate the [DataValue]
|
||||
pub fn read_from_slice_ne(src: &[u8], ty: Type) -> Self {
|
||||
match ty {
|
||||
types::I8 => DataValue::I8(i8::from_ne_bytes(src[..1].try_into().unwrap())),
|
||||
types::I16 => DataValue::I16(i16::from_ne_bytes(src[..2].try_into().unwrap())),
|
||||
@@ -152,15 +213,33 @@ impl DataValue {
|
||||
}
|
||||
}
|
||||
|
||||
/// Write a [DataValue] to a memory location.
|
||||
pub unsafe fn write_value_to(&self, p: *mut u128) {
|
||||
let size = self.ty().bytes() as usize;
|
||||
self.write_to_slice(std::slice::from_raw_parts_mut(p as *mut u8, size));
|
||||
/// Read a [DataValue] from a slice using a given [Type] in big-endian byte order.
|
||||
///
|
||||
/// # Panics:
|
||||
///
|
||||
/// Panics if the slice does not have enough space to accommodate the [DataValue]
|
||||
pub fn read_from_slice_be(src: &[u8], ty: Type) -> Self {
|
||||
DataValue::read_from_slice_ne(src, ty).to_be()
|
||||
}
|
||||
|
||||
/// Read a [DataValue] from a memory location using a given [Type].
|
||||
/// Read a [DataValue] from a slice using a given [Type] in little-endian byte order.
|
||||
///
|
||||
/// # Panics:
|
||||
///
|
||||
/// Panics if the slice does not have enough space to accommodate the [DataValue]
|
||||
pub fn read_from_slice_le(src: &[u8], ty: Type) -> Self {
|
||||
DataValue::read_from_slice_ne(src, ty).to_le()
|
||||
}
|
||||
|
||||
/// Write a [DataValue] to a memory location in native-endian byte order.
|
||||
pub unsafe fn write_value_to(&self, p: *mut u128) {
|
||||
let size = self.ty().bytes() as usize;
|
||||
self.write_to_slice_ne(std::slice::from_raw_parts_mut(p as *mut u8, size));
|
||||
}
|
||||
|
||||
/// Read a [DataValue] from a memory location using a given [Type] in native-endian byte order.
|
||||
pub unsafe fn read_value_from(p: *const u128, ty: Type) -> Self {
|
||||
DataValue::read_from_slice(
|
||||
DataValue::read_from_slice_ne(
|
||||
std::slice::from_raw_parts(p as *const u8, ty.bytes() as usize),
|
||||
ty,
|
||||
)
|
||||
|
||||
@@ -403,7 +403,9 @@ impl InstructionData {
|
||||
&InstructionData::Load { flags, .. }
|
||||
| &InstructionData::LoadNoOffset { flags, .. }
|
||||
| &InstructionData::Store { flags, .. }
|
||||
| &InstructionData::StoreNoOffset { flags, .. } => Some(flags),
|
||||
| &InstructionData::StoreNoOffset { flags, .. }
|
||||
| &InstructionData::AtomicCas { flags, .. }
|
||||
| &InstructionData::AtomicRmw { flags, .. } => Some(flags),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user