-
Notifications
You must be signed in to change notification settings - Fork 785
Description
Hi guys,
I developing a Rust wrapper for the Embree library. This library heavily relies on processor vector operation (SSE, AVX) to provide high performance. For now, I use explicit FFI declaration to interface with Embree. However, I was planning to use rust-bindgen to generate this interface automatically.
However, when I use bindgen, the code does not align correctly compared to what it is specified in the C++ header. Moreover, the test code generated by bindgen does not include a test to check if the current rust code have the proper alignment.
Input C/C++ Header
Extracted code from Embree (v2)
#ifdef _WIN32
# define RTCORE_ALIGN(...) __declspec(align(__VA_ARGS__))
#else
# define RTCORE_ALIGN(...) __attribute__((aligned(__VA_ARGS__)))
#endif
// ....
struct RTCORE_ALIGN(16) RTCRay
{
/* ray data */
public:
float org[3]; //!< Ray origin
float align0;
float dir[3]; //!< Ray direction
float align1;
float tnear; //!< Start of ray segment
float tfar; //!< End of ray segment (set to hit distance)
float time; //!< Time of this ray for motion blur
unsigned mask; //!< Used to mask out objects during traversal
/* hit data */
public:
float Ng[3]; //!< Unnormalized geometry normal
float align2;
float u; //!< Barycentric u coordinate of hit
float v; //!< Barycentric v coordinate of hit
unsigned geomID; //!< geometry ID
unsigned primID; //!< primitive ID
unsigned instID; //!< instance ID
};Bindgen Invocation
let bindings = bindgen::Builder::default()
.clang_args(["-x", "c++", "-std=c++11"].iter())
.enable_cxx_namespaces()
.blacklist_type("max_align_t")
.header("wrapper.h")
.generate()
.expect("Unable to generate bindings");Actual Results
The code generated by rust-bindgen
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct RTCRay {
pub org: [f32; 3usize],
pub align0: f32,
pub dir: [f32; 3usize],
pub align1: f32,
pub tnear: f32,
pub tfar: f32,
pub time: f32,
pub mask: ::std::os::raw::c_uint,
pub Ng: [f32; 3usize],
pub align2: f32,
pub u: f32,
pub v: f32,
pub geomID: ::std::os::raw::c_uint,
pub primID: ::std::os::raw::c_uint,
pub instID: ::std::os::raw::c_uint,
pub __bindgen_padding_0: [u32; 3usize]
}
#[test]
fn bindgen_test_layout_RTCRay() {
assert_eq!(::std::mem::size_of::<RTCRay>(), 96usize, concat!( "Size of: " , stringify ! ( RTCRay ) ));
assert_eq!(unsafe { &(*(::std::ptr::null::<RTCRay>())).org as *const _ as usize }, 0usize, concat!( "Offset of field: " , stringify ! ( RTCRay ) , "::" , stringify ! ( org ) ));
assert_eq!(unsafe { &(*(::std::ptr::null::<RTCRay>())).align0 as *const _ as usize }, 12usize, concat!( "Offset of field: " , stringify ! ( RTCRay ) , "::" , stringify ! ( align0 ) ));
assert_eq!(unsafe { &(*(::std::ptr::null::<RTCRay>())).dir as *const _ as usize }, 16usize, concat!( "Offset of field: " , stringify ! ( RTCRay ) , "::" , stringify ! ( dir ) ));
assert_eq!(unsafe { &(*(::std::ptr::null::<RTCRay>())).align1 as *const _ as usize }, 28usize, concat!( "Offset of field: " , stringify ! ( RTCRay ) , "::" , stringify ! ( align1 ) ));
assert_eq!(unsafe { &(*(::std::ptr::null::<RTCRay>())).tnear as *const _ as usize }, 32usize, concat!( "Offset of field: " , stringify ! ( RTCRay ) , "::" , stringify ! ( tnear ) ));
assert_eq!(unsafe { &(*(::std::ptr::null::<RTCRay>())).tfar as *const _ as usize }, 36usize, concat!( "Offset of field: " , stringify ! ( RTCRay ) , "::" , stringify ! ( tfar ) ));
assert_eq!(unsafe { &(*(::std::ptr::null::<RTCRay>())).time as *const _ as usize }, 40usize, concat!( "Offset of field: " , stringify ! ( RTCRay ) , "::" , stringify ! ( time ) ));
assert_eq!(unsafe { &(*(::std::ptr::null::<RTCRay>())).mask as *const _ as usize }, 44usize, concat!( "Offset of field: " , stringify ! ( RTCRay ) , "::" , stringify ! ( mask ) ));
assert_eq!(unsafe { &(*(::std::ptr::null::<RTCRay>())).Ng as *const _ as usize }, 48usize, concat!( "Offset of field: " , stringify ! ( RTCRay ) , "::" , stringify ! ( Ng ) ));
assert_eq!(unsafe { &(*(::std::ptr::null::<RTCRay>())).align2 as *const _ as usize }, 60usize, concat!( "Offset of field: " , stringify ! ( RTCRay ) , "::" , stringify ! ( align2 ) ));
assert_eq!(unsafe { &(*(::std::ptr::null::<RTCRay>())).u as *const _ as usize }, 64usize, concat!( "Offset of field: " , stringify ! ( RTCRay ) , "::" , stringify ! ( u ) ));
assert_eq!(unsafe { &(*(::std::ptr::null::<RTCRay>())).v as *const _ as usize }, 68usize, concat!( "Offset of field: " , stringify ! ( RTCRay ) , "::" , stringify ! ( v ) ));
assert_eq!(unsafe { &(*(::std::ptr::null::<RTCRay>())).geomID as *const _ as usize }, 72usize, concat!( "Offset of field: " , stringify ! ( RTCRay ) , "::" , stringify ! ( geomID ) ));
assert_eq!(unsafe { &(*(::std::ptr::null::<RTCRay>())).primID as *const _ as usize }, 76usize, concat!( "Offset of field: " , stringify ! ( RTCRay ) , "::" , stringify ! ( primID ) ));
assert_eq!(unsafe { &(*(::std::ptr::null::<RTCRay>())).instID as *const _ as usize }, 80usize, concat!( "Offset of field: " , stringify ! ( RTCRay ) , "::" , stringify ! ( instID ) ));
}The test that I have inside my lib.rs:
#[test]
fn test_ray_align() {
assert_eq!(::std::mem::align_of::<root::RTCRay>(), 16usize);
}this test failed and give me this output:
---- test_ray_align stdout ----
thread 'test_ray_align' panicked at 'assertion failed: `(left == right)`
left: `4`,
right: `16`', src/lib.rs:22:5
note: Run with `RUST_BACKTRACE=1` for a backtrace.
failures:
test_ray_align
Expected Results
From bindgen call, I was expecting two things:
#[repr(C,align(16))](compared to#[repr(C)])- adding:
assert_eq!(::std::mem::align_of::<RTCRay>(), 16usize);inside the test suite.
Does rust-bindgen have a way to generate this test and have explicit align automatically?
Thanks guys for your awsome tool. Hope that I can use it inside my project :)
Version
rustup 1.11.0, stable rust 1.25.0 (84203cac6 2018-03-25), version bindgen: "0.35.0"
My embree wrapper: https://github.com/beltegeuse/embree-rs (branch: bindgen)