Até onde eu sei, o aliasing de referência / ponteiro pode prejudicar a capacidade do compilador de gerar código otimizado, pois eles devem garantir que o binário gerado se comporte corretamente no caso em que as duas referências / ponteiros realmente sejam alias. Por exemplo, no código C a seguir,
void adds(int *a, int *b) {
*a += *b;
*a += *b;
}
quando compilado clang version 6.0.0-1ubuntu2 (tags/RELEASE_600/final)
com a -O3
bandeira, emite
0000000000000000 <adds>:
0: 8b 07 mov (%rdi),%eax
2: 03 06 add (%rsi),%eax
4: 89 07 mov %eax,(%rdi) # The first time
6: 03 06 add (%rsi),%eax
8: 89 07 mov %eax,(%rdi) # The second time
a: c3 retq
Aqui, o código é armazenado novamente (%rdi)
duas vezes em case int *a
e int *b
alias.
Quando dizemos explicitamente ao compilador que esses dois ponteiros não podem usar o alias da restrict
palavra-chave:
void adds(int * restrict a, int * restrict b) {
*a += *b;
*a += *b;
}
Então o Clang emitirá uma versão mais otimizada do código binário:
0000000000000000 <adds>:
0: 8b 06 mov (%rsi),%eax
2: 01 c0 add %eax,%eax
4: 01 07 add %eax,(%rdi)
6: c3 retq
Como o Rust garante (exceto no código não seguro) que duas referências mutáveis não possam usar o alias, eu pensaria que o compilador deveria poder emitir a versão mais otimizada do código.
Quando eu testo com o código abaixo e o compilo rustc 1.35.0
com -C opt-level=3 --emit obj
,
#![crate_type = "staticlib"]
#[no_mangle]
fn adds(a: &mut i32, b: &mut i32) {
*a += *b;
*a += *b;
}
gera:
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
Isso não tira proveito da garantia que a
e b
não pode ser um alias.
Isso ocorre porque o atual compilador Rust ainda está em desenvolvimento e ainda não incorporou a análise de alias para fazer a otimização?
Isso ocorre porque ainda existe uma chance a
e b
poderia, mesmo em Rust seguro?
unsafe
código, referências mutáveis no alias não são permitidas e resultam em comportamento indefinido. Você pode ter ponteiros brutos com alias, mas o unsafe
código na verdade não permite que você ignore as regras padrão do Rust. É apenas um equívoco comum e, portanto, vale a pena apontar.
+=
operações no corpo de adds
podem ser reinterpretadas como *a = *a + *b + *b
. Se os ponteiros não aliás, eles podem, você pode até ver o que equivale a b* + *b
no segundo asm lista: 2: 01 c0 add %eax,%eax
. Mas se eles criarem um alias, não poderão, porque na hora em que você adicionar *b
pela segunda vez, ele conterá um valor diferente do que na primeira vez (o que você armazena na linha 4:
da primeira listagem de asm).