LLVM: member alignment from data-layout - struct

I need to understand how to get member alignment in non-packed literal structures from the data layout.
As specified here, It's possible to get this info.
For example, I have this piece of code:
; ModuleID = 'fy4vsjaw.hjq.cpp'
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-pc-linux"
%struct.S = type { i8, i64 }
; Function Attrs: nounwind uwtable
define { i8, i64 } #foo() #0 !dbg !4 {
in the line %struct.S = type { i8, i64 } , what is the padding between two members here?
I'd expect 32 or 64 bits, but I'd like to be sure.
Thanks!

It's indeed written in the data layout. Such as specified in the data layout spec, this part i64:64 of the layout indicates that int64 are 64 bits aligned.
In the struct %struct.S = type { i8, i64 }, there is therefore a 7 byte padding between the two fields.
Programmatically, it's possible to get offset of member by index:
uint64_t GetOffset(llvm::Module* mod, llvm::StructType* st, uint32_t int index) {
return mod->getDataLayout()->getStructLayout(st)->getElementOffset(index);
}

Related

Align struct members but not struct itself

I'm writing some Rust code that interfaces with C. The C defines some structures like
struct foo {
// other fields
uint32_t count;
const struct bar* array;
};
I want to define a Rust structure with this layout, but for safety I want to put count and array in their own structure as private members, like so:
#[repr(C)]
pub struct Foo {
// other fields
pub bars: BarSlice,
}
#[repr(C)]
pub struct BarSlice {
count: u32,
ptr: *const Bar,
}
This is wrong though, since on 64-bit systems BarSlice will be aligned to 8 bytes, and the field immediately before count might be 8 byte aligned and 4 bytes long. How can I tell Rust to align the members of the struct correctly, but not worry about the struct itself?
I would also rather avoid if possible
creating a different slice type for each alignment circumstance
having private fields in Foo

Cannot set OpenCL kernel argument with buffer memory object

I have the following simple OpenCL kernel, that simply copies all entries pointed at a to b
__kernel void mmcopy(__global float* a, __global float* b) {
unsigned pos = get_global_id(0);
b[pos] = a[pos];
}
The following code snippet shows the opencl function calls for creating a buffer memory object out of four floats, and setting the first argument on the kernel with the buffer object.
let mut v = [1f32, 1f32, 1f32, 1f32];
let size = mem::size_of_val(&v) as size_t;
let mut error_buffer = 0 as i32;
let buffer = unsafe {
clCreateBuffer(
context.id.unwrap(),
(CL_MEM_COPY_HOST_PTR | CL_MEM_READ_WRITE) as u64,
size,
v.as_mut_ptr() as *mut c_void,
&mut error_buffer,
)
};
let real_size = mem::size_of::<cl_mem>() as size_t;
let error = unsafe {
clSetKernelArg(
self.id.unwrap(), // here `self` is a wrapper. `id` is of type `cl_kernel`
0 as cl_uint,
real_size,
buffer as *const c_void,
)
};
However, executing the code results in an error CL_INVALID_MEM_OBJECT.
it looks like creating the buffer didn't succeed, but returned without an error.
The spec is also not very precise when it comes to describe the error in more detail:
for an argument declared to be a memory object when the specified arg_value is not a valid memory object.
note: the OpenCL functions, and types have been generated by rust-bindgen.
update 1
To clarify how the opaque types are represented in rust, here is the representation of cl_mem,
pub struct _cl_mem {
_unused: [u8; 0],
}
pub type cl_mem = *mut _cl_mem;
the ffi to clSetKernelArg
extern "C" {
pub fn clSetKernelArg(
kernel: cl_kernel,
arg_index: cl_uint,
arg_size: size_t,
arg_value: *const ::std::os::raw::c_void,
) -> cl_int;
}
and clCreateBuffer
extern "C" {
pub fn clCreateBuffer(
context: cl_context,
flags: cl_mem_flags,
size: size_t,
host_ptr: *mut ::std::os::raw::c_void,
errcode_ret: *mut cl_int,
) -> cl_mem;
}
In my understanding rust(-bindgen) uses zero sized types (ZST) to represent external opaque types. So basically cl_mem is already a pointer.
update 2
According to pmdj's answer the correct way is to pass a pointer to the cl_mem buffer
let error = unsafe {
clSetKernelArg(
self.id.unwrap(), // here `self` is a wrapper. `id` is of type `cl_kernel`
0 as cl_uint,
real_size,
&buffer as *const _ as *const c_void,
)
};
That actually fixes the problem, and set the return value to CL_SUCCESS. The spec for clSetKernelArg also mentions a pointer to data
A pointer to data that should be used as the argument value for argument specified by arg_index. The argument data pointed to by arg_value is copied and the arg_value pointer can therefore be reused by the application after clSetKernelArg returns. The argument value specified is the value used by all API calls that enqueue kernel (clEnqueueNDRangeKernel) until the argument value is changed by a call to clSetKernelArg for kernel [...]
Before I dig in, I'll point out that I'm a relative beginner with Rust and I'm not particularly familiar with what bindgen produces, but I know OpenCL quite well. So please bear with me if my Rust syntax is off.
The most obvious thing that sticks out for me is that passing the buffer to clSetKernelArg using buffer as *const c_void looks suspicious. My understanding is that your code is roughly equivalent to this C:
cl_int error_buffer = 0;
cl_mem buffer = clCreateBuffer(
context.id,
(CL_MEM_COPY_HOST_PTR | CL_MEM_READ_WRITE),
size,
v,
&error_buffer
);
size_t real_size = siezof(buffer);
cl_int error = clSetKernelArg(self.id, 0, real_size, buffer);
However, the last line is incorrect, it should be:
cl_int error = clSetKernelArg(self.id, 0, real_size, &buffer);
// yes, we want a POINTER to the buffer handle-------^
Although cl_mem is defined as a pointer to an opaque struct type, you need to pass the pointer to that pointer as the argument, just as with any other type of kernel argument: conceptually, I find it useful to think of it as clSetKernelArg performing a memcpy(internal_buffer, arg_value, arg_size); internally - so arg_size must always be the size of the object pointed to by arg_value. I find this helps me work out the correct level of indirection.
So in Rust this is probably along the lines of:
let error = unsafe {
clSetKernelArg(
self.id.unwrap(),
0 as cl_uint,
real_size,
&buffer as *const c_void,
)
};
but I haven't run it past rustc so it's probably wrong. You get the drift though.

Difference between struct and enum

I'm confused about this statement from the Rust Book:
There’s another advantage to using an enum rather than a struct: each variant can have different types and amounts of associated data. Version four type IP addresses will always have four numeric components that will have values between 0 and 255. If we wanted to store V4 addresses as four u8 values but still express V6 addresses as one String value, we wouldn’t be able to with a struct. Enums handle this case with ease:
#![allow(unused_variables)]
fn main() {
enum IpAddr {
V4(u8, u8, u8, u8),
V6(String),
}
let home = IpAddr::V4(127, 0, 0, 1);
let loopback = IpAddr::V6(String::from("::1"));
}
But when I tried it with structs to store V4 addresses as four u8 values but still express V6 addresses as one String value its also doing the same without any errors.
#[derive(Debug)]
struct IpAddr {
V4:(u8, u8, u8, u8),
V6:String,
}
fn main () {
let home = IpAddr {
V4: (127, 1, 1, 1),
V6: String::from("Hello"),
};
println!("{:#?}", home);
}
It's not the same. All enum elements have the very same size! The size of an enum element is the size of the largest variant plus the variant identifier.
With a struct it's a bit different. If we ignore padding, the size of the struct is the sum of the sizes of its members. With padding it will be a bit more:
fn main() {
let size = std::mem::size_of::<TheEnum>();
println!("Enum: {}", size * 8);
let size = std::mem::size_of::<TheStruct>();
println!("Struct: {}", size * 8);
}
struct TheStruct {
a: u64,
b: u8,
c: u64
}
enum TheEnum {
A(u64),
B(u8),
C(u64)
}
Here we can see the difference:
Enum: 128; 64 for the largest variant and 64 for the variant identifier.
Struct: 192; aligned to 64 bits, so we have 54 bits of padding
Another difference is in the way you use enums and structures. In an enum, you have to initialize only one of the variants. In your case - either IPv4 or IPv6. With a structure as in your example you have to provide both V4 and v6 address. You cannot provide only V4 or only V6.

Struct with mixed bitflag and normal members

I'm trying to recreate a C struct with mixed bitfield members and "normal" members in Rust for FFI.
I've read that the bitflags crate would be the one to go with, unfortunately I find the documentation lacking on the regards how the syntax actually works.
The bitflags crate makes it easier to create bitmasks in a similar style as in C using enums. The bitfield crate claims to create bitfields that can be accessed, however I have no idea how it works.
I have a C structure like this:
struct mixed {
unsigned int flag_1_1 : 1;
unsigned int flag_2_7 : 7;
unsigned int flag_3_8 : 8;
unsigned int some_val1;
unsigned int some_val2;
unsigned int flag_4_16 : 16;
};
I have no clue on how to represent it in Rust, I'd use the crate libc to have access to c_uint, but other than that, I'm currently pretty much out of ideas and finding other code that does this has not proven successful:
#[repr(transparent)] // do I also need repr(C) ?
struct mixed {
flags_1_3: mixed_flags_1_3;
some_val1: c_uint;
some_val2: c_uint;
flags_4: mixed_flags_4;
}
bitfield!(
#[repr(transparent)] // do I also need repr(C), here too?
struct mixed_flags_1_3(u16 /* what about this parameter? */) {
u8; // what does this mean?
/* get/field, set: first bit, last bit; */
flag_1_1, _: 0, 0;
flag_2_7, _: 7, 1;
flag_3_8, _: 15, 8;
}
)
bitfield!(
#[repr(transparent)]
struct mixed_flags_4(u8) {
u8;
flag_4_16, _: 15, 0;
}
)
These are just guesses, how do I create a correct representation?
In cases like this you can look at genearted code by bindgen:
$ bindgen test.h
#[repr(C)]
#[derive(Copy, Clone, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct __BindgenBitfieldUnit<Storage, Align>
where
Storage: AsRef<[u8]> + AsMut<[u8]>,
{
storage: Storage,
align: [Align; 0],
}
//skipped code with access method for bit fields
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct mixed {
pub _bitfield_1: __BindgenBitfieldUnit<[u8; 2usize], u8>,
pub some_val1: ::std::os::raw::c_uint,
pub some_val2: ::std::os::raw::c_uint,
pub _bitfield_2: __BindgenBitfieldUnit<[u8; 2usize], u16>,
pub __bindgen_padding_0: u16,
}
Using rustc -- -Z unstable-options --pretty=expanded I think I could figure out that the macro does, and this seems to yield something that could be correct, however this is probably only compatible when the compiler does not try to pad or reorder the bitfields in the struct.
#[repr(transparent)] // do I also need repr(C) ?
struct mixed {
flags_1_3: mixed_flags_1_3;
some_val1: c_uint;
some_val2: c_uint;
flags_4: mixed_flags_4;
}
bitfield!(
#[repr(transparent)] // do I also need repr(C), here too?
// Results in a "tuple struct", ie. u16 = total size of bitfields
struct mixed_flags_1_3(u16) {
// All the following fields value should be treated as an
// unsigned int when accessed
c_uint;
/* get/field, set: first bit, last bit; */
flag_1_1, _: 0, 0;
flag_2_7, _: 7, 1;
// One could change the type again here, if one wanted to:
// u16
flag_3_8, _: 15, 8;
}
)
bitfield!(
#[repr(transparent)]
struct mixed_flags_4(u16) {
c_uint;
flag_4_16, _: 15, 0;
}
)
But for now at least I think I will just use libclang and bindgen as dependencies and generate my bindings automatically, due to the aforementioned problems with platform compat.

Fitting string literals for different string classes

The problem
I am implementing a class where I want to let the user choose the string type (std::string, std::wstring, std::u16string, ...) via a template parameter. I currently fail to make the string literals fit the chosen string type: Once I decide for a literal prefix ("hello" vs. L"hello" vs. u"hello" vs. U"hello"), I get compilation errors for all incompatible string classes.
Toy example
As an example, consider the following code (compile with --std=c++11):
#include <string>
template<typename StringType>
void hello_string()
{
StringType result("hello");
}
int main()
{
// works
hello_string<std::string>();
hello_string<std::basic_string<char>>();
// the code below does not compile
hello_string<std::wstring>();
hello_string<std::basic_string<unsigned char>>();
hello_string<std::u16string>();
}
Function hello_string() shows the essence of what I want to do: have a string type as template parameter, and assign string literals to variables of this type.
Possible workaround
One way to overcome my problem would be to implement several specializations of the hello_string() function. The problem is that this would lead to several copies of each string literal - one for each string literal prefix. I think this is rather ugly, and there must be better way.
Another way could be to chose "normal" string literals as default values and have functions do a conversion to the different string types. While this would avoid code duplication, it would introduce unnecessary conversions of something that is actually constant.
You can make yourself a macro. First define a struct that wraps the char-choosing:
namespace details {
template<typename T>
struct templ_text;
template<>
struct templ_text <char>
{
typedef char char_type;
static const char_type * choose(const char * narrow, const wchar_t * wide, const char16_t* u16, const char32_t* u32) { return narrow; }
static char_type choose(char narrow, wchar_t wide, char16_t u16, char32_t u32) { return narrow; }
};
template<>
struct templ_text < wchar_t >
{
typedef wchar_t char_type;
static const char_type* choose(const char * narrow, const wchar_t * wide, const char16_t* u16, const char32_t* u32) { return wide; }
static char_type choose(char narrow, wchar_t wide, char16_t u16, char32_t u32) { return wide; }
};
template<>
struct templ_text < char16_t >
{
typedef char16_t char_type;
static const char_type* choose(const char * narrow, const wchar_t * wide, const char16_t* u16, const char32_t* u32) { return u16; }
static char_type choose(char narrow, wchar_t wide, char16_t u16, char32_t u32) { return u16; }
};
template<>
struct templ_text < char32_t >
{
typedef char32_t char_type;
static const char_type* choose(const char * narrow, const wchar_t * wide, const char16_t* u16, const char32_t* u32) { return u32; }
static char_type choose(char narrow, wchar_t wide, char16_t u16, char32_t u32) { return u32; }
};
}
Wrap it into a nice macro:
#define TEMPL_TEXT(Ch, txt) details::templ_text<Ch>::choose(txt, L##txt, u##txt, U##txt)
Then your function would be:
template<typename StringType>
void hello_string()
{
StringType result(TEMPL_TEXT(typename StringType::value_type, "Hello"));
}
I think that unused copies of the string will be optimized away.

Resources