-
Notifications
You must be signed in to change notification settings - Fork 12.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Miscompilation with mir-opt-level=2 #77002
Comments
|
Hmm, on first glance the replacement it performs looks correct: It replaces local Maybe this part of the diff causes a problem? - StorageLive(_6); // scope 0 at mis.rs:10:13: 10:20
- _6 = <[[i64; 4]; 4] as Default>::default() -> bb1; // scope 0 at mis.rs:10:28: 10:42
+ nop; // scope 0 at mis.rs:10:13: 10:20
+ _0 = <[[i64; 4]; 4] as Default>::default() -> bb1; // scope 0 at mis.rs:10:28: 10:42 We're using our return place as the return destination for the inner call. It's possible that there's an undocumented (and maybe unintended) assumption that the return place is not reused like this, either in other MIR optimizations or in codegen. Haven't looked too deeply yet though. |
Ah, there's this bad call in LLVM IR: call fastcc void @_ZN3mis4main11matrix_prod17h8c1d34c6f8edb3ecE(
[4 x [4 x i64]]* noalias nocapture nonnull sret dereferenceable(128) %g2,
[4 x [4 x i64]]* noalias nonnull readonly align 8 dereferenceable(128) %0,
[4 x [4 x i64]]* noalias nonnull readonly align 8 dereferenceable(128) %g2
) It passes a reference to |
...and we have this corresponding MIR, where we already incorrectly pass a reference to _20 = &_0; // scope 1 at mis.rs:26:39: 26:43
nop; // scope 1 at mis.rs:26:39: 26:43
StorageLive(_22); // scope 1 at mis.rs:26:45: 26:46
_22 = _2; // scope 1 at mis.rs:26:45: 26:46
StorageLive(_23); // scope 1 at mis.rs:26:48: 26:49
_23 = _2; // scope 1 at mis.rs:26:48: 26:49
StorageLive(_24); // scope 1 at mis.rs:26:51: 26:52
_24 = _2; // scope 1 at mis.rs:26:51: 26:52
_0 = matrix_prod(move _18, move _20, move _22, move _23, move _24) -> bb6; // scope 1 at mis.rs:26:23: 26:53
// mir::Constant
// + span: mis.rs:26:23: 26:34
// + literal: Const { ty: for<'r, 's> fn(&'r [[i64; _]; _], &'s [[i64; _]; _], usize, usize, usize) -> [[i64; _]; _] {main::matrix_prod}, val: Value(Scalar(<ZST>)) } The destination propagation pass already has code that prevents merging a call destination with one of the arguments, but here we pass a reference instead. Curiously, the |
The propagation is disabled only if both locals have their address taken. Changing that to be more conservative does fix this issue. Minimized: type M = [i64; 2];
fn f(a: &M) -> M {
let mut b: M = M::default();
b[0] = a[0] * a[0];
b
}
fn main() {
let mut a: M = [1, 1];
a = f(&a);
std::process::exit((a[0] != 1) as i32);
} |
Oof, this should have been an rust/compiler/rustc_mir/src/transform/dest_prop.rs Lines 907 to 908 in c113030
|
Thanks @tmiasko! |
Opened #77066 with a fix |
…=oli-obk Fix dest prop miscompilation around references Closes rust-lang#77002
…=oli-obk Fix dest prop miscompilation around references Closes rust-lang#77002
This little matrix processing code shows miscompilation if compiled with:
But it compiles correctly with:
With:
The text was updated successfully, but these errors were encountered: