Hasta donde yo sé, el alias de referencia / puntero puede dificultar la capacidad del compilador para generar código optimizado, ya que deben garantizar que el binario generado se comporte correctamente en el caso en que las dos referencias / punteros realmente alias. Por ejemplo, en el siguiente código C,
void adds(int *a, int *b) {
*a += *b;
*a += *b;
}
cuando se compila clang version 6.0.0-1ubuntu2 (tags/RELEASE_600/final)
con la -O3
bandera, 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
Aquí el código se almacena (%rdi)
dos veces en mayúsculas int *a
y minúsculas int *b
.
Cuando explícitamente le decimos al compilador que estos dos punteros no pueden alias con la restrict
palabra clave:
void adds(int * restrict a, int * restrict b) {
*a += *b;
*a += *b;
}
Entonces Clang emitirá una versión más optimizada del código binario:
0000000000000000 <adds>:
0: 8b 06 mov (%rsi),%eax
2: 01 c0 add %eax,%eax
4: 01 07 add %eax,(%rdi)
6: c3 retq
Dado que Rust se asegura (excepto en un código inseguro) de que dos referencias mutables no pueden tener alias, creo que el compilador debería poder emitir la versión más optimizada del código.
Cuando pruebo con el siguiente código y lo compilo rustc 1.35.0
con -C opt-level=3 --emit obj
,
#![crate_type = "staticlib"]
#[no_mangle]
fn adds(a: &mut i32, b: &mut i32) {
*a += *b;
*a += *b;
}
genera:
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
Esto no aprovecha la garantía a
y b
no puede alias.
¿Es esto porque el compilador Rust actual todavía está en desarrollo y aún no ha incorporado el análisis de alias para hacer la optimización?
¿Es esto porque todavía hay una posibilidad de que a
y b
podría alias, incluso en Rust seguro?
unsafe
código, no se permiten alias de referencias mutables y dan como resultado un comportamiento indefinido. Puede tener alias de punteros sin formato, pero el unsafe
código no le permite ignorar las reglas estándar de Rust. Es solo un error común y, por lo tanto, vale la pena señalarlo.
+=
operaciones en el cuerpo de adds
pueden reinterpretarse como *a = *a + *b + *b
. Si los punteros no lo hacen alias, que pueden, incluso se puede ver lo que equivale a b* + *b
en la segunda lista asm: 2: 01 c0 add %eax,%eax
. Pero si hacen un alias, no pueden, porque para cuando agregue *b
por segunda vez, contendrá un valor diferente al de la primera vez (el que almacena en línea 4:
de la primera lista de asm).