Is there a way to disable struct to integer?


#1

Hello,

I am working on a verifier for Rust, based on the generated LLVM code. I
am having an issue with code generated similar to the following

struct Point {
  pub x: u32,
  pub y: u32
}
fn double_point(p: Point) -> Point {
  Point { x: 2*p.x, y: 2*p.y }
}
fn main() {
  let p = Point { x: 2, y: 3 };
  let q = double_point(p);
  assert!(q.x == 4 && q.y == 6);
}

The call to the double_point function is what causes the issue, as shown
in the following generated llvm-ir code

%8 = bitcast %Point* %arg to i64*
%9 = load i64, i64* %8, align 4
%10 = call i64 @_ZN5point12double_point17h4b5ca79567fdc22dE(i64 %9)
store i64 %10, i64* %abi_cast

In the verifier’s default mode, reads from the i64 don’t work correctly,
giving an assertion violation. This code works if the Point structure
uses 64-bit ints instead, since no packing occurs.

My question is: is there is a way to prevent the compiler from
bit-casting the structure to an integer? I am using rustc 1.15.0-nightly (8f02c429a 2016-12-15), and have tried disabling all optimizations.

Thanks


#2

The name %abi_cast there implies to me that this is just how rust’s ABI currently works (there’s no stability guarantee for it), so there’s unlikely to be a way to change it.

Merged loads are fairly common in Rust—even mem::swap will do them, for example—so you probably want to just handle them. You might be able to get some inspiration from how MIRI handles memory, as it also needs to be able to deal with this kind of type-punned-memory access:


#3

Thanks for the pointer. I ultimately made an LLVM pass that recognizes this pattern and converts the packed integer back to the original structure, since other languages do similar packing. I plan to make some extensions with MIR to support some other Rust specific problems.