forked from M-Labs/artiq
Backport of "fixes alignment and size problem" from artiq-zynq (#1841)
This commit is contained in:
parent
93328ad8ee
commit
34008b7a21
|
@ -5,15 +5,20 @@ use byteorder::{NativeEndian, ByteOrder};
|
|||
use io::{ProtoRead, Read, Write, ProtoWrite, Error};
|
||||
use self::tag::{Tag, TagIterator, split_tag};
|
||||
|
||||
#[inline]
|
||||
fn alignment_offset(alignment: isize, ptr: isize) -> isize {
|
||||
(-ptr).rem_euclid(alignment)
|
||||
}
|
||||
|
||||
unsafe fn align_ptr<T>(ptr: *const ()) -> *const T {
|
||||
let alignment = core::mem::align_of::<T>() as isize;
|
||||
let fix = (alignment - (ptr as isize) % alignment) % alignment;
|
||||
let fix = alignment_offset(alignment as isize, ptr as isize);
|
||||
((ptr as isize) + fix) as *const T
|
||||
}
|
||||
|
||||
unsafe fn align_ptr_mut<T>(ptr: *mut ()) -> *mut T {
|
||||
let alignment = core::mem::align_of::<T>() as isize;
|
||||
let fix = (alignment - (ptr as isize) % alignment) % alignment;
|
||||
let fix = alignment_offset(alignment as isize, ptr as isize);
|
||||
((ptr as isize) + fix) as *mut T
|
||||
}
|
||||
|
||||
|
@ -54,6 +59,7 @@ unsafe fn recv_value<R, E>(reader: &mut R, tag: Tag, data: &mut *mut (),
|
|||
})
|
||||
}
|
||||
Tag::Tuple(it, arity) => {
|
||||
*data = data.offset(alignment_offset(tag.alignment() as isize, *data as isize));
|
||||
let mut it = it.clone();
|
||||
for _ in 0..arity {
|
||||
let tag = it.next().expect("truncated tag");
|
||||
|
@ -69,9 +75,12 @@ unsafe fn recv_value<R, E>(reader: &mut R, tag: Tag, data: &mut *mut (),
|
|||
let length = (*ptr).length as usize;
|
||||
|
||||
let tag = it.clone().next().expect("truncated tag");
|
||||
(*ptr).elements = alloc(tag.size() * (*ptr).length as usize)?;
|
||||
let padding = if let Tag::Int64 | Tag::Float64 = tag { 4 } else { 0 };
|
||||
let mut data = alloc(tag.size() * length + padding)?;
|
||||
|
||||
let mut data = (*ptr).elements;
|
||||
data = data.offset(alignment_offset(tag.alignment() as isize, data as isize));
|
||||
|
||||
(*ptr).elements = data;
|
||||
match tag {
|
||||
Tag::Bool => {
|
||||
let dest = slice::from_raw_parts_mut(data as *mut u8, length);
|
||||
|
@ -109,9 +118,11 @@ unsafe fn recv_value<R, E>(reader: &mut R, tag: Tag, data: &mut *mut (),
|
|||
let length = total_len as usize;
|
||||
|
||||
let elt_tag = it.clone().next().expect("truncated tag");
|
||||
*buffer = alloc(elt_tag.size() * total_len as usize)?;
|
||||
let padding = if let Tag::Int64 | Tag::Float64 = tag { 4 } else { 0 };
|
||||
let mut data = alloc(elt_tag.size() * length + padding)?;
|
||||
data = data.offset(alignment_offset(tag.alignment() as isize, data as isize));
|
||||
|
||||
let mut data = *buffer;
|
||||
*buffer = data;
|
||||
match elt_tag {
|
||||
Tag::Bool => {
|
||||
let dest = slice::from_raw_parts_mut(data as *mut u8, length);
|
||||
|
@ -139,6 +150,7 @@ unsafe fn recv_value<R, E>(reader: &mut R, tag: Tag, data: &mut *mut (),
|
|||
})
|
||||
}
|
||||
Tag::Range(it) => {
|
||||
*data = data.offset(alignment_offset(tag.alignment() as isize, *data as isize));
|
||||
let tag = it.clone().next().expect("truncated tag");
|
||||
recv_value(reader, tag, data, alloc)?;
|
||||
recv_value(reader, tag, data, alloc)?;
|
||||
|
@ -336,6 +348,7 @@ pub fn send_args<W>(writer: &mut W, service: u32, tag_bytes: &[u8], data: *const
|
|||
|
||||
mod tag {
|
||||
use core::fmt;
|
||||
use super::alignment_offset;
|
||||
|
||||
pub fn split_tag(tag_bytes: &[u8]) -> (&[u8], &[u8]) {
|
||||
let tag_separator =
|
||||
|
@ -385,6 +398,33 @@ mod tag {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn alignment(self) -> usize {
|
||||
use cslice::CSlice;
|
||||
match self {
|
||||
Tag::None => 1,
|
||||
Tag::Bool => core::mem::align_of::<u8>(),
|
||||
Tag::Int32 => core::mem::align_of::<i32>(),
|
||||
Tag::Int64 => core::mem::align_of::<i64>(),
|
||||
Tag::Float64 => core::mem::align_of::<f64>(),
|
||||
// struct type: align to largest element
|
||||
Tag::Tuple(it, arity) => {
|
||||
let it = it.clone();
|
||||
it.take(arity.into()).map(|t| t.alignment()).max().unwrap()
|
||||
},
|
||||
Tag::Range(it) => {
|
||||
let it = it.clone();
|
||||
it.take(3).map(|t| t.alignment()).max().unwrap()
|
||||
}
|
||||
// CSlice basically
|
||||
Tag::Bytes | Tag::String | Tag::ByteArray | Tag::List(_) =>
|
||||
core::mem::align_of::<CSlice<()>>(),
|
||||
// array buffer is allocated, so no need for alignment first
|
||||
Tag::Array(_, _) => 1,
|
||||
// will not be sent from the host
|
||||
_ => unreachable!("unexpected tag from host")
|
||||
}
|
||||
}
|
||||
|
||||
pub fn size(self) -> usize {
|
||||
match self {
|
||||
Tag::None => 0,
|
||||
|
@ -401,6 +441,7 @@ mod tag {
|
|||
for _ in 0..arity {
|
||||
let tag = it.next().expect("truncated tag");
|
||||
size += tag.size();
|
||||
size += alignment_offset(tag.alignment() as isize, size as isize) as usize;
|
||||
}
|
||||
size
|
||||
}
|
||||
|
@ -469,6 +510,13 @@ mod tag {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> Iterator for TagIterator<'a> {
|
||||
type Item = Tag<'a>;
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
(self as &mut TagIterator<'a>).next()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> fmt::Display for TagIterator<'a> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let mut it = self.clone();
|
||||
|
|
|
@ -515,3 +515,26 @@ class NumpyBoolTest(ExperimentCase):
|
|||
def test_numpy_bool(self):
|
||||
"""Test NumPy bools decay to ARTIQ compiler builtin bools as expected"""
|
||||
self.create(_NumpyBool).run()
|
||||
|
||||
|
||||
class _Alignment(EnvExperiment):
|
||||
def build(self):
|
||||
self.setattr_device("core")
|
||||
|
||||
@rpc
|
||||
def a_tuple(self) -> TList(TTuple([TBool, TFloat, TBool])):
|
||||
return [(True, 1234.5678, True)]
|
||||
|
||||
@kernel
|
||||
def run(self):
|
||||
a, b, c = self.a_tuple()[0]
|
||||
d, e, f = self.a_tuple()[0]
|
||||
assert a == d
|
||||
assert b == e
|
||||
assert c == f
|
||||
return 0
|
||||
|
||||
|
||||
class AlignmentTest(ExperimentCase):
|
||||
def test_tuple(self):
|
||||
self.create(_Alignment).run()
|
||||
|
|
Loading…
Reference in New Issue