Backport of "fixes alignment and size problem" from artiq-zynq (#1841)

This commit is contained in:
Steve Fan 2022-01-28 20:49:55 +08:00 committed by GitHub
parent 93328ad8ee
commit 34008b7a21
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 77 additions and 6 deletions

View File

@ -5,15 +5,20 @@ use byteorder::{NativeEndian, ByteOrder};
use io::{ProtoRead, Read, Write, ProtoWrite, Error}; use io::{ProtoRead, Read, Write, ProtoWrite, Error};
use self::tag::{Tag, TagIterator, split_tag}; 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 { unsafe fn align_ptr<T>(ptr: *const ()) -> *const T {
let alignment = core::mem::align_of::<T>() as isize; 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 ((ptr as isize) + fix) as *const T
} }
unsafe fn align_ptr_mut<T>(ptr: *mut ()) -> *mut T { unsafe fn align_ptr_mut<T>(ptr: *mut ()) -> *mut T {
let alignment = core::mem::align_of::<T>() as isize; 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 ((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) => { Tag::Tuple(it, arity) => {
*data = data.offset(alignment_offset(tag.alignment() as isize, *data as isize));
let mut it = it.clone(); let mut it = it.clone();
for _ in 0..arity { for _ in 0..arity {
let tag = it.next().expect("truncated tag"); 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 length = (*ptr).length as usize;
let tag = it.clone().next().expect("truncated tag"); 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 { match tag {
Tag::Bool => { Tag::Bool => {
let dest = slice::from_raw_parts_mut(data as *mut u8, length); 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 length = total_len as usize;
let elt_tag = it.clone().next().expect("truncated tag"); 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 { match elt_tag {
Tag::Bool => { Tag::Bool => {
let dest = slice::from_raw_parts_mut(data as *mut u8, length); 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) => { Tag::Range(it) => {
*data = data.offset(alignment_offset(tag.alignment() as isize, *data as isize));
let tag = it.clone().next().expect("truncated tag"); let tag = it.clone().next().expect("truncated tag");
recv_value(reader, tag, data, alloc)?; recv_value(reader, tag, data, alloc)?;
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 { mod tag {
use core::fmt; use core::fmt;
use super::alignment_offset;
pub fn split_tag(tag_bytes: &[u8]) -> (&[u8], &[u8]) { pub fn split_tag(tag_bytes: &[u8]) -> (&[u8], &[u8]) {
let tag_separator = 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 { pub fn size(self) -> usize {
match self { match self {
Tag::None => 0, Tag::None => 0,
@ -401,6 +441,7 @@ mod tag {
for _ in 0..arity { for _ in 0..arity {
let tag = it.next().expect("truncated tag"); let tag = it.next().expect("truncated tag");
size += tag.size(); size += tag.size();
size += alignment_offset(tag.alignment() as isize, size as isize) as usize;
} }
size 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> { impl<'a> fmt::Display for TagIterator<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut it = self.clone(); let mut it = self.clone();

View File

@ -515,3 +515,26 @@ class NumpyBoolTest(ExperimentCase):
def test_numpy_bool(self): def test_numpy_bool(self):
"""Test NumPy bools decay to ARTIQ compiler builtin bools as expected""" """Test NumPy bools decay to ARTIQ compiler builtin bools as expected"""
self.create(_NumpyBool).run() 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()