As far as I know, reference/pointer aliasing can hinder the compiler’s ability to generate optimized code, since they must ensure the generated binary behaves correctly in the case where the two references/pointers indeed alias. For instance, in the following C code,
void adds(int *a, int *b) {
*a += *b;
*a += *b;
}
when compiled by clang version 6.0.0-1ubuntu2 (tags/RELEASE_600/final)
with the -O3
flag, it emits
0000000000000000 <adds>:
0: 8b 07 mov (%rdi),%eax # load a into EAX
2: 03 06 add (%rsi),%eax # load-and-add b
4: 89 07 mov %eax,(%rdi) # store into a
6: 03 06 add (%rsi),%eax # load-and-add b again
8: 89 07 mov %eax,(%rdi) # store into a again
a: c3 retq
Here the code stores back to (%rdi)
twice in case int *a
and int *b
alias.
When we explicitly tell the compiler that these two pointers cannot alias with the restrict
keyword:
void adds(int * restrict a, int * restrict b) {
*a += *b;
*a += *b;
}
Then Clang will emit a more optimized version that effectively does *a += 2 * (*b)
, which is equivalent if (as promised by restrict
) *b
isn’t modified by assigning to *a
:
0000000000000000 <adds>:
0: 8b 06 mov (%rsi),%eax # load b once
2: 01 c0 add %eax,%eax # double it
4: 01 07 add %eax,(%rdi) # *a += 2 * (*b)
6: c3 retq
Since Rust makes sure (except in unsafe code) that two mutable references cannot alias, I would think that the compiler should be able to emit the more optimized version of the code.
When I test with the code below and compile it with rustc 1.35.0
with -C opt-level=3 --emit obj
,
#![crate_type = "staticlib"]
#[no_mangle]
fn adds(a: &mut i32, b: &mut i32) {
*a += *b;
*a += *b;
}
it generates:
0000000000000000 <adds>:
0: 8b 07 mov (%rdi),%eax
2: 03 06 add (%rsi),%eax
4: 89 07 mov %eax,(%rdi)
6: 03 06 add (%rsi),%eax
8: 89 07 mov %eax,(%rdi)
a: c3 retq
This does not take advantage of the guarantee that a
and b
cannot alias.
Is this because the current Rust compiler is still in development and has not yet incorporated alias analysis to do the optimization?
Is this because there is still a chance that a
and b
could alias, even in safe Rust?