Rust memory optimization #

One of my goals this year is to learn new things that take more than a few weeks to learn. I've been learning Rust. One of the claims I saw is that Rust's borrow mechanics allow it to optimize better than C++ does. I wanted to see this in action so I ran some simple examples through godbolt. Here's some C++ code that reads from array A and writes to array B:

int test(const int* A, int* B, int i) {
    int x = A[i];
    B[i] = x+1;
    int y = A[i];
    return x+y;

This C++ code compiles to assembly, with -O2:

movsx   rdx, edx
lea     rcx, [rdi+rdx*4]
mov     eax, DWORD PTR [rcx]
lea     edi, [rax+1]
mov     DWORD PTR [rsi+rdx*4], edi
add     eax, DWORD PTR [rcx]

Note that it is loading DWORD PTR [rcx] twice and loading DWORD PTR [rsi+…] once. That means it's accessing A[i]'s memory twice and B[i] once. It knows that A hasn't changed and it knows i hasn't changed but it doesn't know that A[i] hasn't changed. It's possible that A and B overlap. That means it has to load A[i] twice, even though it's marked const.

Here's the Rust version:

pub fn test(A: &[i32], B: &mut [i32], i: usize) -> i32 {
    let x = A[i];
    B[i] = x+1;
    let y = A[i];
    return x+y;

and the output (some parts omitted):

push    rax
mov     eax, DWORD PTR [rdi + 4*r8]lea     ecx, [rax + 1]
mov     DWORD PTR [rdx + 4*r8], ecx
add     eax, eax
pop     rcx

This code has only two DWORD PTR accesses. It knows that A is a shared reference (so there are no other writers), and B is a mutable reference (so there are no other readers). That means it can conclude that A and B can't overlap. Once it's read A[i] from memory it doesn't have to read it again. Cool!

C (but not C++) has the restrict keyword for this. You can tell the C compiler "trust me, these don't overlap", but C doesn't check. Rust checks this at compile time.

So far I'm enjoying learning Rust. It has many of the things I wanted in a language since the mid-1990s. I don't know if I'll actually use it for a real project, but that's not my goal right now. My goal is to learn some new things that challenge my brain, and Rust is doing that for me.


Cross-compiling Rust to Linux on Mac #

In my last blog post I said I wanted to spend some time learning new things. The first of those is Rust. I had previously tried learning it, but got distracted before I got very far.

Since one of the things I'd use Rust for is web pages, I decided to learn how to compile to WebAssembly, how to interface with Javascript, and how to use WebSockets. At home, I use a Mac to work on my web projects, so for Rust I am compiling a native server and a wasm client. But I also wanted to try running this on, which is a Linux server. How should I compile to Linux? My first thought was to use my Linux machine at home. I can install the Rust compiler there and compile the server on that machine. Alternatively, I could use a virtual machine running Linux. Both of these options seemed slightly annoying.

Labels: ,