I'm trying to create an LLVM value of a structure type. I'm using LLVM-C interface and find a function:
LLVMValueRef LLVMConstStruct (LLVMValueRef *ConstantVals, unsigned Count, LLVMBool Packed)
This works fine if all members are constant value created by LLVMConstXXX(), it will generate code like:
store { i32, i32, i32 } { i32 1, i32 2, i32 3 }, { i32, i32, i32 }* %17, align 4
But the problem is if the member is not constant, it will generate things like:
%0 = call i32 #llvm.nvvm.read.ptx.sreg.tid.x()
store { i32, i32, i32 } { i32 1, i32 %0, i32 3 }, { i32, i32, i32 }* %17, align 4
And when I send this piece of LLVM code to NVVM (Nvidia PTX backend), it says:
module 0 (27, 39): parse error: invalid use of function-local name
So, I don't know if this struct value creating is a correct. What I need is a value, not an allocated memory.
Anyone has idea?
Regards,
Xiang.
A constant struct is a kind of literal that - loyal to its name - may only contain other constants, not general values. The correct way to generate that struct, then, is via insertvalue. In your example above, it should look like this:
%0 = call i32 #llvm.nvvm.read.ptx.sreg.tid.x()
%1 = insertvalue {i32, i32, i32} {i32 1, i32 undef, i32 3}, i32 %0, 1
store { i32, i32, i32 } %1, { i32, i32, i32 }* %17, align 4
Related
TL;DR: I thought that the packed attribute in Rust always strips any padding between the fields but apparently this is only true for packed(1).
I want my struct to represent the exact bytes in memory without any additional padding between fields but the struct also needs to be page-aligned. The compiler output isn't what I expect it to be in my code example. From the language reference [0] I found, that packed(N) aligns the struct to a N-byte boundary. I expected that only the beginning of the struct is aligned while there is never padding between the fields. However, I found out that:
#[repr(C, packed(4096)]
struct Foo {
first: u8,
second: u32,
}
let foo = Foo { first: 0, second: 0 };
println!("foo is page-aligned: {}", &foo as *const _ as usize & 0xfff == 0);
println!("{:?}", &foo.first as *const _);
println!("{:?}", &foo.second as *const _);
println!("padding between fields: {}", &foo.second as *const _ as usize - &foo.first as *const _ as usize);
results in
foo is page-aligned: false
0x7ffc85be5eb8
0x7ffc85be5ebc
padding between fields: 4
Why is the struct not page-aligned and why is there padding between the fields? I found out that I can achieve what I want with
#[repr(align(4096))]
struct PageAligned<T>(T);
#[repr(C, packed)]
struct Foo {
first: u8,
second: u32,
}
let foo = Foo { first: 0, second: 0 };
let aligned_foo = PageAligned(Foo { first: 0, second: 0 });
it results in
foo is page-aligned: true
0x7ffd18c12000
0x7ffd18c12001
padding between fields: 1
but I think this is counter-intuitive. Is this how it is supposed to work? I'm on Rust stable 1.57.
To meet the requirements with the available tools, your best option may be to construct a substitute for your u32 field which naturally has an alignment of 1:
#[repr(C, align(4096))]
struct Foo {
first: u8,
second: [u8; 4],
}
impl Foo {
fn second(&self) -> u32 {
u32::from_ne_bytes(self.second)
}
fn set_second(&mut self, value: u32) {
self.second = u32::to_ne_bytes(value);
}
}
This struct's layout passes your tests.
I have a struct that has 20 fields:
struct StructA {
value1: i32,
value2: i32,
// ...
value19: i32,
day: chrono::NaiveDate,
}
I'd like to impl Default trait for StructA. I tried to add #[derive(Default)] to the struct, but chrono::NaiveDate doesn't implement Default.
I then tried to implement Default for StructA:
impl Default for StructA {
fn default() -> Self {
Self {
value1: Default::default(),
value2: Default::default(),
// ...
value19: Default::default(),
day: chrono::NaiveDate::from_ymd(2021, 1, 1),
}
}
}
This code works fine, but the parts of value1 through value19 are redundant. Is there a solution with less code?
I defined StructA to deserialize JSON data via serde-json so I can't change the struct's definition.
A value of day: chrono::NaiveDate is always given from JSON data, so I want to avoid day: Option<chrono::NaiveDate>.
The derivative crate makes this kind of thing a breeze:
#[derive(Derivative)]
#[derivative(Default)]
struct StructA {
value1: i32,
value2: i32,
// ...
value19: i32,
#[derivative(Default(value = "NaiveDate::from_ymd(2021, 1, 1)"))]
day: NaiveDate,
}
If you want to avoid external crates, your options are:
the approach you already used, with the downside that you must name all the fields. Also note that you don't need to repeat Default::default() for each numeric field, a simple 0 will work as well.
make day an Option and derive Default, with the downside that it will default to None, bear a run-time cost, and you'll have to unwrap() to access it.
make day a newtype that wraps NaiveDate and implements Default to set it to the desired value, with the downside that you'll need to access the NaiveDate through a (zero-cost) field or method.
That's a rather dirty trick, but you can wrap your date in an Option, and it has an implementation of Default. Then you won't need to implement Default on your own, you can derive it. To keep the same semantics of StructA::default() you'll need to write your own method (luckily Rust allows to define default() method besides already derived Default::default()) Playground
use chrono;
#[derive(Debug, Default)]
struct StructA {
value1: i32,
value2: i32,
value19: i32,
day: Option<chrono::NaiveDate>,
}
impl StructA {
fn default() -> Self {
let mut instance: Self = Default::default();
instance.day = Some(chrono::NaiveDate::from_ymd(2021, 1, 1));
instance
}
}
fn main() {
println!("{:?}", StructA::default());
// StructA { value1: 0, value2: 0, value19: 0, day: Some(2021-01-01) }
}
Downsides of this version:
Need to .unwrap() the date everywhere it's used
Two methods with same name default, but one is Self::default which fills the date as I implemented and the other is Default::default which fills the date with None, you'll need to be careful which you call (calling StructA::default() invokes Self::default())
EDIT. Please be careful with this answer (details in the comments by #user4815162342)
In short - the last downside of having two different .default() methods in one type is dangerous in generic methods with T: Default arguments, because in this case will be called Default::default(), which initializes the day field to None. The worst part of this effect, is that compiler won't ever warn you about it, thus forcing you to spend your time debugging in case of a bug.
There's one similar approach suggested by #Ă–merErden, where you can again wrap the date into another type, to which you implement Default on your own. This will ensure that your field will always be initialized, but still forces you to somehow "unwrap" the value. In case of wrapping NaiveDate into a tuple struct, you can unwrap as simply as instance.day.0 or implement Deref to this wrapper and unwrap with *instance.day
use chrono;
use std::ops::Deref;
#[derive(Debug)]
struct NaiveDateWrapper(chrono::NaiveDate);
impl Default for NaiveDateWrapper {
fn default() -> Self {
Self(chrono::NaiveDate::from_ymd(2021, 1, 1))
}
}
impl Deref for NaiveDateWrapper {
type Target = chrono::NaiveDate;
fn deref(&self) -> &Self::Target {
&self.0
}
}
#[derive(Debug, Default)]
struct StructA {
value1: i32,
value2: i32,
value19: i32,
day: NaiveDateWrapper,
}
fn main() {
let v = StructA::default();
println!("{:?}", v.day.0);
println!("{:?}", *v.day);
}
There is another crate called Educe https://docs.rs/educe/latest/educe/#default
Some code snippets.
#[macro_use] extern crate educe;
#[derive(Educe)]
#[educe(Default)]
struct Struct {
#[educe(Default = 1)]
f1: u8,
#[educe(Default = 11111111111111111111111111111)]
f2: i128,
#[educe(Default = 1.1)]
f3: f64,
#[educe(Default = true)]
f4: bool,
#[educe(Default = "Hi")]
f5: &'static str,
#[educe(Default = "Hello")]
f6: String,
#[educe(Default = 'M')]
f7: char,
}
#[derive(Educe)]
#[educe(Default)]
enum Enum {
Unit,
#[educe(Default)]
Tuple(
#[educe(Default(expression = "0 + 1"))]
u8,
#[educe(Default(expression = "-11111111111111111111111111111 * -1"))]
i128,
#[educe(Default(expression = "1.0 + 0.1"))]
f64,
#[educe(Default(expression = "!false"))]
bool,
#[educe(Default(expression = "\"Hi\""))]
&'static str,
#[educe(Default(expression = "String::from(\"Hello\")"))]
String,
#[educe(Default(expression = "'M'"))]
char,
),
}
#[derive(Educe)]
#[educe(Default)]
union Union {
f1: u8,
f2: i128,
f3: f64,
f4: bool,
#[educe(Default = "Hi")]
f5: &'static str,
f6: char,
}
I'm reading a series of bytes from a socket and I need to put each segment of n bytes as a item in a struct.
use std::mem;
#[derive(Debug)]
struct Things {
x: u8,
y: u16,
}
fn main() {
let array = [22 as u8, 76 as u8, 34 as u8];
let foobar: Things;
unsafe {
foobar = mem::transmute::<[u8; 3], Things>(array);
}
println!("{:?}", foobar);
}
I'm getting errors that say that foobar is 32 bits when array is 24 bits. Shouldn't foobar be 24 bits (8 + 16 = 24)?
The issue here is that the y field is 16-bit-aligned. So your memory layout is actually
x
padding
y
y
Note that swapping the order of x and y doesn't help, because Rust's memory layout for structs is actually undefined (and thus still 32 bits for no reason but simplicity in the compiler). If you depend on it you will get undefined behavior.
The reasons for alignment are explained in Purpose of memory alignment.
You can prevent alignment from happening by adding the attribute repr(packed) to your struct, but you'll lose performance and the ability to take references of fields:
#[repr(packed)]
struct Things {
x: u8,
y: u16,
}
The best way would be to not use transmute at all, but to extract the values manually and hope the optimizer makes it fast:
let foobar = Things {
x: array[0],
y: ((array[1] as u16) << 8) | (array[2] as u16),
};
A crate like byteorder may simplify the process of reading different sizes and endianness from the bytes.
bincode and serde can do this quit simply.
use bincode::{deserialize};
use serde::{Deserialize};
#[derive(Deserialize, Debug)]
struct Things {
x: u8,
y: u16,
}
fn main() {
let array = [22 as u8, 76 as u8, 34 as u8];
let foobar: Things = deserialize(&array).unwrap();
println!("{:?}", foobar);
}
This also works well for serializing a struct into bytes as well.
use bincode::{serialize};
use serde::{Serialize};
#[derive(Serialize, Debug)]
struct Things {
x: u8,
y: u16,
}
fn main() {
let things = Things{
x: 22,
y: 8780,
};
let baz = serialize(&things).unwrap();
println!("{:?}", baz);
}
I was having issues using the byteorder crate when dealing with structs that also had char arrays. I couldn't get past the compiler errors. I ended up casting like this:
#[repr(packed)]
struct Things {
x: u8,
y: u16,
}
fn main() {
let data: [u8; 3] = [0x22, 0x76, 0x34];
unsafe {
let things_p: *const Things = data.as_ptr() as *const Things;
let things: &Things = &*things_p;
println!("{:x} {:x}", things.x, things.y);
}
}
Note that with using packed, you get this warning:
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
If you can, change Things to behave like a C struct:
#[repr(C)]
struct Things2 {
x: u8,
y: u16,
}
Then initialize data like this. Note the extra byte for alignment purposes.
let data: [u8; 4] = [0x22, 0, 0x76, 0x34];
use std::mem;
fn main() {
let bytes = vec!(0u8, 1u8,2u8, 3, 4, 5, 6, 7, 8, 9, 0xffu8, );
let data_ptr: *const u64 = unsafe { mem::transmute(bytes[0..4].as_ptr()) };
let data: u64 = unsafe { *data_ptr };
println!("{:#x}", data);
}
I'm reading a series of bytes from a socket and I need to put each segment of n bytes as a item in a struct.
use std::mem;
#[derive(Debug)]
struct Things {
x: u8,
y: u16,
}
fn main() {
let array = [22 as u8, 76 as u8, 34 as u8];
let foobar: Things;
unsafe {
foobar = mem::transmute::<[u8; 3], Things>(array);
}
println!("{:?}", foobar);
}
I'm getting errors that say that foobar is 32 bits when array is 24 bits. Shouldn't foobar be 24 bits (8 + 16 = 24)?
The issue here is that the y field is 16-bit-aligned. So your memory layout is actually
x
padding
y
y
Note that swapping the order of x and y doesn't help, because Rust's memory layout for structs is actually undefined (and thus still 32 bits for no reason but simplicity in the compiler). If you depend on it you will get undefined behavior.
The reasons for alignment are explained in Purpose of memory alignment.
You can prevent alignment from happening by adding the attribute repr(packed) to your struct, but you'll lose performance and the ability to take references of fields:
#[repr(packed)]
struct Things {
x: u8,
y: u16,
}
The best way would be to not use transmute at all, but to extract the values manually and hope the optimizer makes it fast:
let foobar = Things {
x: array[0],
y: ((array[1] as u16) << 8) | (array[2] as u16),
};
A crate like byteorder may simplify the process of reading different sizes and endianness from the bytes.
bincode and serde can do this quit simply.
use bincode::{deserialize};
use serde::{Deserialize};
#[derive(Deserialize, Debug)]
struct Things {
x: u8,
y: u16,
}
fn main() {
let array = [22 as u8, 76 as u8, 34 as u8];
let foobar: Things = deserialize(&array).unwrap();
println!("{:?}", foobar);
}
This also works well for serializing a struct into bytes as well.
use bincode::{serialize};
use serde::{Serialize};
#[derive(Serialize, Debug)]
struct Things {
x: u8,
y: u16,
}
fn main() {
let things = Things{
x: 22,
y: 8780,
};
let baz = serialize(&things).unwrap();
println!("{:?}", baz);
}
I was having issues using the byteorder crate when dealing with structs that also had char arrays. I couldn't get past the compiler errors. I ended up casting like this:
#[repr(packed)]
struct Things {
x: u8,
y: u16,
}
fn main() {
let data: [u8; 3] = [0x22, 0x76, 0x34];
unsafe {
let things_p: *const Things = data.as_ptr() as *const Things;
let things: &Things = &*things_p;
println!("{:x} {:x}", things.x, things.y);
}
}
Note that with using packed, you get this warning:
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
If you can, change Things to behave like a C struct:
#[repr(C)]
struct Things2 {
x: u8,
y: u16,
}
Then initialize data like this. Note the extra byte for alignment purposes.
let data: [u8; 4] = [0x22, 0, 0x76, 0x34];
use std::mem;
fn main() {
let bytes = vec!(0u8, 1u8,2u8, 3, 4, 5, 6, 7, 8, 9, 0xffu8, );
let data_ptr: *const u64 = unsafe { mem::transmute(bytes[0..4].as_ptr()) };
let data: u64 = unsafe { *data_ptr };
println!("{:#x}", data);
}
I'm having a really hard time fathoming pointers in Rust. This code won't compile because: wrong number of lifetime parameters: expected 1, found 0 [E0107]. What does that mean?
struct Planet<'a> {
name: &'a str,
radius_km: i32,
surface_area_km2: i64,
orbital_period_days: i32,
distance_from_sun: i64
}
fn mercury() -> Planet {
Planet {
name: "Mercury",
radius_km: 2_440,
surface_area_km2: 74_800_000,
orbital_period_days: 88,
distance_from_sun: 57_910_000
}
}
fn main() {
let mercury = Box::new(mercury());
println!("{}",mercury.name)
}
It's saying that your definition for the struct includes a type parameter and, therefore, so must your function that creates one.
struct Planet<'a>{
name : &'a str,
radius_km: i32,
surface_area_km2: i64,
orbital_period_days: i32,
distance_from_sun: i64
}
fn mercury<'a>()->Planet<'a>{
Planet{
name:"Mercudy",
radius_km: 2_440,
surface_area_km2: 74_800_000,
orbital_period_days: 88,
distance_from_sun: 57_910_000
}
}
fn main(){
let planet = mercury();
println!("{}", planet.name)
}