Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 60 additions & 22 deletions cranelift/codegen/src/data_value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ use crate::ir::immediates::{Ieee32, Ieee64, Offset32};
use crate::ir::{types, ConstantData, Type};
use core::convert::TryInto;
use core::fmt::{self, Display, Formatter};
use core::ptr;

/// Represent a data value. Where [Value] is an SSA reference, [DataValue] is the type + value
/// that would be referred to by a [Value].
Expand Down Expand Up @@ -74,37 +73,76 @@ impl DataValue {
}
}

/// Write a [DataValue] to a memory location.
pub unsafe fn write_value_to(&self, p: *mut u128) {
/// Write a [DataValue] to a slice.
///
/// # Panics:
///
/// Panics if the slice does not have enough space to accommodate the [DataValue]
pub fn write_to_slice(&self, dst: &mut [u8]) {
match self {
DataValue::B(b) => ptr::write(p, if *b { -1i128 as u128 } else { 0u128 }),
DataValue::I8(i) => ptr::write(p as *mut i8, *i),
DataValue::I16(i) => ptr::write(p as *mut i16, *i),
DataValue::I32(i) => ptr::write(p as *mut i32, *i),
DataValue::I64(i) => ptr::write(p as *mut i64, *i),
DataValue::F32(f) => ptr::write(p as *mut Ieee32, *f),
DataValue::F64(f) => ptr::write(p as *mut Ieee64, *f),
DataValue::V128(b) => ptr::write(p as *mut [u8; 16], *b),
DataValue::B(true) => dst[..16].copy_from_slice(&[u8::MAX; 16][..]),
DataValue::B(false) => dst[..16].copy_from_slice(&[0; 16][..]),
DataValue::I8(i) => dst[..1].copy_from_slice(&i.to_le_bytes()[..]),
DataValue::I16(i) => dst[..2].copy_from_slice(&i.to_le_bytes()[..]),
DataValue::I32(i) => dst[..4].copy_from_slice(&i.to_le_bytes()[..]),
DataValue::I64(i) => dst[..8].copy_from_slice(&i.to_le_bytes()[..]),
DataValue::F32(f) => dst[..4].copy_from_slice(&f.bits().to_le_bytes()[..]),
DataValue::F64(f) => dst[..8].copy_from_slice(&f.bits().to_le_bytes()[..]),
DataValue::V128(v) => dst[..16].copy_from_slice(&v[..]),
_ => unimplemented!(),
}
};
}

/// Read a [DataValue] from a memory location using a given [Type].
pub unsafe fn read_value_from(p: *const u128, ty: Type) -> Self {
/// Read a [DataValue] from a slice using a given [Type].
///
/// # Panics:
///
/// Panics if the slice does not have enough space to accommodate the [DataValue]
pub fn read_from_slice(src: &[u8], ty: Type) -> Self {
match ty {
types::I8 => DataValue::I8(ptr::read(p as *const i8)),
types::I16 => DataValue::I16(ptr::read(p as *const i16)),
types::I32 => DataValue::I32(ptr::read(p as *const i32)),
types::I64 => DataValue::I64(ptr::read(p as *const i64)),
types::F32 => DataValue::F32(ptr::read(p as *const Ieee32)),
types::F64 => DataValue::F64(ptr::read(p as *const Ieee64)),
_ if ty.is_bool() => DataValue::B(ptr::read(p) != 0),
types::I8 => DataValue::I8(i8::from_le_bytes(src[..1].try_into().unwrap())),
types::I16 => DataValue::I16(i16::from_le_bytes(src[..2].try_into().unwrap())),
types::I32 => DataValue::I32(i32::from_le_bytes(src[..4].try_into().unwrap())),
types::I64 => DataValue::I64(i64::from_le_bytes(src[..8].try_into().unwrap())),
types::F32 => DataValue::F32(Ieee32::with_bits(u32::from_le_bytes(
src[..4].try_into().unwrap(),
))),
types::F64 => DataValue::F64(Ieee64::with_bits(u64::from_le_bytes(
src[..8].try_into().unwrap(),
))),
_ if ty.is_bool() => {
// Only `ty.bytes()` are guaranteed to be written
// so we can only test the first n bytes of `src`

let size = ty.bytes() as usize;
DataValue::B(src[..size].iter().any(|&i| i != 0))
}
_ if ty.is_vector() && ty.bytes() == 16 => {
DataValue::V128(ptr::read(p as *const [u8; 16]))
DataValue::V128(src[..16].try_into().unwrap())
}
_ => unimplemented!(),
}
}

/// Write a [DataValue] to a memory location.
pub unsafe fn write_value_to(&self, p: *mut u128) {
// Since `DataValue` does not have type info for bools we always
// write out a full 16 byte slot.
let size = match self.ty() {
ty if ty.is_bool() => 16,
ty => ty.bytes() as usize,
};

self.write_to_slice(std::slice::from_raw_parts_mut(p as *mut u8, size));
}

/// Read a [DataValue] from a memory location using a given [Type].
pub unsafe fn read_value_from(p: *const u128, ty: Type) -> Self {
DataValue::read_from_slice(
std::slice::from_raw_parts(p as *const u8, ty.bytes() as usize),
ty,
)
}
}

/// Record failures to cast [DataValue].
Expand Down
7 changes: 7 additions & 0 deletions cranelift/codegen/src/ir/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -421,6 +421,13 @@ impl Function {
self.dfg[dst] = self.dfg[src].clone();
self.layout.remove_inst(src);
}

/// Size occupied by all stack slots associated with this function.
///
/// Does not include any padding necessary due to offsets
pub fn stack_size(&self) -> u32 {
self.stack_slots.values().map(|ss| ss.size).sum()
}
}

/// Additional annotations for function display.
Expand Down
11 changes: 10 additions & 1 deletion cranelift/codegen/src/ir/instructions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ use crate::ir::{
self,
condcodes::{FloatCC, IntCC},
trapcode::TrapCode,
types, Block, FuncRef, JumpTable, MemFlags, SigRef, Type, Value,
types, Block, FuncRef, JumpTable, MemFlags, SigRef, StackSlot, Type, Value,
};
use crate::isa;

Expand Down Expand Up @@ -411,6 +411,15 @@ impl InstructionData {
}
}

/// If this instruction references a stack slot, return it
pub fn stack_slot(&self) -> Option<StackSlot> {
match self {
&InstructionData::StackStore { stack_slot, .. }
| &InstructionData::StackLoad { stack_slot, .. } => Some(stack_slot),
_ => None,
}
}

/// Return information about a call instruction.
///
/// Any instruction that can call another function reveals its call signature here.
Expand Down
85 changes: 85 additions & 0 deletions cranelift/filetests/filetests/runtests/stack-addr-32.clif
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
test interpret

function %stack_addr_iadd(i64) -> b1 {
ss0 = explicit_slot 16

block0(v0: i64):
v1 = stack_addr.i32 ss0
v2 = iadd_imm.i32 v1, 8

stack_store.i64 v0, ss0+8
v3 = load.i64 v2

v5 = iadd_imm.i64 v0, 20
store.i64 v5, v2
v6 = stack_load.i64 ss0+8

v7 = icmp eq v0, v3
v8 = icmp eq v5, v6
v9 = band v7, v8
return v9
}
; run: %stack_addr_iadd(0) == true
; run: %stack_addr_iadd(1) == true
; run: %stack_addr_iadd(-1) == true


function %stack_addr_32(i64) -> b1 {
ss0 = explicit_slot 24

block0(v0: i64):
v1 = stack_addr.i32 ss0
stack_store.i64 v0, ss0
v2 = load.i64 v1
v3 = icmp eq v0, v2

v4 = stack_addr.i32 ss0+8
store.i64 v0, v4
v5 = stack_load.i64 ss0+8
v6 = icmp eq v0, v5

v7 = stack_addr.i32 ss0+16
store.i64 v0, v7
v8 = load.i64 v7
v9 = icmp eq v0, v8

v10 = band v3, v6
v11 = band v10, v9
return v11
}
; run: %stack_addr_32(0) == true
; run: %stack_addr_32(1) == true
; run: %stack_addr_32(-1) == true



function %addr32_64(i64) -> b1 {
ss0 = explicit_slot 16

block0(v0: i64):
v1 = stack_addr.i32 ss0+8
v2 = stack_addr.i64 ss0+8

store.i64 v0, v1
v3 = load.i64 v2

v4 = icmp eq v3, v0

return v4
}
; run: %addr32_64(0) == true
; run: %addr32_64(1) == true
; run: %addr32_64(-1) == true


function %multi_slot_different_addrs() -> b1 {
ss0 = explicit_slot 8
ss1 = explicit_slot 8

block0:
v0 = stack_addr.i32 ss0
v1 = stack_addr.i32 ss1
v2 = icmp ne v0, v1
return v2
}
; run: %multi_slot_diffe() == true
56 changes: 56 additions & 0 deletions cranelift/filetests/filetests/runtests/stack-addr-64.clif
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
test interpret
test run
target x86_64 machinst
target s390x
target aarch64


function %stack_addr_iadd(i64) -> b1 {
ss0 = explicit_slot 16

block0(v0: i64):
v1 = stack_addr.i64 ss0
v2 = iadd_imm.i64 v1, 8

stack_store.i64 v0, ss0+8
v3 = load.i64 v2

v5 = iadd_imm.i64 v0, 20
store.i64 v5, v2
v6 = stack_load.i64 ss0+8

v7 = icmp eq v0, v3
v8 = icmp eq v5, v6
v9 = band v7, v8
return v9
}
; run: %stack_addr_iadd(0) == true
; run: %stack_addr_iadd(1) == true
; run: %stack_addr_iadd(-1) == true

function %stack_addr_64(i64) -> b1 {
ss0 = explicit_slot 24

block0(v0: i64):
v1 = stack_addr.i64 ss0
stack_store.i64 v0, ss0
v2 = load.i64 v1
v3 = icmp eq v0, v2

v4 = stack_addr.i64 ss0+8
store.i64 v0, v4
v5 = stack_load.i64 ss0+8
v6 = icmp eq v0, v5

v7 = stack_addr.i64 ss0+16
store.i64 v0, v7
v8 = load.i64 v7
v9 = icmp eq v0, v8

v10 = band v3, v6
v11 = band v10, v9
return v11
}
; run: %stack_addr_64(0) == true
; run: %stack_addr_64(1) == true
; run: %stack_addr_64(-1) == true
Loading