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 -O3bandera, 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 *ay minúsculas int *b.
Cuando explícitamente le decimos al compilador que estos dos punteros no pueden alias con la restrictpalabra 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.0con -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 ay bno 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 ay bpodría alias, incluso en Rust seguro?

unsafecódigo, no se permiten alias de referencias mutables y dan como resultado un comportamiento indefinido. Puede tener alias de punteros sin formato, pero elunsafecó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 deaddspueden reinterpretarse como*a = *a + *b + *b. Si los punteros no lo hacen alias, que pueden, incluso se puede ver lo que equivale ab* + *ben la segunda lista asm:2: 01 c0 add %eax,%eax. Pero si hacen un alias, no pueden, porque para cuando agregue*bpor segunda vez, contendrá un valor diferente al de la primera vez (el que almacena en línea4:de la primera lista de asm).Respuestas:
Rust originalmente hizo permitirá LLVM de
noaliasatributo, pero este código miscompiled causado . Cuando todas las versiones de LLVM compatibles ya no compilan mal el código, se volverá a habilitar .Si agrega
-Zmutable-noalias=yesa las opciones del compilador, obtiene el ensamblado esperado:En pocas palabras, Rust puso el equivalente de la
restrictpalabra clave de C en todas partes , mucho más frecuente que cualquier programa habitual de C. Esto ejerció casos de esquina de LLVM más de lo que pudo manejar correctamente. Resulta que los programadores C y C ++ simplemente no usan conrestricttanta frecuencia como&mutse usa en Rust.Esto ha sucedido varias veces .
noaliashabilitadonoaliasdeshabilitadonoaliashabilitadonoaliasdeshabilitadoProblemas relacionados con el óxido
Caso actual
Caso anterior
Otro
fuente
restricty compilan mal tanto en Clang como en GCC. No se limita a lenguajes que no son "lo suficientemente C ++", a menos que cuente C ++ en ese grupo .noaliasen cuenta completamente los punteros al ejecutar. Creó nuevos punteros basados en punteros de entrada, copiando incorrectamente elnoaliasatributo a pesar de que los nuevos punteros tenían un alias.