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] ret
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 ret
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.
Labels: rust
Hi Amit,
I'm glad to see you are learning Rust! I have become a Rust aficionado over the last few years. I have twice taught Operating Systems in Rust, and I just had my first paper accepted where I implemented the underlying algorithm in Rust. I am trying to find as many ways as possible to use it.
With compiler-guaranteed immunity to race conditions and unwanted mutations, so far for me there has been no going back.
Here's a blog post I wrote about the OS class: OS in Rust
I'm curious which C++ compiler you used. I've seen a couple of comparisons recently between the ASM generated by Rust vs C++ and they have neglected to mention that Rust is an LLVM language, and so it's LLVM which is generating the machine code from the IR generated by Rust. So it'd be most interesting to compare Rust and Clang which both use the same LLVM backend.
@Gabriel: cool! I'll check out the blog post.
@Toby: I had used gcc on godbolt.org but clang produces similar code. I think the extra load is required in C++ because B and A might be pointing to the same array, and then the write to B will affect the read from A.
I have twice taught Operating Systems in Rust, and I just had my first paper accepted where I implemented the underlying algorithm in Rust. I am trying to find as many ways as possible to use it.
Post a Comment