From 937cae331e47c82924b38ff35bc2d9d003ce0220 Mon Sep 17 00:00:00 2001 From: sagudev <16504129+sagudev@users.noreply.github.com> Date: Fri, 20 Oct 2023 10:43:55 +0200 Subject: [PATCH] float16 --- .../expectations/tests/libclang-5/float16.rs | 1 + .../expectations/tests/libclang-9/float16.rs | 224 ++++++++++++++++++ bindgen-tests/tests/headers/float16.h | 24 ++ bindgen/codegen/helpers.rs | 9 + bindgen/codegen/mod.rs | 17 ++ bindgen/codegen/serialize.rs | 2 + bindgen/ir/context.rs | 16 ++ bindgen/ir/ty.rs | 2 + 8 files changed, 295 insertions(+) create mode 100644 bindgen-tests/tests/expectations/tests/libclang-5/float16.rs create mode 100644 bindgen-tests/tests/expectations/tests/libclang-9/float16.rs create mode 100644 bindgen-tests/tests/headers/float16.h diff --git a/bindgen-tests/tests/expectations/tests/libclang-5/float16.rs b/bindgen-tests/tests/expectations/tests/libclang-5/float16.rs new file mode 100644 index 0000000000..996b877e50 --- /dev/null +++ b/bindgen-tests/tests/expectations/tests/libclang-5/float16.rs @@ -0,0 +1 @@ +/* error generating bindings */ diff --git a/bindgen-tests/tests/expectations/tests/libclang-9/float16.rs b/bindgen-tests/tests/expectations/tests/libclang-9/float16.rs new file mode 100644 index 0000000000..69deaa2fec --- /dev/null +++ b/bindgen-tests/tests/expectations/tests/libclang-9/float16.rs @@ -0,0 +1,224 @@ +#![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)] +#[derive(PartialEq, Copy, Clone, Hash, Debug, Default)] +#[repr(C)] +pub struct __BindgenComplex { + pub re: T, + pub im: T, +} +#[derive(PartialEq, Copy, Clone, Hash, Debug, Default)] +#[repr(C)] +pub struct __BindgenFloat16(pub u16); +extern "C" { + pub static mut global: __BindgenFloat16; +} +#[repr(C)] +#[derive(Debug, Default, Copy, Clone, PartialEq)] +pub struct A { + pub f: __BindgenFloat16, +} +#[test] +fn bindgen_test_layout_A() { + const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!(::std::mem::size_of::(), 2usize, concat!("Size of: ", stringify!(A))); + assert_eq!( + ::std::mem::align_of::(), + 2usize, + concat!("Alignment of ", stringify!(A)), + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).f) as usize - ptr as usize }, + 0usize, + concat!("Offset of field: ", stringify!(A), "::", stringify!(f)), + ); +} +#[repr(C)] +#[derive(Debug, Default, Copy, Clone, PartialEq)] +pub struct TestDouble { + pub mMember: __BindgenComplex, +} +#[test] +fn bindgen_test_layout_TestDouble() { + const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 16usize, + concat!("Size of: ", stringify!(TestDouble)), + ); + assert_eq!( + ::std::mem::align_of::(), + 8usize, + concat!("Alignment of ", stringify!(TestDouble)), + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).mMember) as usize - ptr as usize }, + 0usize, + concat!("Offset of field: ", stringify!(TestDouble), "::", stringify!(mMember)), + ); +} +#[repr(C)] +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +pub struct TestDoublePtr { + pub mMember: *mut __BindgenComplex, +} +#[test] +fn bindgen_test_layout_TestDoublePtr() { + const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 8usize, + concat!("Size of: ", stringify!(TestDoublePtr)), + ); + assert_eq!( + ::std::mem::align_of::(), + 8usize, + concat!("Alignment of ", stringify!(TestDoublePtr)), + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).mMember) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(TestDoublePtr), + "::", + stringify!(mMember), + ), + ); +} +impl Default for TestDoublePtr { + fn default() -> Self { + let mut s = ::std::mem::MaybeUninit::::uninit(); + unsafe { + ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); + s.assume_init() + } + } +} +#[repr(C)] +#[derive(Debug, Default, Copy, Clone, PartialEq)] +pub struct TestFloat { + pub mMember: __BindgenComplex, +} +#[test] +fn bindgen_test_layout_TestFloat() { + const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 8usize, + concat!("Size of: ", stringify!(TestFloat)), + ); + assert_eq!( + ::std::mem::align_of::(), + 4usize, + concat!("Alignment of ", stringify!(TestFloat)), + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).mMember) as usize - ptr as usize }, + 0usize, + concat!("Offset of field: ", stringify!(TestFloat), "::", stringify!(mMember)), + ); +} +#[repr(C)] +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +pub struct TestFloatPtr { + pub mMember: *mut __BindgenComplex, +} +#[test] +fn bindgen_test_layout_TestFloatPtr() { + const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 8usize, + concat!("Size of: ", stringify!(TestFloatPtr)), + ); + assert_eq!( + ::std::mem::align_of::(), + 8usize, + concat!("Alignment of ", stringify!(TestFloatPtr)), + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).mMember) as usize - ptr as usize }, + 0usize, + concat!("Offset of field: ", stringify!(TestFloatPtr), "::", stringify!(mMember)), + ); +} +impl Default for TestFloatPtr { + fn default() -> Self { + let mut s = ::std::mem::MaybeUninit::::uninit(); + unsafe { + ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); + s.assume_init() + } + } +} +#[repr(C)] +#[derive(Debug, Default, Copy, Clone, PartialEq)] +pub struct Test_Float16 { + pub mMember: __BindgenComplex, +} +#[test] +fn bindgen_test_layout_Test_Float16() { + const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 8usize, + concat!("Size of: ", stringify!(Test_Float16)), + ); + assert_eq!( + ::std::mem::align_of::(), + 4usize, + concat!("Alignment of ", stringify!(Test_Float16)), + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).mMember) as usize - ptr as usize }, + 0usize, + concat!("Offset of field: ", stringify!(Test_Float16), "::", stringify!(mMember)), + ); +} +#[repr(C)] +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +pub struct Test_Float16Ptr { + pub mMember: *mut __BindgenComplex, +} +#[test] +fn bindgen_test_layout_Test_Float16Ptr() { + const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 8usize, + concat!("Size of: ", stringify!(Test_Float16Ptr)), + ); + assert_eq!( + ::std::mem::align_of::(), + 8usize, + concat!("Alignment of ", stringify!(Test_Float16Ptr)), + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).mMember) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(Test_Float16Ptr), + "::", + stringify!(mMember), + ), + ); +} +impl Default for Test_Float16Ptr { + fn default() -> Self { + let mut s = ::std::mem::MaybeUninit::::uninit(); + unsafe { + ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); + s.assume_init() + } + } +} +extern "C" { + pub static mut globalValueHalf: __BindgenComplex<__BindgenFloat16>; +} diff --git a/bindgen-tests/tests/headers/float16.h b/bindgen-tests/tests/headers/float16.h new file mode 100644 index 0000000000..4e2f075586 --- /dev/null +++ b/bindgen-tests/tests/headers/float16.h @@ -0,0 +1,24 @@ +// bindgen-flags: --with-derive-hash --with-derive-partialeq --with-derive-eq + +static _Float16 global; + +struct A +{ + _Float16 f; +}; + +#define COMPLEX_TEST(ty_, name_) \ + struct Test##name_ \ + { \ + ty_ _Complex mMember; \ + }; \ + struct Test##name_##Ptr \ + { \ + ty_ _Complex *mMember; \ + }; + +COMPLEX_TEST(double, Double) +COMPLEX_TEST(float, Float) +COMPLEX_TEST(float, _Float16) + +_Float16 _Complex globalValueHalf; \ No newline at end of file diff --git a/bindgen/codegen/helpers.rs b/bindgen/codegen/helpers.rs index 7ef44fe099..48bfe56dde 100644 --- a/bindgen/codegen/helpers.rs +++ b/bindgen/codegen/helpers.rs @@ -232,6 +232,15 @@ pub(crate) mod ast_ty { // // Also, maybe this one shouldn't be the default? match (fk, ctx.options().convert_floats) { + (FloatKind::Float16, _) => { + // TODO: do f16 when rust lands it + ctx.generated_bindgen_float16(); + if ctx.options().enable_cxx_namespaces { + syn::parse_quote! { root::__BindgenFloat16 } + } else { + syn::parse_quote! { __BindgenFloat16 } + } + } (FloatKind::Float, true) => syn::parse_quote! { f32 }, (FloatKind::Double, true) => syn::parse_quote! { f64 }, (FloatKind::Float, false) => raw_type(ctx, "c_float"), diff --git a/bindgen/codegen/mod.rs b/bindgen/codegen/mod.rs index 8e13606345..c1dd45bbcd 100644 --- a/bindgen/codegen/mod.rs +++ b/bindgen/codegen/mod.rs @@ -578,6 +578,9 @@ impl CodeGenerator for Module { if result.saw_incomplete_array { utils::prepend_incomplete_array_types(ctx, &mut *result); } + if ctx.need_bindgen_float16_type() { + utils::prepend_float16_type(&mut *result); + } if ctx.need_bindgen_complex_type() { utils::prepend_complex_type(&mut *result); } @@ -5136,6 +5139,20 @@ pub(crate) mod utils { result.extend(old_items); } + pub(crate) fn prepend_float16_type( + result: &mut Vec, + ) { + let float16_type = quote! { + #[derive(PartialEq, Copy, Clone, Hash, Debug, Default)] + #[repr(C)] + pub struct __BindgenFloat16(pub u16); + }; + + let items = vec![float16_type]; + let old_items = mem::replace(result, items); + result.extend(old_items); + } + pub(crate) fn prepend_complex_type( result: &mut Vec, ) { diff --git a/bindgen/codegen/serialize.rs b/bindgen/codegen/serialize.rs index 02c4680263..9765a8bdf2 100644 --- a/bindgen/codegen/serialize.rs +++ b/bindgen/codegen/serialize.rs @@ -270,6 +270,7 @@ impl<'a> CSerialize<'a> for Type { write!(writer, "const ")?; } match float_kind { + FloatKind::Float16 => write!(writer, "_Float16")?, FloatKind::Float => write!(writer, "float")?, FloatKind::Double => write!(writer, "double")?, FloatKind::LongDouble => write!(writer, "long double")?, @@ -281,6 +282,7 @@ impl<'a> CSerialize<'a> for Type { write!(writer, "const ")?; } match float_kind { + FloatKind::Float16 => write!(writer, "_Float16 complex")?, FloatKind::Float => write!(writer, "float complex")?, FloatKind::Double => write!(writer, "double complex")?, FloatKind::LongDouble => { diff --git a/bindgen/ir/context.rs b/bindgen/ir/context.rs index c5e2832cc9..11048b70c8 100644 --- a/bindgen/ir/context.rs +++ b/bindgen/ir/context.rs @@ -386,6 +386,9 @@ pub(crate) struct BindgenContext { /// Whether a bindgen complex was generated generated_bindgen_complex: Cell, + /// Whether a bindgen float16 was generated + generated_bindgen_float16: Cell, + /// The set of `ItemId`s that are allowlisted. This the very first thing /// computed after parsing our IR, and before running any of our analyses. allowlisted: Option, @@ -585,6 +588,7 @@ If you encounter an error missing from this list, please file an issue or a PR!" target_info, options, generated_bindgen_complex: Cell::new(false), + generated_bindgen_float16: Cell::new(false), allowlisted: None, blocklisted_types_implement_traits: Default::default(), codegen_items: None, @@ -2005,6 +2009,7 @@ If you encounter an error missing from this list, please file an issue or a PR!" CXType_ULongLong => TypeKind::Int(IntKind::ULongLong), CXType_Int128 => TypeKind::Int(IntKind::I128), CXType_UInt128 => TypeKind::Int(IntKind::U128), + CXType_Float16 | CXType_Half => TypeKind::Float(FloatKind::Float16), CXType_Float => TypeKind::Float(FloatKind::Float), CXType_Double => TypeKind::Float(FloatKind::Double), CXType_LongDouble => TypeKind::Float(FloatKind::LongDouble), @@ -2013,6 +2018,7 @@ If you encounter an error missing from this list, please file an issue or a PR!" let float_type = ty.elem_type().expect("Not able to resolve complex type?"); let float_kind = match float_type.kind() { + CXType_Float16 | CXType_Half => FloatKind::Float16, CXType_Float => FloatKind::Float, CXType_Double => FloatKind::Double, CXType_LongDouble => FloatKind::LongDouble, @@ -2528,6 +2534,16 @@ If you encounter an error missing from this list, please file an issue or a PR!" self.generated_bindgen_complex.get() } + /// Call if a bindgen float16 is generated + pub(crate) fn generated_bindgen_float16(&self) { + self.generated_bindgen_float16.set(true) + } + + /// Whether we need to generate the bindgen float16 type + pub(crate) fn need_bindgen_float16_type(&self) -> bool { + self.generated_bindgen_float16.get() + } + /// Compute which `enum`s have an associated `typedef` definition. fn compute_enum_typedef_combos(&mut self) { let _t = self.timer("compute_enum_typedef_combos"); diff --git a/bindgen/ir/ty.rs b/bindgen/ir/ty.rs index 1aee065970..b7a429323e 100644 --- a/bindgen/ir/ty.rs +++ b/bindgen/ir/ty.rs @@ -558,6 +558,8 @@ impl TemplateParameters for TypeKind { /// The kind of float this type represents. #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub(crate) enum FloatKind { + /// A half (`_Float16` or `__fp16`) + Float16, /// A `float`. Float, /// A `double`.