From 2c09f9ff82659e2caf928053c91b4f0761c16e24 Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Fri, 14 Jun 2024 17:47:23 +0000 Subject: [PATCH 01/32] add regression tests for gvn of local arrays --- .../mir-opt/const_array_locals.main.GVN.diff | 97 +++++++++++++++++++ tests/mir-opt/const_array_locals.rs | 44 +++++++++ 2 files changed, 141 insertions(+) create mode 100644 tests/mir-opt/const_array_locals.main.GVN.diff create mode 100644 tests/mir-opt/const_array_locals.rs diff --git a/tests/mir-opt/const_array_locals.main.GVN.diff b/tests/mir-opt/const_array_locals.main.GVN.diff new file mode 100644 index 0000000000000..2fd0a09dcc62c --- /dev/null +++ b/tests/mir-opt/const_array_locals.main.GVN.diff @@ -0,0 +1,97 @@ +- // MIR for `main` before GVN ++ // MIR for `main` after GVN + + fn main() -> () { + let mut _0: (); + let _1: [i32; 32]; + let mut _4: [i32; 12]; + let mut _5: [i32; 12]; + let mut _7: &[i32; 32]; + let _8: [i32; 32]; + let _9: (); + let mut _10: [u16; 32]; + let mut _12: [f32; 8]; + let _13: [[i32; 3]; 3]; + let mut _14: [i32; 3]; + let mut _15: [i32; 3]; + let mut _16: [i32; 3]; + scope 1 { + debug _arr => _1; + let _2: [i32; 32]; + scope 2 { + debug _barr => _2; + let _3: [[i32; 12]; 2]; + scope 3 { + debug _foo => _3; + let _6: [i32; 32]; + let mut _17: &[i32; 32]; + scope 4 { + debug _darr => _6; + let _11: F32x8; + scope 5 { + debug _f => _11; + } + } + } + } + } + + bb0: { +- StorageLive(_1); ++ nop; + _1 = [const 255_i32, const 105_i32, const 15_i32, const 39_i32, const 62_i32, const 251_i32, const 191_i32, const 178_i32, const 9_i32, const 4_i32, const 56_i32, const 221_i32, const 193_i32, const 164_i32, const 194_i32, const 197_i32, const 6_i32, const 243_i32, const 218_i32, const 171_i32, const 87_i32, const 247_i32, const 104_i32, const 159_i32, const 22_i32, const 157_i32, const 105_i32, const 31_i32, const 96_i32, const 173_i32, const 50_i32, const 1_i32]; + StorageLive(_2); +- _2 = [const 255_i32, const 105_i32, const 15_i32, const 39_i32, const 62_i32, const 251_i32, const 191_i32, const 178_i32, const 9_i32, const 4_i32, const 56_i32, const 221_i32, const 193_i32, const 164_i32, const 194_i32, const 197_i32, const 6_i32, const 243_i32, const 218_i32, const 171_i32, const 87_i32, const 247_i32, const 104_i32, const 159_i32, const 22_i32, const 157_i32, const 105_i32, const 31_i32, const 96_i32, const 173_i32, const 50_i32, const 1_i32]; ++ _2 = _1; + StorageLive(_3); + StorageLive(_4); + _4 = [const 255_i32, const 105_i32, const 15_i32, const 39_i32, const 62_i32, const 251_i32, const 191_i32, const 178_i32, const 9_i32, const 4_i32, const 56_i32, const 221_i32]; + StorageLive(_5); + _5 = [const 193_i32, const 164_i32, const 194_i32, const 197_i32, const 6_i32, const 243_i32, const 218_i32, const 171_i32, const 87_i32, const 247_i32, const 104_i32, const 42_i32]; + _3 = [move _4, move _5]; + StorageDead(_5); + StorageDead(_4); + StorageLive(_6); + StorageLive(_7); + _17 = const main::promoted[0]; + _7 = &(*_17); +- _6 = (*_7); ++ _6 = (*_17); + StorageDead(_7); + StorageLive(_9); + StorageLive(_10); + _10 = [const 255_u16, const 105_u16, const 15_u16, const 39_u16, const 62_u16, const 251_u16, const 191_u16, const 178_u16, const 9_u16, const 4_u16, const 56_u16, const 221_u16, const 193_u16, const 164_u16, const 194_u16, const 197_u16, const 6_u16, const 243_u16, const 218_u16, const 171_u16, const 87_u16, const 247_u16, const 104_u16, const 159_u16, const 22_u16, const 157_u16, const 105_u16, const 31_u16, const 96_u16, const 173_u16, const 50_u16, const 1_u16]; + _9 = consume(move _10) -> [return: bb1, unwind continue]; + } + + bb1: { + StorageDead(_10); + StorageDead(_9); + StorageLive(_11); + StorageLive(_12); + _12 = [const 1f32, const 2f32, const 3f32, const 1f32, const 1f32, const 1f32, const 1f32, const 42f32]; + _11 = F32x8(move _12); + StorageDead(_12); + StorageLive(_13); + StorageLive(_14); + _14 = [const 1_i32, const 0_i32, const 0_i32]; + StorageLive(_15); + _15 = [const 0_i32, const 1_i32, const 0_i32]; + StorageLive(_16); + _16 = [const 0_i32, const 0_i32, const 1_i32]; + _13 = [move _14, move _15, move _16]; + StorageDead(_16); + StorageDead(_15); + StorageDead(_14); + StorageDead(_13); + _0 = const (); + StorageDead(_11); + StorageDead(_6); + StorageDead(_3); + StorageDead(_2); +- StorageDead(_1); ++ nop; + return; + } + } + diff --git a/tests/mir-opt/const_array_locals.rs b/tests/mir-opt/const_array_locals.rs new file mode 100644 index 0000000000000..88cceeff9ac56 --- /dev/null +++ b/tests/mir-opt/const_array_locals.rs @@ -0,0 +1,44 @@ +//@ test-mir-pass: GVN +#![feature(repr_simd)] + +#[repr(simd)] +struct F32x8([f32; 8]); + +// EMIT_MIR const_array_locals.main.GVN.diff +// CHECK-LABEL: fn main( +#[rustfmt::skip] +pub fn main() { + let _arr = [ + 255, 105, 15, 39, 62, 251, 191, 178, 9, 4, 56, 221, + 193, 164, 194, 197, 6, 243, 218, 171, 87, 247, 104, + 159, 22, 157, 105, 31, 96, 173, 50, 1, + ]; + // duplicate item + let _barr = [ + 255, 105, 15, 39, 62, 251, 191, 178, 9, 4, 56, 221, + 193, 164, 194, 197, 6, 243, 218, 171, 87, 247, 104, + 159, 22, 157, 105, 31, 96, 173, 50, 1, + ]; + let _foo = [ + [255, 105, 15, 39, 62, 251, 191, 178, 9, 4, 56, 221], + [193, 164, 194, 197, 6, 243, 218, 171, 87, 247, 104, 42], + ]; + let _darr = *&[ + 255, 105, 15, 39, 62, 251, 191, 178, 9, 4, 56, 221, + 193, 164, 194, 197, 6, 243, 218, 171, 87, 247, 104, + 159, 22, 157, 105, 31, 96, 173, 50, 1, + ]; + + consume([255, 105, 15, 39, 62, 251, 191, 178, 9, 4, 56, 221, + 193, 164, 194, 197, 6, 243, 218, 171, 87, 247, 104, + 159, 22, 157, 105, 31, 96, 173, 50, 1,]); + + let _f = F32x8([1.0, 2.0, 3.0, 1.0, 1.0, 1.0, 1.0, 42.0]); + + // ice + [[1, 0, 0], [0, 1, 0], [0, 0, 1]]; // 2D array +} + +fn consume(_arr: [u16; 32]) { + unimplemented!() +} From db63d180c01823c3979a034d681e5eb677ac4c22 Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Fri, 14 Jun 2024 17:47:57 +0000 Subject: [PATCH 02/32] add codegen test for issue 73825 --- .../issue-73825-gvn-const-local-array.rs | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 tests/codegen/issue-73825-gvn-const-local-array.rs diff --git a/tests/codegen/issue-73825-gvn-const-local-array.rs b/tests/codegen/issue-73825-gvn-const-local-array.rs new file mode 100644 index 0000000000000..cd70eb330f112 --- /dev/null +++ b/tests/codegen/issue-73825-gvn-const-local-array.rs @@ -0,0 +1,25 @@ +// issue: +//@ compile-flags: -C opt-level=1 +#![crate_type = "lib"] + +// CHECK-LABEL: @foo +// CHECK-NEXT: start: +// CHECK-NEXT: %_3 = and i64 %x, 63 +// CHECK-NEXT: %0 = getelementptr inbounds [64 x i32], ptr @0, i64 0, i64 %_3 +// CHECK-NEXT: %_0 = load i32, ptr %0, align 4, !noundef !3 +// CHECK-NEXT: ret i32 %_0 +#[no_mangle] +#[rustfmt::skip] +pub fn foo(x: usize) -> i32 { + let base: [i32; 64] = [ + 67, 754, 860, 559, 368, 870, 548, 972, + 141, 731, 351, 664, 32, 4, 996, 741, + 203, 292, 237, 480, 151, 940, 777, 540, + 143, 587, 747, 65, 152, 517, 882, 880, + 712, 595, 370, 901, 237, 53, 789, 785, + 912, 650, 896, 367, 316, 392, 62, 473, + 675, 691, 281, 192, 445, 970, 225, 425, + 628, 324, 322, 206, 912, 867, 462, 92 + ]; + base[x % 64] +} From caaa729a55f0856a858ebc460d51f6b2bbfc82c1 Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Wed, 12 Jun 2024 07:03:41 +0000 Subject: [PATCH 03/32] gvn: promote propagatable local arrays --- compiler/rustc_mir_transform/src/gvn.rs | 24 ++++- .../mir-opt/const_array_locals.main.GVN.diff | 91 +++++++++++++++---- ...ray_index.main.GVN.64bit.panic-unwind.diff | 7 +- ..._variable.main.GVN.64bit.panic-unwind.diff | 5 +- 4 files changed, 104 insertions(+), 23 deletions(-) diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index 1002746e553d7..c1cf4993e83f1 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -406,6 +406,24 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { }; let ptr_imm = Immediate::new_pointer_with_meta(data, meta, &self.ecx); ImmTy::from_immediate(ptr_imm, ty).into() + } else if matches!(kind, AggregateTy::Array) { + let mut mplace = None; + let alloc_id = self.ecx.intern_with_temp_alloc(ty, |ecx, dest| { + for (field_index, op) in fields.iter().copied().enumerate() { + let field_dest = ecx.project_field(dest, field_index)?; + ecx.copy_op(op, &field_dest)?; + } + + let dest = dest.assert_mem_place().map_provenance(|prov| prov.as_immutable()); + mplace.replace(dest); + Ok(()) + }).ok()?; + let GlobalAlloc::Memory(_alloc) = self.tcx.global_alloc(alloc_id) else { + bug!() + }; + let mplace = mplace.unwrap(); + debug!(?mplace); + return Some(mplace.into()); } else if matches!(ty.abi, Abi::Scalar(..) | Abi::ScalarPair(..)) { let dest = self.ecx.allocate(ty, MemoryKind::Stack).ok()?; let variant_dest = if let Some(variant) = variant { @@ -1347,6 +1365,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { } } +#[instrument(level = "trace", skip(ecx), ret)] fn op_to_prop_const<'tcx>( ecx: &mut InterpCx<'tcx, DummyMachine>, op: &OpTy<'tcx>, @@ -1444,10 +1463,6 @@ impl<'tcx> VnState<'_, 'tcx> { } let op = self.evaluated[index].as_ref()?; - if op.layout.is_unsized() { - // Do not attempt to propagate unsized locals. - return None; - } let value = op_to_prop_const(&mut self.ecx, op)?; @@ -1497,6 +1512,7 @@ impl<'tcx> MutVisitor<'tcx> for VnState<'_, 'tcx> { .as_local() .and_then(|local| self.locals[local]) .or_else(|| self.simplify_rvalue(rvalue, location)); + debug!(?value); let Some(value) = value else { return }; if let Some(const_) = self.try_as_constant(value) { diff --git a/tests/mir-opt/const_array_locals.main.GVN.diff b/tests/mir-opt/const_array_locals.main.GVN.diff index 2fd0a09dcc62c..49063410236a8 100644 --- a/tests/mir-opt/const_array_locals.main.GVN.diff +++ b/tests/mir-opt/const_array_locals.main.GVN.diff @@ -37,18 +37,21 @@ } bb0: { -- StorageLive(_1); -+ nop; - _1 = [const 255_i32, const 105_i32, const 15_i32, const 39_i32, const 62_i32, const 251_i32, const 191_i32, const 178_i32, const 9_i32, const 4_i32, const 56_i32, const 221_i32, const 193_i32, const 164_i32, const 194_i32, const 197_i32, const 6_i32, const 243_i32, const 218_i32, const 171_i32, const 87_i32, const 247_i32, const 104_i32, const 159_i32, const 22_i32, const 157_i32, const 105_i32, const 31_i32, const 96_i32, const 173_i32, const 50_i32, const 1_i32]; + StorageLive(_1); +- _1 = [const 255_i32, const 105_i32, const 15_i32, const 39_i32, const 62_i32, const 251_i32, const 191_i32, const 178_i32, const 9_i32, const 4_i32, const 56_i32, const 221_i32, const 193_i32, const 164_i32, const 194_i32, const 197_i32, const 6_i32, const 243_i32, const 218_i32, const 171_i32, const 87_i32, const 247_i32, const 104_i32, const 159_i32, const 22_i32, const 157_i32, const 105_i32, const 31_i32, const 96_i32, const 173_i32, const 50_i32, const 1_i32]; ++ _1 = const [255_i32, 105_i32, 15_i32, 39_i32, 62_i32, 251_i32, 191_i32, 178_i32, 9_i32, 4_i32, 56_i32, 221_i32, 193_i32, 164_i32, 194_i32, 197_i32, 6_i32, 243_i32, 218_i32, 171_i32, 87_i32, 247_i32, 104_i32, 159_i32, 22_i32, 157_i32, 105_i32, 31_i32, 96_i32, 173_i32, 50_i32, 1_i32]; StorageLive(_2); - _2 = [const 255_i32, const 105_i32, const 15_i32, const 39_i32, const 62_i32, const 251_i32, const 191_i32, const 178_i32, const 9_i32, const 4_i32, const 56_i32, const 221_i32, const 193_i32, const 164_i32, const 194_i32, const 197_i32, const 6_i32, const 243_i32, const 218_i32, const 171_i32, const 87_i32, const 247_i32, const 104_i32, const 159_i32, const 22_i32, const 157_i32, const 105_i32, const 31_i32, const 96_i32, const 173_i32, const 50_i32, const 1_i32]; -+ _2 = _1; ++ _2 = const [255_i32, 105_i32, 15_i32, 39_i32, 62_i32, 251_i32, 191_i32, 178_i32, 9_i32, 4_i32, 56_i32, 221_i32, 193_i32, 164_i32, 194_i32, 197_i32, 6_i32, 243_i32, 218_i32, 171_i32, 87_i32, 247_i32, 104_i32, 159_i32, 22_i32, 157_i32, 105_i32, 31_i32, 96_i32, 173_i32, 50_i32, 1_i32]; StorageLive(_3); StorageLive(_4); - _4 = [const 255_i32, const 105_i32, const 15_i32, const 39_i32, const 62_i32, const 251_i32, const 191_i32, const 178_i32, const 9_i32, const 4_i32, const 56_i32, const 221_i32]; +- _4 = [const 255_i32, const 105_i32, const 15_i32, const 39_i32, const 62_i32, const 251_i32, const 191_i32, const 178_i32, const 9_i32, const 4_i32, const 56_i32, const 221_i32]; ++ _4 = const [255_i32, 105_i32, 15_i32, 39_i32, 62_i32, 251_i32, 191_i32, 178_i32, 9_i32, 4_i32, 56_i32, 221_i32]; StorageLive(_5); - _5 = [const 193_i32, const 164_i32, const 194_i32, const 197_i32, const 6_i32, const 243_i32, const 218_i32, const 171_i32, const 87_i32, const 247_i32, const 104_i32, const 42_i32]; - _3 = [move _4, move _5]; +- _5 = [const 193_i32, const 164_i32, const 194_i32, const 197_i32, const 6_i32, const 243_i32, const 218_i32, const 171_i32, const 87_i32, const 247_i32, const 104_i32, const 42_i32]; +- _3 = [move _4, move _5]; ++ _5 = const [193_i32, 164_i32, 194_i32, 197_i32, 6_i32, 243_i32, 218_i32, 171_i32, 87_i32, 247_i32, 104_i32, 42_i32]; ++ _3 = [const [255_i32, 105_i32, 15_i32, 39_i32, 62_i32, 251_i32, 191_i32, 178_i32, 9_i32, 4_i32, 56_i32, 221_i32], const [193_i32, 164_i32, 194_i32, 197_i32, 6_i32, 243_i32, 218_i32, 171_i32, 87_i32, 247_i32, 104_i32, 42_i32]]; StorageDead(_5); StorageDead(_4); StorageLive(_6); @@ -60,8 +63,10 @@ StorageDead(_7); StorageLive(_9); StorageLive(_10); - _10 = [const 255_u16, const 105_u16, const 15_u16, const 39_u16, const 62_u16, const 251_u16, const 191_u16, const 178_u16, const 9_u16, const 4_u16, const 56_u16, const 221_u16, const 193_u16, const 164_u16, const 194_u16, const 197_u16, const 6_u16, const 243_u16, const 218_u16, const 171_u16, const 87_u16, const 247_u16, const 104_u16, const 159_u16, const 22_u16, const 157_u16, const 105_u16, const 31_u16, const 96_u16, const 173_u16, const 50_u16, const 1_u16]; - _9 = consume(move _10) -> [return: bb1, unwind continue]; +- _10 = [const 255_u16, const 105_u16, const 15_u16, const 39_u16, const 62_u16, const 251_u16, const 191_u16, const 178_u16, const 9_u16, const 4_u16, const 56_u16, const 221_u16, const 193_u16, const 164_u16, const 194_u16, const 197_u16, const 6_u16, const 243_u16, const 218_u16, const 171_u16, const 87_u16, const 247_u16, const 104_u16, const 159_u16, const 22_u16, const 157_u16, const 105_u16, const 31_u16, const 96_u16, const 173_u16, const 50_u16, const 1_u16]; +- _9 = consume(move _10) -> [return: bb1, unwind continue]; ++ _10 = const [255_u16, 105_u16, 15_u16, 39_u16, 62_u16, 251_u16, 191_u16, 178_u16, 9_u16, 4_u16, 56_u16, 221_u16, 193_u16, 164_u16, 194_u16, 197_u16, 6_u16, 243_u16, 218_u16, 171_u16, 87_u16, 247_u16, 104_u16, 159_u16, 22_u16, 157_u16, 105_u16, 31_u16, 96_u16, 173_u16, 50_u16, 1_u16]; ++ _9 = consume(const [255_u16, 105_u16, 15_u16, 39_u16, 62_u16, 251_u16, 191_u16, 178_u16, 9_u16, 4_u16, 56_u16, 221_u16, 193_u16, 164_u16, 194_u16, 197_u16, 6_u16, 243_u16, 218_u16, 171_u16, 87_u16, 247_u16, 104_u16, 159_u16, 22_u16, 157_u16, 105_u16, 31_u16, 96_u16, 173_u16, 50_u16, 1_u16]) -> [return: bb1, unwind continue]; } bb1: { @@ -69,17 +74,23 @@ StorageDead(_9); StorageLive(_11); StorageLive(_12); - _12 = [const 1f32, const 2f32, const 3f32, const 1f32, const 1f32, const 1f32, const 1f32, const 42f32]; - _11 = F32x8(move _12); +- _12 = [const 1f32, const 2f32, const 3f32, const 1f32, const 1f32, const 1f32, const 1f32, const 42f32]; +- _11 = F32x8(move _12); ++ _12 = const [1f32, 2f32, 3f32, 1f32, 1f32, 1f32, 1f32, 42f32]; ++ _11 = F32x8(const [1f32, 2f32, 3f32, 1f32, 1f32, 1f32, 1f32, 42f32]); StorageDead(_12); StorageLive(_13); StorageLive(_14); - _14 = [const 1_i32, const 0_i32, const 0_i32]; +- _14 = [const 1_i32, const 0_i32, const 0_i32]; ++ _14 = const [1_i32, 0_i32, 0_i32]; StorageLive(_15); - _15 = [const 0_i32, const 1_i32, const 0_i32]; +- _15 = [const 0_i32, const 1_i32, const 0_i32]; ++ _15 = const [0_i32, 1_i32, 0_i32]; StorageLive(_16); - _16 = [const 0_i32, const 0_i32, const 1_i32]; - _13 = [move _14, move _15, move _16]; +- _16 = [const 0_i32, const 0_i32, const 1_i32]; +- _13 = [move _14, move _15, move _16]; ++ _16 = const [0_i32, 0_i32, 1_i32]; ++ _13 = [const [1_i32, 0_i32, 0_i32], const [0_i32, 1_i32, 0_i32], const [0_i32, 0_i32, 1_i32]]; StorageDead(_16); StorageDead(_15); StorageDead(_14); @@ -89,9 +100,55 @@ StorageDead(_6); StorageDead(_3); StorageDead(_2); -- StorageDead(_1); -+ nop; + StorageDead(_1); return; } ++ } ++ ++ ALLOC0 (size: 12, align: 4) { ++ 00 00 00 00 00 00 00 00 01 00 00 00 │ ............ ++ } ++ ++ ALLOC1 (size: 12, align: 4) { ++ 00 00 00 00 01 00 00 00 00 00 00 00 │ ............ ++ } ++ ++ ALLOC2 (size: 12, align: 4) { ++ 01 00 00 00 00 00 00 00 00 00 00 00 │ ............ ++ } ++ ++ ALLOC3 (size: 32, align: 4) { ++ 0x00 │ 00 00 80 3f 00 00 00 40 00 00 40 40 00 00 80 3f │ ...?...@..@@...? ++ 0x10 │ 00 00 80 3f 00 00 80 3f 00 00 80 3f 00 00 28 42 │ ...?...?...?..(B ++ } ++ ++ ALLOC4 (size: 64, align: 2) { ++ 0x00 │ ff 00 69 00 0f 00 27 00 3e 00 fb 00 bf 00 b2 00 │ ..i...'.>....... ++ 0x10 │ 09 00 04 00 38 00 dd 00 c1 00 a4 00 c2 00 c5 00 │ ....8........... ++ 0x20 │ 06 00 f3 00 da 00 ab 00 57 00 f7 00 68 00 9f 00 │ ........W...h... ++ 0x30 │ 16 00 9d 00 69 00 1f 00 60 00 ad 00 32 00 01 00 │ ....i...`...2... ++ } ++ ++ ALLOC5 (size: 48, align: 4) { ++ 0x00 │ c1 00 00 00 a4 00 00 00 c2 00 00 00 c5 00 00 00 │ ................ ++ 0x10 │ 06 00 00 00 f3 00 00 00 da 00 00 00 ab 00 00 00 │ ................ ++ 0x20 │ 57 00 00 00 f7 00 00 00 68 00 00 00 2a 00 00 00 │ W.......h...*... ++ } ++ ++ ALLOC6 (size: 48, align: 4) { ++ 0x00 │ ff 00 00 00 69 00 00 00 0f 00 00 00 27 00 00 00 │ ....i.......'... ++ 0x10 │ 3e 00 00 00 fb 00 00 00 bf 00 00 00 b2 00 00 00 │ >............... ++ 0x20 │ 09 00 00 00 04 00 00 00 38 00 00 00 dd 00 00 00 │ ........8....... ++ } ++ ++ ALLOC7 (size: 128, align: 4) { ++ 0x00 │ ff 00 00 00 69 00 00 00 0f 00 00 00 27 00 00 00 │ ....i.......'... ++ 0x10 │ 3e 00 00 00 fb 00 00 00 bf 00 00 00 b2 00 00 00 │ >............... ++ 0x20 │ 09 00 00 00 04 00 00 00 38 00 00 00 dd 00 00 00 │ ........8....... ++ 0x30 │ c1 00 00 00 a4 00 00 00 c2 00 00 00 c5 00 00 00 │ ................ ++ 0x40 │ 06 00 00 00 f3 00 00 00 da 00 00 00 ab 00 00 00 │ ................ ++ 0x50 │ 57 00 00 00 f7 00 00 00 68 00 00 00 9f 00 00 00 │ W.......h....... ++ 0x60 │ 16 00 00 00 9d 00 00 00 69 00 00 00 1f 00 00 00 │ ........i....... ++ 0x70 │ 60 00 00 00 ad 00 00 00 32 00 00 00 01 00 00 00 │ `.......2....... } diff --git a/tests/mir-opt/const_prop/array_index.main.GVN.64bit.panic-unwind.diff b/tests/mir-opt/const_prop/array_index.main.GVN.64bit.panic-unwind.diff index 7e2f72ab31bce..38e7b2b688dd4 100644 --- a/tests/mir-opt/const_prop/array_index.main.GVN.64bit.panic-unwind.diff +++ b/tests/mir-opt/const_prop/array_index.main.GVN.64bit.panic-unwind.diff @@ -15,7 +15,8 @@ bb0: { StorageLive(_1); StorageLive(_2); - _2 = [const 0_u32, const 1_u32, const 2_u32, const 3_u32]; +- _2 = [const 0_u32, const 1_u32, const 2_u32, const 3_u32]; ++ _2 = const [0_u32, 1_u32, 2_u32, 3_u32]; StorageLive(_3); _3 = const 2_usize; - _4 = Len(_2); @@ -35,5 +36,9 @@ StorageDead(_1); return; } ++ } ++ ++ ALLOC0 (size: 16, align: 4) { ++ 00 00 00 00 01 00 00 00 02 00 00 00 03 00 00 00 │ ................ } diff --git a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.64bit.panic-unwind.diff b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.64bit.panic-unwind.diff index e6ee1e6f9a348..21461efd0abd9 100644 --- a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.64bit.panic-unwind.diff +++ b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.64bit.panic-unwind.diff @@ -35,7 +35,8 @@ + _1 = const 4_i32; StorageLive(_3); StorageLive(_4); - _4 = [const 0_i32, const 1_i32, const 2_i32, const 3_i32, const 4_i32, const 5_i32]; +- _4 = [const 0_i32, const 1_i32, const 2_i32, const 3_i32, const 4_i32, const 5_i32]; ++ _4 = const [0_i32, 1_i32, 2_i32, 3_i32, 4_i32, 5_i32]; StorageLive(_5); _5 = const 3_usize; _6 = const 6_usize; @@ -64,4 +65,6 @@ } + + ALLOC0 (size: 8, align: 4) { .. } ++ ++ ALLOC1 (size: 24, align: 4) { .. } From beec32d994dc73a1d0103c3b2d6e8402fa6881c0 Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Thu, 13 Jun 2024 21:06:55 +0000 Subject: [PATCH 04/32] ignore nested arrays --- compiler/rustc_mir_transform/src/gvn.rs | 42 +++++++++++++++++++++---- 1 file changed, 36 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index c1cf4993e83f1..874b2cb3ac1e6 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -410,6 +410,10 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { let mut mplace = None; let alloc_id = self.ecx.intern_with_temp_alloc(ty, |ecx, dest| { for (field_index, op) in fields.iter().copied().enumerate() { + // ignore nested arrays + if let Either::Left(_) = op.as_mplace_or_imm() { + interpret::throw_inval!(TooGeneric); + } let field_dest = ecx.project_field(dest, field_index)?; ecx.copy_op(op, &field_dest)?; } @@ -722,7 +726,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { place.projection = self.tcx.mk_place_elems(&projection); } - trace!(?place); + trace!(after_place = ?place); } /// Represent the *value* which would be read from `place`, and point `place` to a preexisting @@ -1381,7 +1385,7 @@ fn op_to_prop_const<'tcx>( } // Do not synthetize too large constants. Codegen will just memcpy them, which we'd like to avoid. - if !matches!(op.layout.abi, Abi::Scalar(..) | Abi::ScalarPair(..)) { + if !(op.layout.ty.is_array() || matches!(op.layout.abi, Abi::Scalar(..) | Abi::ScalarPair(..))) { return None; } @@ -1452,14 +1456,37 @@ impl<'tcx> VnState<'_, 'tcx> { } /// If `index` is a `Value::Constant`, return the `Constant` to be put in the MIR. + #[instrument(level = "trace", skip(self, index), ret)] fn try_as_constant(&mut self, index: VnIndex) -> Option> { // This was already constant in MIR, do not change it. - if let Value::Constant { value, disambiguator: _ } = *self.get(index) + let value = self.get(index); + debug!(?index, ?value); + match value { // If the constant is not deterministic, adding an additional mention of it in MIR will // not give the same value as the former mention. - && value.is_deterministic() - { - return Some(ConstOperand { span: DUMMY_SP, user_ty: None, const_: value }); + Value::Constant { value, disambiguator: _ } if value.is_deterministic() => { + return Some(ConstOperand { span: DUMMY_SP, user_ty: None, const_: *value }); + } + // ignore nested arrays + Value::Aggregate(AggregateTy::Array, _, fields) => { + for f in fields { + if let Value::Constant { value: Const::Val(const_, _), .. } = self.get(*f) + && let ConstValue::Indirect { .. } = const_ { + return None; + } + } + } + // ignore promoted arrays + Value::Projection(index, ProjectionElem::Deref) => { + if let Value::Constant { value: Const::Val(const_, ty), .. } = self.get(*index) + && let ConstValue::Scalar(Scalar::Ptr(..)) = const_ + && let ty::Ref(region, ty, _mutability) = ty.kind() + && region.is_erased() + && ty.is_array() { + return None; + } + } + _ => {} } let op = self.evaluated[index].as_ref()?; @@ -1499,6 +1526,7 @@ impl<'tcx> MutVisitor<'tcx> for VnState<'_, 'tcx> { self.simplify_operand(operand, location); } + #[instrument(level = "trace", skip(self, stmt))] fn visit_statement(&mut self, stmt: &mut Statement<'tcx>, location: Location) { if let StatementKind::Assign(box (ref mut lhs, ref mut rvalue)) = stmt.kind { self.simplify_place_projection(lhs, location); @@ -1515,6 +1543,7 @@ impl<'tcx> MutVisitor<'tcx> for VnState<'_, 'tcx> { debug!(?value); let Some(value) = value else { return }; + debug!(before_rvalue = ?rvalue); if let Some(const_) = self.try_as_constant(value) { *rvalue = Rvalue::Use(Operand::Constant(Box::new(const_))); } else if let Some(local) = self.try_as_local(value, location) @@ -1523,6 +1552,7 @@ impl<'tcx> MutVisitor<'tcx> for VnState<'_, 'tcx> { *rvalue = Rvalue::Use(Operand::Copy(local.into())); self.reused_locals.insert(local); } + debug!(after_rvalue = ?rvalue); return; } From fa65e0f48a610543004199cd2914b252acabfc35 Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Thu, 13 Jun 2024 21:39:02 +0000 Subject: [PATCH 05/32] fmt --- compiler/rustc_mir_transform/src/gvn.rs | 37 +++++++++++++++---------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index 874b2cb3ac1e6..aa91642e1b93f 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -408,20 +408,24 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { ImmTy::from_immediate(ptr_imm, ty).into() } else if matches!(kind, AggregateTy::Array) { let mut mplace = None; - let alloc_id = self.ecx.intern_with_temp_alloc(ty, |ecx, dest| { - for (field_index, op) in fields.iter().copied().enumerate() { - // ignore nested arrays - if let Either::Left(_) = op.as_mplace_or_imm() { - interpret::throw_inval!(TooGeneric); + let alloc_id = self + .ecx + .intern_with_temp_alloc(ty, |ecx, dest| { + for (field_index, op) in fields.iter().copied().enumerate() { + // ignore nested arrays + if let Either::Left(_) = op.as_mplace_or_imm() { + interpret::throw_inval!(TooGeneric); + } + let field_dest = ecx.project_field(dest, field_index)?; + ecx.copy_op(op, &field_dest)?; } - let field_dest = ecx.project_field(dest, field_index)?; - ecx.copy_op(op, &field_dest)?; - } - let dest = dest.assert_mem_place().map_provenance(|prov| prov.as_immutable()); - mplace.replace(dest); - Ok(()) - }).ok()?; + let dest = + dest.assert_mem_place().map_provenance(|prov| prov.as_immutable()); + mplace.replace(dest); + Ok(()) + }) + .ok()?; let GlobalAlloc::Memory(_alloc) = self.tcx.global_alloc(alloc_id) else { bug!() }; @@ -1385,7 +1389,8 @@ fn op_to_prop_const<'tcx>( } // Do not synthetize too large constants. Codegen will just memcpy them, which we'd like to avoid. - if !(op.layout.ty.is_array() || matches!(op.layout.abi, Abi::Scalar(..) | Abi::ScalarPair(..))) { + if !(op.layout.ty.is_array() || matches!(op.layout.abi, Abi::Scalar(..) | Abi::ScalarPair(..))) + { return None; } @@ -1471,7 +1476,8 @@ impl<'tcx> VnState<'_, 'tcx> { Value::Aggregate(AggregateTy::Array, _, fields) => { for f in fields { if let Value::Constant { value: Const::Val(const_, _), .. } = self.get(*f) - && let ConstValue::Indirect { .. } = const_ { + && let ConstValue::Indirect { .. } = const_ + { return None; } } @@ -1482,7 +1488,8 @@ impl<'tcx> VnState<'_, 'tcx> { && let ConstValue::Scalar(Scalar::Ptr(..)) = const_ && let ty::Ref(region, ty, _mutability) = ty.kind() && region.is_erased() - && ty.is_array() { + && ty.is_array() + { return None; } } From 8e1dedb33a923558d739c7a83beeb7d08c72d3c9 Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Fri, 14 Jun 2024 09:05:34 +0000 Subject: [PATCH 06/32] rewrite ignore nested array condition --- compiler/rustc_mir_transform/src/gvn.rs | 43 ++++++++++--------------- 1 file changed, 17 insertions(+), 26 deletions(-) diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index aa91642e1b93f..e90754e714013 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -1466,38 +1466,29 @@ impl<'tcx> VnState<'_, 'tcx> { // This was already constant in MIR, do not change it. let value = self.get(index); debug!(?index, ?value); - match value { - // If the constant is not deterministic, adding an additional mention of it in MIR will - // not give the same value as the former mention. - Value::Constant { value, disambiguator: _ } if value.is_deterministic() => { - return Some(ConstOperand { span: DUMMY_SP, user_ty: None, const_: *value }); - } + // If the constant is not deterministic, adding an additional mention of it in MIR will + // not give the same value as the former mention. + if let Value::Constant { value, disambiguator: _ } = value + && value.is_deterministic() + { + return Some(ConstOperand { span: DUMMY_SP, user_ty: None, const_: *value }); + } + + let op = self.evaluated[index].as_ref()?; + + if let Either::Left(mplace) = op.as_mplace_or_imm() + && let ty::Array(ty, _const) = mplace.layout.ty.kind() + { // ignore nested arrays - Value::Aggregate(AggregateTy::Array, _, fields) => { - for f in fields { - if let Value::Constant { value: Const::Val(const_, _), .. } = self.get(*f) - && let ConstValue::Indirect { .. } = const_ - { - return None; - } - } + if ty.is_array() { + return None; } // ignore promoted arrays - Value::Projection(index, ProjectionElem::Deref) => { - if let Value::Constant { value: Const::Val(const_, ty), .. } = self.get(*index) - && let ConstValue::Scalar(Scalar::Ptr(..)) = const_ - && let ty::Ref(region, ty, _mutability) = ty.kind() - && region.is_erased() - && ty.is_array() - { - return None; - } + else if let Value::Projection(_index, ProjectionElem::Deref) = value { + return None; } - _ => {} } - let op = self.evaluated[index].as_ref()?; - let value = op_to_prop_const(&mut self.ecx, op)?; // Check that we do not leak a pointer. From 2b4840b8a1d9184dff058518b0f9e86c8a81d835 Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Fri, 14 Jun 2024 12:38:10 +0000 Subject: [PATCH 07/32] move ignoring condition out of loop --- compiler/rustc_mir_transform/src/gvn.rs | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index e90754e714013..a77ea93d9d1a8 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -381,8 +381,19 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { .collect::>>()?; let ty = match kind { AggregateTy::Array => { - assert!(fields.len() > 0); - Ty::new_array(self.tcx, fields[0].layout.ty, fields.len() as u64) + let [field, ..] = fields.as_slice() else { + bug!("fields.len() == 0"); + }; + let field_ty = field.layout.ty; + // Ignore nested array + if field_ty.is_array() { + trace!( + "ignoring nested array of type: [{field_ty}; {len}]", + len = fields.len(), + ); + return None; + } + Ty::new_array(self.tcx, field_ty, fields.len() as u64) } AggregateTy::Tuple => { Ty::new_tup_from_iter(self.tcx, fields.iter().map(|f| f.layout.ty)) @@ -412,10 +423,6 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { .ecx .intern_with_temp_alloc(ty, |ecx, dest| { for (field_index, op) in fields.iter().copied().enumerate() { - // ignore nested arrays - if let Either::Left(_) = op.as_mplace_or_imm() { - interpret::throw_inval!(TooGeneric); - } let field_dest = ecx.project_field(dest, field_index)?; ecx.copy_op(op, &field_dest)?; } From 9a62b994d538533477c506e090fe376397f77f34 Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Fri, 14 Jun 2024 12:49:15 +0000 Subject: [PATCH 08/32] add fixme about potential perf --- compiler/rustc_mir_transform/src/gvn.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index a77ea93d9d1a8..0e81650cd66e5 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -422,6 +422,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { let alloc_id = self .ecx .intern_with_temp_alloc(ty, |ecx, dest| { + // FIXME: Can we speed it up by using `ecx.write_immediate(.ScalarPair(_), dest)`? for (field_index, op) in fields.iter().copied().enumerate() { let field_dest = ecx.project_field(dest, field_index)?; ecx.copy_op(op, &field_dest)?; From 5d10ac038618a520ae165674a737252580c27c10 Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Fri, 14 Jun 2024 17:42:02 +0000 Subject: [PATCH 09/32] avoid blessing differences between {32,64}-bits targets --- compiler/rustc_mir_transform/src/gvn.rs | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index 0e81650cd66e5..8e5ce0f05f6b4 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -366,7 +366,15 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { #[instrument(level = "trace", skip(self), ret)] fn eval_to_const(&mut self, value: VnIndex) -> Option> { use Value::*; - let op = match *self.get(value) { + // LLVM optimizes the load of `sizeof(size_t) * 2` as a single `mov`, + // which is cheap. Bigger values make more `mov` instructions generated. + // After GVN, it became a single load (`lea`) of an address in `.rodata`. + // But to avoid blessing differences between 32-bit and 64-bit target, + // let's choose `size_t = u64`. + const STACK_THRESHOLD: u64 = std::mem::size_of::() as u64 * 2; + let vvalue = self.get(value); + debug!(?vvalue); + let op = match *vvalue { Opaque(_) => return None, // Do not bother evaluating repeat expressions. This would uselessly consume memory. Repeat(..) => return None, @@ -381,10 +389,8 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { .collect::>>()?; let ty = match kind { AggregateTy::Array => { - let [field, ..] = fields.as_slice() else { - bug!("fields.len() == 0"); - }; - let field_ty = field.layout.ty; + assert!(fields.len() > 0); + let field_ty = fields[0].layout.ty; // Ignore nested array if field_ty.is_array() { trace!( @@ -418,6 +424,9 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { let ptr_imm = Immediate::new_pointer_with_meta(data, meta, &self.ecx); ImmTy::from_immediate(ptr_imm, ty).into() } else if matches!(kind, AggregateTy::Array) { + if ty.layout.size().bytes() <= STACK_THRESHOLD { + return None; + } let mut mplace = None; let alloc_id = self .ecx From 6de604b7f41e7823155a3f0d8cbd445b3e9e8ab2 Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Fri, 14 Jun 2024 17:58:43 +0000 Subject: [PATCH 10/32] bless tests --- .../mir-opt/const_array_locals.main.GVN.diff | 34 +++++-------------- ...ray_index.main.GVN.64bit.panic-unwind.diff | 7 +--- 2 files changed, 10 insertions(+), 31 deletions(-) diff --git a/tests/mir-opt/const_array_locals.main.GVN.diff b/tests/mir-opt/const_array_locals.main.GVN.diff index 49063410236a8..2276176b1cbd4 100644 --- a/tests/mir-opt/const_array_locals.main.GVN.diff +++ b/tests/mir-opt/const_array_locals.main.GVN.diff @@ -81,16 +81,12 @@ StorageDead(_12); StorageLive(_13); StorageLive(_14); -- _14 = [const 1_i32, const 0_i32, const 0_i32]; -+ _14 = const [1_i32, 0_i32, 0_i32]; + _14 = [const 1_i32, const 0_i32, const 0_i32]; StorageLive(_15); -- _15 = [const 0_i32, const 1_i32, const 0_i32]; -+ _15 = const [0_i32, 1_i32, 0_i32]; + _15 = [const 0_i32, const 1_i32, const 0_i32]; StorageLive(_16); -- _16 = [const 0_i32, const 0_i32, const 1_i32]; -- _13 = [move _14, move _15, move _16]; -+ _16 = const [0_i32, 0_i32, 1_i32]; -+ _13 = [const [1_i32, 0_i32, 0_i32], const [0_i32, 1_i32, 0_i32], const [0_i32, 0_i32, 1_i32]]; + _16 = [const 0_i32, const 0_i32, const 1_i32]; + _13 = [move _14, move _15, move _16]; StorageDead(_16); StorageDead(_15); StorageDead(_14); @@ -105,43 +101,31 @@ } + } + -+ ALLOC0 (size: 12, align: 4) { -+ 00 00 00 00 00 00 00 00 01 00 00 00 │ ............ -+ } -+ -+ ALLOC1 (size: 12, align: 4) { -+ 00 00 00 00 01 00 00 00 00 00 00 00 │ ............ -+ } -+ -+ ALLOC2 (size: 12, align: 4) { -+ 01 00 00 00 00 00 00 00 00 00 00 00 │ ............ -+ } -+ -+ ALLOC3 (size: 32, align: 4) { ++ ALLOC0 (size: 32, align: 4) { + 0x00 │ 00 00 80 3f 00 00 00 40 00 00 40 40 00 00 80 3f │ ...?...@..@@...? + 0x10 │ 00 00 80 3f 00 00 80 3f 00 00 80 3f 00 00 28 42 │ ...?...?...?..(B + } + -+ ALLOC4 (size: 64, align: 2) { ++ ALLOC1 (size: 64, align: 2) { + 0x00 │ ff 00 69 00 0f 00 27 00 3e 00 fb 00 bf 00 b2 00 │ ..i...'.>....... + 0x10 │ 09 00 04 00 38 00 dd 00 c1 00 a4 00 c2 00 c5 00 │ ....8........... + 0x20 │ 06 00 f3 00 da 00 ab 00 57 00 f7 00 68 00 9f 00 │ ........W...h... + 0x30 │ 16 00 9d 00 69 00 1f 00 60 00 ad 00 32 00 01 00 │ ....i...`...2... + } + -+ ALLOC5 (size: 48, align: 4) { ++ ALLOC2 (size: 48, align: 4) { + 0x00 │ c1 00 00 00 a4 00 00 00 c2 00 00 00 c5 00 00 00 │ ................ + 0x10 │ 06 00 00 00 f3 00 00 00 da 00 00 00 ab 00 00 00 │ ................ + 0x20 │ 57 00 00 00 f7 00 00 00 68 00 00 00 2a 00 00 00 │ W.......h...*... + } + -+ ALLOC6 (size: 48, align: 4) { ++ ALLOC3 (size: 48, align: 4) { + 0x00 │ ff 00 00 00 69 00 00 00 0f 00 00 00 27 00 00 00 │ ....i.......'... + 0x10 │ 3e 00 00 00 fb 00 00 00 bf 00 00 00 b2 00 00 00 │ >............... + 0x20 │ 09 00 00 00 04 00 00 00 38 00 00 00 dd 00 00 00 │ ........8....... + } + -+ ALLOC7 (size: 128, align: 4) { ++ ALLOC4 (size: 128, align: 4) { + 0x00 │ ff 00 00 00 69 00 00 00 0f 00 00 00 27 00 00 00 │ ....i.......'... + 0x10 │ 3e 00 00 00 fb 00 00 00 bf 00 00 00 b2 00 00 00 │ >............... + 0x20 │ 09 00 00 00 04 00 00 00 38 00 00 00 dd 00 00 00 │ ........8....... diff --git a/tests/mir-opt/const_prop/array_index.main.GVN.64bit.panic-unwind.diff b/tests/mir-opt/const_prop/array_index.main.GVN.64bit.panic-unwind.diff index 38e7b2b688dd4..7e2f72ab31bce 100644 --- a/tests/mir-opt/const_prop/array_index.main.GVN.64bit.panic-unwind.diff +++ b/tests/mir-opt/const_prop/array_index.main.GVN.64bit.panic-unwind.diff @@ -15,8 +15,7 @@ bb0: { StorageLive(_1); StorageLive(_2); -- _2 = [const 0_u32, const 1_u32, const 2_u32, const 3_u32]; -+ _2 = const [0_u32, 1_u32, 2_u32, 3_u32]; + _2 = [const 0_u32, const 1_u32, const 2_u32, const 3_u32]; StorageLive(_3); _3 = const 2_usize; - _4 = Len(_2); @@ -36,9 +35,5 @@ StorageDead(_1); return; } -+ } -+ -+ ALLOC0 (size: 16, align: 4) { -+ 00 00 00 00 01 00 00 00 02 00 00 00 03 00 00 00 │ ................ } From ac4f464d8161e6e6b037c2ef1ab776a5c51a2be6 Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Fri, 14 Jun 2024 20:10:18 +0000 Subject: [PATCH 11/32] prevent code bloat for for arrays --- compiler/rustc_mir_transform/src/gvn.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index 8e5ce0f05f6b4..ac01b3b2af306 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -1488,6 +1488,14 @@ impl<'tcx> VnState<'_, 'tcx> { if let Value::Constant { value, disambiguator: _ } = value && value.is_deterministic() { + // Prevent code bloat that makes + // `_2 = _1` now resolved to `_2 = `. + if let Const::Val(_, ty) = value + && ty.is_array() + && self.rev_locals[index].len() > 1 + { + return None; + } return Some(ConstOperand { span: DUMMY_SP, user_ty: None, const_: *value }); } From 10004965765a0b7f2d81881df99bb1ed4521a71f Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Fri, 14 Jun 2024 20:12:32 +0000 Subject: [PATCH 12/32] dbg: move to sub functions for easier filtering tracing --- compiler/rustc_mir_transform/src/gvn.rs | 2 +- compiler/rustc_mir_transform/src/ssa.rs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index ac01b3b2af306..989ef3ae78b7e 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -138,7 +138,7 @@ fn propagate_ssa<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { let value = state.simplify_rvalue(rvalue, location); // FIXME(#112651) `rvalue` may have a subtype to `local`. We can only mark `local` as // reusable if we have an exact type match. - if state.local_decls[local].ty != rvalue.ty(state.local_decls, tcx) { + if state.local_decls[local].ty != rvalue.ty(state.local_decls, state.tcx) { return; } value diff --git a/compiler/rustc_mir_transform/src/ssa.rs b/compiler/rustc_mir_transform/src/ssa.rs index fb870425f6ef8..0230150a40214 100644 --- a/compiler/rustc_mir_transform/src/ssa.rs +++ b/compiler/rustc_mir_transform/src/ssa.rs @@ -147,6 +147,7 @@ impl SsaLocals { }) } + #[instrument(level = "trace", skip_all)] pub fn for_each_assignment_mut<'tcx>( &self, basic_blocks: &mut IndexSlice>, From 817f0977d509b67085f2e9f14169e316d6f60fa7 Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Fri, 14 Jun 2024 20:51:49 +0000 Subject: [PATCH 13/32] really ignore nested arrays --- compiler/rustc_mir_transform/src/gvn.rs | 19 +++++++++---------- .../mir-opt/const_array_locals.main.GVN.diff | 3 +-- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index 989ef3ae78b7e..8727e51b25ffd 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -927,8 +927,12 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { } let (mut ty, variant_index) = match *kind { - AggregateKind::Array(..) => { + AggregateKind::Array(ty) => { assert!(!field_ops.is_empty()); + // Ignore nested arrays + if ty.is_array() { + return None; + } (AggregateTy::Array, FIRST_VARIANT) } AggregateKind::Tuple => { @@ -1501,17 +1505,12 @@ impl<'tcx> VnState<'_, 'tcx> { let op = self.evaluated[index].as_ref()?; + // Ignore promoted arrays. if let Either::Left(mplace) = op.as_mplace_or_imm() - && let ty::Array(ty, _const) = mplace.layout.ty.kind() + && mplace.layout.ty.is_array() + && let Value::Projection(_index, ProjectionElem::Deref) = value { - // ignore nested arrays - if ty.is_array() { - return None; - } - // ignore promoted arrays - else if let Value::Projection(_index, ProjectionElem::Deref) = value { - return None; - } + return None; } let value = op_to_prop_const(&mut self.ecx, op)?; diff --git a/tests/mir-opt/const_array_locals.main.GVN.diff b/tests/mir-opt/const_array_locals.main.GVN.diff index 2276176b1cbd4..6eb9043b5f450 100644 --- a/tests/mir-opt/const_array_locals.main.GVN.diff +++ b/tests/mir-opt/const_array_locals.main.GVN.diff @@ -49,9 +49,8 @@ + _4 = const [255_i32, 105_i32, 15_i32, 39_i32, 62_i32, 251_i32, 191_i32, 178_i32, 9_i32, 4_i32, 56_i32, 221_i32]; StorageLive(_5); - _5 = [const 193_i32, const 164_i32, const 194_i32, const 197_i32, const 6_i32, const 243_i32, const 218_i32, const 171_i32, const 87_i32, const 247_i32, const 104_i32, const 42_i32]; -- _3 = [move _4, move _5]; + _5 = const [193_i32, 164_i32, 194_i32, 197_i32, 6_i32, 243_i32, 218_i32, 171_i32, 87_i32, 247_i32, 104_i32, 42_i32]; -+ _3 = [const [255_i32, 105_i32, 15_i32, 39_i32, 62_i32, 251_i32, 191_i32, 178_i32, 9_i32, 4_i32, 56_i32, 221_i32], const [193_i32, 164_i32, 194_i32, 197_i32, 6_i32, 243_i32, 218_i32, 171_i32, 87_i32, 247_i32, 104_i32, 42_i32]]; + _3 = [move _4, move _5]; StorageDead(_5); StorageDead(_4); StorageLive(_6); From 4762ebb64a1b31a79c826c9a144c7a733e8eb9b2 Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Fri, 14 Jun 2024 21:20:27 +0000 Subject: [PATCH 14/32] rm unneeded checks --- compiler/rustc_mir_transform/src/gvn.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index 8727e51b25ffd..bee80863bdddb 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -428,7 +428,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { return None; } let mut mplace = None; - let alloc_id = self + let _alloc_id = self .ecx .intern_with_temp_alloc(ty, |ecx, dest| { // FIXME: Can we speed it up by using `ecx.write_immediate(.ScalarPair(_), dest)`? @@ -443,11 +443,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { Ok(()) }) .ok()?; - let GlobalAlloc::Memory(_alloc) = self.tcx.global_alloc(alloc_id) else { - bug!() - }; let mplace = mplace.unwrap(); - debug!(?mplace); return Some(mplace.into()); } else if matches!(ty.abi, Abi::Scalar(..) | Abi::ScalarPair(..)) { let dest = self.ecx.allocate(ty, MemoryKind::Stack).ok()?; From 57ac10fa1014802858da771288f22df5d97d9b3f Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Sat, 15 Jun 2024 00:38:26 +0000 Subject: [PATCH 15/32] bless 32bit diff --- .../optimizes_into_variable.main.GVN.32bit.panic-unwind.diff | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.32bit.panic-unwind.diff b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.32bit.panic-unwind.diff index e6ee1e6f9a348..21461efd0abd9 100644 --- a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.32bit.panic-unwind.diff +++ b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.32bit.panic-unwind.diff @@ -35,7 +35,8 @@ + _1 = const 4_i32; StorageLive(_3); StorageLive(_4); - _4 = [const 0_i32, const 1_i32, const 2_i32, const 3_i32, const 4_i32, const 5_i32]; +- _4 = [const 0_i32, const 1_i32, const 2_i32, const 3_i32, const 4_i32, const 5_i32]; ++ _4 = const [0_i32, 1_i32, 2_i32, 3_i32, 4_i32, 5_i32]; StorageLive(_5); _5 = const 3_usize; _6 = const 6_usize; @@ -64,4 +65,6 @@ } + + ALLOC0 (size: 8, align: 4) { .. } ++ ++ ALLOC1 (size: 24, align: 4) { .. } From 3b75afed3ea3050f4160828572b5ce8efb18ab5f Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Sat, 15 Jun 2024 00:50:00 +0000 Subject: [PATCH 16/32] shorten array in tests big arrays make the diff hard to read --- .../mir-opt/const_array_locals.main.GVN.diff | 74 ++++++++----------- tests/mir-opt/const_array_locals.rs | 31 ++------ 2 files changed, 38 insertions(+), 67 deletions(-) diff --git a/tests/mir-opt/const_array_locals.main.GVN.diff b/tests/mir-opt/const_array_locals.main.GVN.diff index 6eb9043b5f450..03140119051fa 100644 --- a/tests/mir-opt/const_array_locals.main.GVN.diff +++ b/tests/mir-opt/const_array_locals.main.GVN.diff @@ -3,13 +3,13 @@ fn main() -> () { let mut _0: (); - let _1: [i32; 32]; - let mut _4: [i32; 12]; - let mut _5: [i32; 12]; - let mut _7: &[i32; 32]; - let _8: [i32; 32]; + let _1: [i32; 5]; + let mut _4: [i32; 5]; + let mut _5: [i32; 5]; + let mut _7: &[i32; 5]; + let _8: [i32; 5]; let _9: (); - let mut _10: [u16; 32]; + let mut _10: [u32; 5]; let mut _12: [f32; 8]; let _13: [[i32; 3]; 3]; let mut _14: [i32; 3]; @@ -17,14 +17,14 @@ let mut _16: [i32; 3]; scope 1 { debug _arr => _1; - let _2: [i32; 32]; + let _2: [i32; 5]; scope 2 { - debug _barr => _2; - let _3: [[i32; 12]; 2]; + debug _duplicated_arr => _2; + let _3: [[i32; 5]; 2]; scope 3 { debug _foo => _3; - let _6: [i32; 32]; - let mut _17: &[i32; 32]; + let _6: [i32; 5]; + let mut _17: &[i32; 5]; scope 4 { debug _darr => _6; let _11: F32x8; @@ -38,18 +38,18 @@ bb0: { StorageLive(_1); -- _1 = [const 255_i32, const 105_i32, const 15_i32, const 39_i32, const 62_i32, const 251_i32, const 191_i32, const 178_i32, const 9_i32, const 4_i32, const 56_i32, const 221_i32, const 193_i32, const 164_i32, const 194_i32, const 197_i32, const 6_i32, const 243_i32, const 218_i32, const 171_i32, const 87_i32, const 247_i32, const 104_i32, const 159_i32, const 22_i32, const 157_i32, const 105_i32, const 31_i32, const 96_i32, const 173_i32, const 50_i32, const 1_i32]; -+ _1 = const [255_i32, 105_i32, 15_i32, 39_i32, 62_i32, 251_i32, 191_i32, 178_i32, 9_i32, 4_i32, 56_i32, 221_i32, 193_i32, 164_i32, 194_i32, 197_i32, 6_i32, 243_i32, 218_i32, 171_i32, 87_i32, 247_i32, 104_i32, 159_i32, 22_i32, 157_i32, 105_i32, 31_i32, 96_i32, 173_i32, 50_i32, 1_i32]; +- _1 = [const 255_i32, const 105_i32, const 15_i32, const 39_i32, const 62_i32]; ++ _1 = const [255_i32, 105_i32, 15_i32, 39_i32, 62_i32]; StorageLive(_2); -- _2 = [const 255_i32, const 105_i32, const 15_i32, const 39_i32, const 62_i32, const 251_i32, const 191_i32, const 178_i32, const 9_i32, const 4_i32, const 56_i32, const 221_i32, const 193_i32, const 164_i32, const 194_i32, const 197_i32, const 6_i32, const 243_i32, const 218_i32, const 171_i32, const 87_i32, const 247_i32, const 104_i32, const 159_i32, const 22_i32, const 157_i32, const 105_i32, const 31_i32, const 96_i32, const 173_i32, const 50_i32, const 1_i32]; -+ _2 = const [255_i32, 105_i32, 15_i32, 39_i32, 62_i32, 251_i32, 191_i32, 178_i32, 9_i32, 4_i32, 56_i32, 221_i32, 193_i32, 164_i32, 194_i32, 197_i32, 6_i32, 243_i32, 218_i32, 171_i32, 87_i32, 247_i32, 104_i32, 159_i32, 22_i32, 157_i32, 105_i32, 31_i32, 96_i32, 173_i32, 50_i32, 1_i32]; +- _2 = [const 255_i32, const 105_i32, const 15_i32, const 39_i32, const 62_i32]; ++ _2 = const [255_i32, 105_i32, 15_i32, 39_i32, 62_i32]; StorageLive(_3); StorageLive(_4); -- _4 = [const 255_i32, const 105_i32, const 15_i32, const 39_i32, const 62_i32, const 251_i32, const 191_i32, const 178_i32, const 9_i32, const 4_i32, const 56_i32, const 221_i32]; -+ _4 = const [255_i32, 105_i32, 15_i32, 39_i32, 62_i32, 251_i32, 191_i32, 178_i32, 9_i32, 4_i32, 56_i32, 221_i32]; +- _4 = [const 178_i32, const 9_i32, const 4_i32, const 56_i32, const 221_i32]; ++ _4 = const [178_i32, 9_i32, 4_i32, 56_i32, 221_i32]; StorageLive(_5); -- _5 = [const 193_i32, const 164_i32, const 194_i32, const 197_i32, const 6_i32, const 243_i32, const 218_i32, const 171_i32, const 87_i32, const 247_i32, const 104_i32, const 42_i32]; -+ _5 = const [193_i32, 164_i32, 194_i32, 197_i32, 6_i32, 243_i32, 218_i32, 171_i32, 87_i32, 247_i32, 104_i32, 42_i32]; +- _5 = [const 193_i32, const 164_i32, const 194_i32, const 197_i32, const 6_i32]; ++ _5 = const [193_i32, 164_i32, 194_i32, 197_i32, 6_i32]; _3 = [move _4, move _5]; StorageDead(_5); StorageDead(_4); @@ -62,10 +62,10 @@ StorageDead(_7); StorageLive(_9); StorageLive(_10); -- _10 = [const 255_u16, const 105_u16, const 15_u16, const 39_u16, const 62_u16, const 251_u16, const 191_u16, const 178_u16, const 9_u16, const 4_u16, const 56_u16, const 221_u16, const 193_u16, const 164_u16, const 194_u16, const 197_u16, const 6_u16, const 243_u16, const 218_u16, const 171_u16, const 87_u16, const 247_u16, const 104_u16, const 159_u16, const 22_u16, const 157_u16, const 105_u16, const 31_u16, const 96_u16, const 173_u16, const 50_u16, const 1_u16]; +- _10 = [const 31_u32, const 96_u32, const 173_u32, const 50_u32, const 1_u32]; - _9 = consume(move _10) -> [return: bb1, unwind continue]; -+ _10 = const [255_u16, 105_u16, 15_u16, 39_u16, 62_u16, 251_u16, 191_u16, 178_u16, 9_u16, 4_u16, 56_u16, 221_u16, 193_u16, 164_u16, 194_u16, 197_u16, 6_u16, 243_u16, 218_u16, 171_u16, 87_u16, 247_u16, 104_u16, 159_u16, 22_u16, 157_u16, 105_u16, 31_u16, 96_u16, 173_u16, 50_u16, 1_u16]; -+ _9 = consume(const [255_u16, 105_u16, 15_u16, 39_u16, 62_u16, 251_u16, 191_u16, 178_u16, 9_u16, 4_u16, 56_u16, 221_u16, 193_u16, 164_u16, 194_u16, 197_u16, 6_u16, 243_u16, 218_u16, 171_u16, 87_u16, 247_u16, 104_u16, 159_u16, 22_u16, 157_u16, 105_u16, 31_u16, 96_u16, 173_u16, 50_u16, 1_u16]) -> [return: bb1, unwind continue]; ++ _10 = const [31_u32, 96_u32, 173_u32, 50_u32, 1_u32]; ++ _9 = consume(const [31_u32, 96_u32, 173_u32, 50_u32, 1_u32]) -> [return: bb1, unwind continue]; } bb1: { @@ -105,33 +105,23 @@ + 0x10 │ 00 00 80 3f 00 00 80 3f 00 00 80 3f 00 00 28 42 │ ...?...?...?..(B + } + -+ ALLOC1 (size: 64, align: 2) { -+ 0x00 │ ff 00 69 00 0f 00 27 00 3e 00 fb 00 bf 00 b2 00 │ ..i...'.>....... -+ 0x10 │ 09 00 04 00 38 00 dd 00 c1 00 a4 00 c2 00 c5 00 │ ....8........... -+ 0x20 │ 06 00 f3 00 da 00 ab 00 57 00 f7 00 68 00 9f 00 │ ........W...h... -+ 0x30 │ 16 00 9d 00 69 00 1f 00 60 00 ad 00 32 00 01 00 │ ....i...`...2... ++ ALLOC1 (size: 20, align: 4) { ++ 0x00 │ 1f 00 00 00 60 00 00 00 ad 00 00 00 32 00 00 00 │ ....`.......2... ++ 0x10 │ 01 00 00 00 │ .... + } + -+ ALLOC2 (size: 48, align: 4) { ++ ALLOC2 (size: 20, align: 4) { + 0x00 │ c1 00 00 00 a4 00 00 00 c2 00 00 00 c5 00 00 00 │ ................ -+ 0x10 │ 06 00 00 00 f3 00 00 00 da 00 00 00 ab 00 00 00 │ ................ -+ 0x20 │ 57 00 00 00 f7 00 00 00 68 00 00 00 2a 00 00 00 │ W.......h...*... ++ 0x10 │ 06 00 00 00 │ .... + } + -+ ALLOC3 (size: 48, align: 4) { -+ 0x00 │ ff 00 00 00 69 00 00 00 0f 00 00 00 27 00 00 00 │ ....i.......'... -+ 0x10 │ 3e 00 00 00 fb 00 00 00 bf 00 00 00 b2 00 00 00 │ >............... -+ 0x20 │ 09 00 00 00 04 00 00 00 38 00 00 00 dd 00 00 00 │ ........8....... ++ ALLOC3 (size: 20, align: 4) { ++ 0x00 │ b2 00 00 00 09 00 00 00 04 00 00 00 38 00 00 00 │ ............8... ++ 0x10 │ dd 00 00 00 │ .... + } + -+ ALLOC4 (size: 128, align: 4) { ++ ALLOC4 (size: 20, align: 4) { + 0x00 │ ff 00 00 00 69 00 00 00 0f 00 00 00 27 00 00 00 │ ....i.......'... -+ 0x10 │ 3e 00 00 00 fb 00 00 00 bf 00 00 00 b2 00 00 00 │ >............... -+ 0x20 │ 09 00 00 00 04 00 00 00 38 00 00 00 dd 00 00 00 │ ........8....... -+ 0x30 │ c1 00 00 00 a4 00 00 00 c2 00 00 00 c5 00 00 00 │ ................ -+ 0x40 │ 06 00 00 00 f3 00 00 00 da 00 00 00 ab 00 00 00 │ ................ -+ 0x50 │ 57 00 00 00 f7 00 00 00 68 00 00 00 9f 00 00 00 │ W.......h....... -+ 0x60 │ 16 00 00 00 9d 00 00 00 69 00 00 00 1f 00 00 00 │ ........i....... -+ 0x70 │ 60 00 00 00 ad 00 00 00 32 00 00 00 01 00 00 00 │ `.......2....... ++ 0x10 │ 3e 00 00 00 │ >... } diff --git a/tests/mir-opt/const_array_locals.rs b/tests/mir-opt/const_array_locals.rs index 88cceeff9ac56..ab71a6b5d2c7f 100644 --- a/tests/mir-opt/const_array_locals.rs +++ b/tests/mir-opt/const_array_locals.rs @@ -6,32 +6,13 @@ struct F32x8([f32; 8]); // EMIT_MIR const_array_locals.main.GVN.diff // CHECK-LABEL: fn main( -#[rustfmt::skip] pub fn main() { - let _arr = [ - 255, 105, 15, 39, 62, 251, 191, 178, 9, 4, 56, 221, - 193, 164, 194, 197, 6, 243, 218, 171, 87, 247, 104, - 159, 22, 157, 105, 31, 96, 173, 50, 1, - ]; - // duplicate item - let _barr = [ - 255, 105, 15, 39, 62, 251, 191, 178, 9, 4, 56, 221, - 193, 164, 194, 197, 6, 243, 218, 171, 87, 247, 104, - 159, 22, 157, 105, 31, 96, 173, 50, 1, - ]; - let _foo = [ - [255, 105, 15, 39, 62, 251, 191, 178, 9, 4, 56, 221], - [193, 164, 194, 197, 6, 243, 218, 171, 87, 247, 104, 42], - ]; - let _darr = *&[ - 255, 105, 15, 39, 62, 251, 191, 178, 9, 4, 56, 221, - 193, 164, 194, 197, 6, 243, 218, 171, 87, 247, 104, - 159, 22, 157, 105, 31, 96, 173, 50, 1, - ]; + let _arr = [255, 105, 15, 39, 62]; + let _duplicated_arr = [255, 105, 15, 39, 62]; + let _foo = [[178, 9, 4, 56, 221], [193, 164, 194, 197, 6]]; + let _darr = *&[254, 42, 15, 39, 62]; - consume([255, 105, 15, 39, 62, 251, 191, 178, 9, 4, 56, 221, - 193, 164, 194, 197, 6, 243, 218, 171, 87, 247, 104, - 159, 22, 157, 105, 31, 96, 173, 50, 1,]); + consume([31, 96, 173, 50, 1]); let _f = F32x8([1.0, 2.0, 3.0, 1.0, 1.0, 1.0, 1.0, 42.0]); @@ -39,6 +20,6 @@ pub fn main() { [[1, 0, 0], [0, 1, 0], [0, 0, 1]]; // 2D array } -fn consume(_arr: [u16; 32]) { +fn consume(_arr: [u32; 5]) { unimplemented!() } From 8093f11f0c7e4ddc0f80876d707ccc36f5d0dacb Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Sat, 15 Jun 2024 11:26:38 +0000 Subject: [PATCH 17/32] ignore arrays in operands --- compiler/rustc_mir_transform/src/gvn.rs | 4 ++++ tests/mir-opt/const_array_locals.main.GVN.diff | 3 +-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index bee80863bdddb..9a931f348c8ec 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -816,6 +816,10 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { } Operand::Copy(ref mut place) | Operand::Move(ref mut place) => { let value = self.simplify_place_value(place, location)?; + // Ignore arrays in operand. + if let Value::Aggregate(AggregateTy::Array, ..) = self.get(value) { + return None; + } if let Some(const_) = self.try_as_constant(value) { *operand = Operand::Constant(Box::new(const_)); } diff --git a/tests/mir-opt/const_array_locals.main.GVN.diff b/tests/mir-opt/const_array_locals.main.GVN.diff index 03140119051fa..b9ba75ad3f20d 100644 --- a/tests/mir-opt/const_array_locals.main.GVN.diff +++ b/tests/mir-opt/const_array_locals.main.GVN.diff @@ -74,9 +74,8 @@ StorageLive(_11); StorageLive(_12); - _12 = [const 1f32, const 2f32, const 3f32, const 1f32, const 1f32, const 1f32, const 1f32, const 42f32]; -- _11 = F32x8(move _12); + _12 = const [1f32, 2f32, 3f32, 1f32, 1f32, 1f32, 1f32, 42f32]; -+ _11 = F32x8(const [1f32, 2f32, 3f32, 1f32, 1f32, 1f32, 1f32, 42f32]); + _11 = F32x8(move _12); StorageDead(_12); StorageLive(_13); StorageLive(_14); From 41484d325437f6bf2166de9902041cb3eea403ef Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Sat, 15 Jun 2024 11:27:06 +0000 Subject: [PATCH 18/32] disallow duplicate arrays in rvalue --- compiler/rustc_mir_transform/src/gvn.rs | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index 9a931f348c8ec..a834cee5f228f 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -816,7 +816,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { } Operand::Copy(ref mut place) | Operand::Move(ref mut place) => { let value = self.simplify_place_value(place, location)?; - // Ignore arrays in operand. + // Ignore arrays in operands. if let Value::Aggregate(AggregateTy::Array, ..) = self.get(value) { return None; } @@ -1492,14 +1492,6 @@ impl<'tcx> VnState<'_, 'tcx> { if let Value::Constant { value, disambiguator: _ } = value && value.is_deterministic() { - // Prevent code bloat that makes - // `_2 = _1` now resolved to `_2 = `. - if let Const::Val(_, ty) = value - && ty.is_array() - && self.rev_locals[index].len() > 1 - { - return None; - } return Some(ConstOperand { span: DUMMY_SP, user_ty: None, const_: *value }); } @@ -1566,7 +1558,19 @@ impl<'tcx> MutVisitor<'tcx> for VnState<'_, 'tcx> { let Some(value) = value else { return }; debug!(before_rvalue = ?rvalue); - if let Some(const_) = self.try_as_constant(value) { + // Ignore arrays in operands. + // Prevent code bloat that makes + // `_2 = _1` now resolved to `_2 = `. + let disallow_dup_array = if rvalue.ty(self.local_decls, self.tcx).is_array() + && let Some(locals) = self.rev_locals.get(value).as_deref() + && let [first, ..] = locals[..] + { + first != lhs.local + } else { + false + }; + + if !disallow_dup_array && let Some(const_) = self.try_as_constant(value) { *rvalue = Rvalue::Use(Operand::Constant(Box::new(const_))); } else if let Some(local) = self.try_as_local(value, location) && *rvalue != Rvalue::Use(Operand::Move(local.into())) From 27117a19603f49a480d5d57fcd914ba5111aa5a8 Mon Sep 17 00:00:00 2001 From: tesuji <15225902+tesuji@users.noreply.github.com> Date: Sun, 16 Jun 2024 23:13:28 +0700 Subject: [PATCH 19/32] Apply suggestions from code review Co-authored-by: Camille Gillot --- compiler/rustc_mir_transform/src/gvn.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index a834cee5f228f..5c03ff5eba845 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -372,9 +372,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { // But to avoid blessing differences between 32-bit and 64-bit target, // let's choose `size_t = u64`. const STACK_THRESHOLD: u64 = std::mem::size_of::() as u64 * 2; - let vvalue = self.get(value); - debug!(?vvalue); - let op = match *vvalue { + let op = match *self.get(value) { Opaque(_) => return None, // Do not bother evaluating repeat expressions. This would uselessly consume memory. Repeat(..) => return None, @@ -444,7 +442,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { }) .ok()?; let mplace = mplace.unwrap(); - return Some(mplace.into()); + mplace.into() } else if matches!(ty.abi, Abi::Scalar(..) | Abi::ScalarPair(..)) { let dest = self.ecx.allocate(ty, MemoryKind::Stack).ok()?; let variant_dest = if let Some(variant) = variant { From 65a9c756a5b76a7bb52e9f852c6946e22568c26e Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Sun, 16 Jun 2024 17:19:02 +0000 Subject: [PATCH 20/32] add explicit mir checks for mir-opt test --- .../mir-opt/const_array_locals.main.GVN.diff | 11 +++++----- tests/mir-opt/const_array_locals.rs | 22 ++++++++++++++++++- 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/tests/mir-opt/const_array_locals.main.GVN.diff b/tests/mir-opt/const_array_locals.main.GVN.diff index b9ba75ad3f20d..6cf2f9707e4f5 100644 --- a/tests/mir-opt/const_array_locals.main.GVN.diff +++ b/tests/mir-opt/const_array_locals.main.GVN.diff @@ -37,12 +37,13 @@ } bb0: { - StorageLive(_1); +- StorageLive(_1); - _1 = [const 255_i32, const 105_i32, const 15_i32, const 39_i32, const 62_i32]; ++ nop; + _1 = const [255_i32, 105_i32, 15_i32, 39_i32, 62_i32]; StorageLive(_2); - _2 = [const 255_i32, const 105_i32, const 15_i32, const 39_i32, const 62_i32]; -+ _2 = const [255_i32, 105_i32, 15_i32, 39_i32, 62_i32]; ++ _2 = _1; StorageLive(_3); StorageLive(_4); - _4 = [const 178_i32, const 9_i32, const 4_i32, const 56_i32, const 221_i32]; @@ -63,9 +64,8 @@ StorageLive(_9); StorageLive(_10); - _10 = [const 31_u32, const 96_u32, const 173_u32, const 50_u32, const 1_u32]; -- _9 = consume(move _10) -> [return: bb1, unwind continue]; + _10 = const [31_u32, 96_u32, 173_u32, 50_u32, 1_u32]; -+ _9 = consume(const [31_u32, 96_u32, 173_u32, 50_u32, 1_u32]) -> [return: bb1, unwind continue]; + _9 = consume(move _10) -> [return: bb1, unwind continue]; } bb1: { @@ -94,7 +94,8 @@ StorageDead(_6); StorageDead(_3); StorageDead(_2); - StorageDead(_1); +- StorageDead(_1); ++ nop; return; } + } diff --git a/tests/mir-opt/const_array_locals.rs b/tests/mir-opt/const_array_locals.rs index ab71a6b5d2c7f..bc6d98314a8ac 100644 --- a/tests/mir-opt/const_array_locals.rs +++ b/tests/mir-opt/const_array_locals.rs @@ -6,17 +6,37 @@ struct F32x8([f32; 8]); // EMIT_MIR const_array_locals.main.GVN.diff // CHECK-LABEL: fn main( +// CHECK: debug _arr => [[_arr:_[0-9]+]]; +// CHECK: debug _duplicated_arr => [[_duplicated_arr:_[0-9]+]]; +// CHECK: debug _foo => [[_foo:_[0-9]+]]; +// CHECK: debug _darr => [[_darr:_[0-9]+]]; +// CHECK: debug _f => [[_f:_[0-9]+]]; pub fn main() { + // CHECK: [[_arr]] = const [255_i32, 105_i32, 15_i32, 39_i32, 62_i32]; let _arr = [255, 105, 15, 39, 62]; + // CHECK: [[_duplicated_arr]] = [[_arr]]; let _duplicated_arr = [255, 105, 15, 39, 62]; + // CHECK: [[subarray1:_[0-9]+]] = const [178_i32, 9_i32, 4_i32, 56_i32, 221_i32]; + // CHECK: [[subarray2:_[0-9]+]] = const [193_i32, 164_i32, 194_i32, 197_i32, 6_i32]; + // CHECK: [[_foo]] = [move [[subarray1]], move [[subarray2]]]; let _foo = [[178, 9, 4, 56, 221], [193, 164, 194, 197, 6]]; + // CHECK: [[PROMOTED:_[0-9]+]] = const main::promoted[0]; + // CHECK: [[_darr]] = (*[[PROMOTED]]); let _darr = *&[254, 42, 15, 39, 62]; + // CHECK: [[ARG:_[0-9]+]] = const [31_u32, 96_u32, 173_u32, 50_u32, 1_u32]; + // CHECK: consume(move [[ARG]]) consume([31, 96, 173, 50, 1]); + // CHECK: [[OP:_[0-9]+]] = const [1f32, 2f32, 3f32, 1f32, 1f32, 1f32, 1f32, 42f32]; + // CHECK: [[_f]] = F32x8(move [[OP]]); let _f = F32x8([1.0, 2.0, 3.0, 1.0, 1.0, 1.0, 1.0, 42.0]); - // ice + // ice with small arrays + // CHECK: [[A:_[0-9]+]] = [const 1_i32, const 0_i32, const 0_i32]; + // CHECK: [[B:_[0-9]+]] = [const 0_i32, const 1_i32, const 0_i32]; + // CHECK: [[C:_[0-9]+]] = [const 0_i32, const 0_i32, const 1_i32]; + // CHECK: {{_[0-9]+}} = [move [[A]], move [[B]], move [[C]]]; [[1, 0, 0], [0, 1, 0], [0, 0, 1]]; // 2D array } From e0c2e81e51aea5f012a97d036be607337e0120f6 Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Sun, 16 Jun 2024 17:39:14 +0000 Subject: [PATCH 21/32] explain why we ignore nested arrays --- compiler/rustc_mir_transform/src/gvn.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index 5c03ff5eba845..4f6e334e2da86 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -389,7 +389,8 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { AggregateTy::Array => { assert!(fields.len() > 0); let field_ty = fields[0].layout.ty; - // Ignore nested array + // FIXME: Ignore nested arrays, because arrays is large. Nested arrays are rarer and bigger + // while we already process 1-dimension arrays, which is enough? if field_ty.is_array() { trace!( "ignoring nested array of type: [{field_ty}; {len}]", @@ -814,7 +815,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { } Operand::Copy(ref mut place) | Operand::Move(ref mut place) => { let value = self.simplify_place_value(place, location)?; - // Ignore arrays in operands. + // In MIR, the array assignments are previously processed before operands. if let Value::Aggregate(AggregateTy::Array, ..) = self.get(value) { return None; } @@ -927,7 +928,8 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { let (mut ty, variant_index) = match *kind { AggregateKind::Array(ty) => { assert!(!field_ops.is_empty()); - // Ignore nested arrays + // FIXME: Ignore nested arrays, because arrays is large. Nested arrays are rarer and bigger + // while we already process 1-dimension arrays, which is enough? if ty.is_array() { return None; } From 2b7e2a43a530179e8ed1daefabd89c1bd5a2e759 Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Sun, 16 Jun 2024 17:50:48 +0000 Subject: [PATCH 22/32] Explain code with more comments --- compiler/rustc_mir_transform/src/gvn.rs | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index 4f6e334e2da86..e32cc7c7bab17 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -1409,7 +1409,9 @@ fn op_to_prop_const<'tcx>( return Some(ConstValue::ZeroSized); } - // Do not synthetize too large constants. Codegen will just memcpy them, which we'd like to avoid. + // Do not synthesize too large constants, except constant arrays. + // For arrays, codegen will just memcpy them, but LLVM will optimize out those unneeded memcpy. + // For others, we'd prefer in-place initialization over memcpy them. if !(op.layout.ty.is_array() || matches!(op.layout.abi, Abi::Scalar(..) | Abi::ScalarPair(..))) { return None; @@ -1487,17 +1489,18 @@ impl<'tcx> VnState<'_, 'tcx> { // This was already constant in MIR, do not change it. let value = self.get(index); debug!(?index, ?value); - // If the constant is not deterministic, adding an additional mention of it in MIR will - // not give the same value as the former mention. - if let Value::Constant { value, disambiguator: _ } = value + if let Value::Constant { value, disambiguator: _ } = *value + // If the constant is not deterministic, adding an additional mention of it in MIR will + // not give the same value as the former mention. && value.is_deterministic() { - return Some(ConstOperand { span: DUMMY_SP, user_ty: None, const_: *value }); + return Some(ConstOperand { span: DUMMY_SP, user_ty: None, const_: value }); } let op = self.evaluated[index].as_ref()?; - // Ignore promoted arrays. + // Ignore promoted arrays. Promoted arrays are already placed in `.rodata`. + // Which is what we try to archive for running gvn on constant local arrays. if let Either::Left(mplace) = op.as_mplace_or_imm() && mplace.layout.ty.is_array() && let Value::Projection(_index, ProjectionElem::Deref) = value @@ -1558,10 +1561,8 @@ impl<'tcx> MutVisitor<'tcx> for VnState<'_, 'tcx> { let Some(value) = value else { return }; debug!(before_rvalue = ?rvalue); - // Ignore arrays in operands. - // Prevent code bloat that makes - // `_2 = _1` now resolved to `_2 = `. - let disallow_dup_array = if rvalue.ty(self.local_decls, self.tcx).is_array() + // De-duplicate locals has the same arrays assigned to prevent code bloat. + let disallowed_duplicated_array = if rvalue.ty(self.local_decls, self.tcx).is_array() && let Some(locals) = self.rev_locals.get(value).as_deref() && let [first, ..] = locals[..] { @@ -1570,7 +1571,7 @@ impl<'tcx> MutVisitor<'tcx> for VnState<'_, 'tcx> { false }; - if !disallow_dup_array && let Some(const_) = self.try_as_constant(value) { + if !disallowed_duplicated_array && let Some(const_) = self.try_as_constant(value) { *rvalue = Rvalue::Use(Operand::Constant(Box::new(const_))); } else if let Some(local) = self.try_as_local(value, location) && *rvalue != Rvalue::Use(Operand::Move(local.into())) From 44de1f1001c171819e65bbbcdab5571fe53568fc Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Sun, 16 Jun 2024 17:54:18 +0000 Subject: [PATCH 23/32] rm some debug! --- compiler/rustc_mir_transform/src/gvn.rs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index e32cc7c7bab17..29a06941a5eef 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -1487,9 +1487,7 @@ impl<'tcx> VnState<'_, 'tcx> { #[instrument(level = "trace", skip(self, index), ret)] fn try_as_constant(&mut self, index: VnIndex) -> Option> { // This was already constant in MIR, do not change it. - let value = self.get(index); - debug!(?index, ?value); - if let Value::Constant { value, disambiguator: _ } = *value + if let Value::Constant { value, disambiguator: _ } = *self.get(index) // If the constant is not deterministic, adding an additional mention of it in MIR will // not give the same value as the former mention. && value.is_deterministic() @@ -1557,10 +1555,8 @@ impl<'tcx> MutVisitor<'tcx> for VnState<'_, 'tcx> { .as_local() .and_then(|local| self.locals[local]) .or_else(|| self.simplify_rvalue(rvalue, location)); - debug!(?value); let Some(value) = value else { return }; - debug!(before_rvalue = ?rvalue); // De-duplicate locals has the same arrays assigned to prevent code bloat. let disallowed_duplicated_array = if rvalue.ty(self.local_decls, self.tcx).is_array() && let Some(locals) = self.rev_locals.get(value).as_deref() @@ -1579,7 +1575,6 @@ impl<'tcx> MutVisitor<'tcx> for VnState<'_, 'tcx> { *rvalue = Rvalue::Use(Operand::Copy(local.into())); self.reused_locals.insert(local); } - debug!(after_rvalue = ?rvalue); return; } From 779fa4035223d28f54d6ed9b37f94769e7ef78ce Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Sun, 16 Jun 2024 23:31:43 +0000 Subject: [PATCH 24/32] replace ecx.intern_with_temp_alloc with ecx.alloc --- compiler/rustc_mir_transform/src/gvn.rs | 26 ++++++++----------------- 1 file changed, 8 insertions(+), 18 deletions(-) diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index 29a06941a5eef..302efd17bf3a5 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -426,24 +426,14 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { if ty.layout.size().bytes() <= STACK_THRESHOLD { return None; } - let mut mplace = None; - let _alloc_id = self - .ecx - .intern_with_temp_alloc(ty, |ecx, dest| { - // FIXME: Can we speed it up by using `ecx.write_immediate(.ScalarPair(_), dest)`? - for (field_index, op) in fields.iter().copied().enumerate() { - let field_dest = ecx.project_field(dest, field_index)?; - ecx.copy_op(op, &field_dest)?; - } - - let dest = - dest.assert_mem_place().map_provenance(|prov| prov.as_immutable()); - mplace.replace(dest); - Ok(()) - }) - .ok()?; - let mplace = mplace.unwrap(); - mplace.into() + let dest = self.ecx.allocate(ty, MemoryKind::Stack).ok()?; + // FIXME: Can we speed it up by using `ecx.write_immediate(.ScalarPair(_), dest)`? + for (field_index, op) in fields.iter().copied().enumerate() { + let field_dest = self.ecx.project_field(&dest, field_index).ok()?; + self.ecx.copy_op(op, &field_dest).ok()?; + } + let dest = dest.map_provenance(|prov| prov.as_immutable()); + dest.into() } else if matches!(ty.abi, Abi::Scalar(..) | Abi::ScalarPair(..)) { let dest = self.ecx.allocate(ty, MemoryKind::Stack).ok()?; let variant_dest = if let Some(variant) = variant { From 9fa040ef97d1155a3722d1f176d3cca87cfb714d Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Sun, 14 Jul 2024 01:39:08 +0000 Subject: [PATCH 25/32] explain why don't eval array locals as const operands --- compiler/rustc_mir_transform/src/gvn.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index 302efd17bf3a5..2ed6c45940330 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -805,7 +805,8 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { } Operand::Copy(ref mut place) | Operand::Move(ref mut place) => { let value = self.simplify_place_value(place, location)?; - // In MIR, the array assignments are previously processed before operands. + // NOTE(tesuji): We just want to promote rvalues of array kind that assigned to a local, and + // not evaluate this local as a const operand of a function to avoid bloating MIR. if let Value::Aggregate(AggregateTy::Array, ..) = self.get(value) { return None; } From eac1ae73be637ae3a3f287fc108f07bb9cddd29b Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Sun, 14 Jul 2024 02:30:18 +0000 Subject: [PATCH 26/32] Defer to llvm to deduplicate promote allocations Between promote temps pass and gvn --- compiler/rustc_mir_transform/src/gvn.rs | 9 ------ .../issue-73825-gvn-const-local-array.rs | 28 ++++++++++++++++++- .../mir-opt/const_array_locals.main.GVN.diff | 7 ++++- tests/mir-opt/const_array_locals.rs | 2 +- 4 files changed, 34 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index 2ed6c45940330..0c3adfa9859bd 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -1488,15 +1488,6 @@ impl<'tcx> VnState<'_, 'tcx> { let op = self.evaluated[index].as_ref()?; - // Ignore promoted arrays. Promoted arrays are already placed in `.rodata`. - // Which is what we try to archive for running gvn on constant local arrays. - if let Either::Left(mplace) = op.as_mplace_or_imm() - && mplace.layout.ty.is_array() - && let Value::Projection(_index, ProjectionElem::Deref) = value - { - return None; - } - let value = op_to_prop_const(&mut self.ecx, op)?; // Check that we do not leak a pointer. diff --git a/tests/codegen/issue-73825-gvn-const-local-array.rs b/tests/codegen/issue-73825-gvn-const-local-array.rs index cd70eb330f112..1b25899168a85 100644 --- a/tests/codegen/issue-73825-gvn-const-local-array.rs +++ b/tests/codegen/issue-73825-gvn-const-local-array.rs @@ -6,7 +6,7 @@ // CHECK-NEXT: start: // CHECK-NEXT: %_3 = and i64 %x, 63 // CHECK-NEXT: %0 = getelementptr inbounds [64 x i32], ptr @0, i64 0, i64 %_3 -// CHECK-NEXT: %_0 = load i32, ptr %0, align 4, !noundef !3 +// CHECK-NEXT: %_0 = load i32, ptr %0, align 4 // CHECK-NEXT: ret i32 %_0 #[no_mangle] #[rustfmt::skip] @@ -23,3 +23,29 @@ pub fn foo(x: usize) -> i32 { ]; base[x % 64] } + +// This checks whether LLVM de-duplicates `promoted` array and `base` array. +// Because in MIR, `&[..]` is already promoted by promote pass. GVN keeps promoting +// `*&[..]` to `const [..]` again. +// +// CHECK-LABEL: @deduplicability +// CHECK-NEXT: start: +// CHECK-NEXT: %_3 = and i64 %x, 63 +// CHECK-NEXT: %0 = getelementptr inbounds [64 x i32], ptr @0, i64 0, i64 %_3 +// CHECK-NEXT: %_0 = load i32, ptr %0, align 4 +// CHECK-NEXT: ret i32 %_0 +#[no_mangle] +#[rustfmt::skip] +pub fn deduplicability(x: usize) -> i32 { + let promoted = *&[ + 67i32, 754, 860, 559, 368, 870, 548, 972, + 141, 731, 351, 664, 32, 4, 996, 741, + 203, 292, 237, 480, 151, 940, 777, 540, + 143, 587, 747, 65, 152, 517, 882, 880, + 712, 595, 370, 901, 237, 53, 789, 785, + 912, 650, 896, 367, 316, 392, 62, 473, + 675, 691, 281, 192, 445, 970, 225, 425, + 628, 324, 322, 206, 912, 867, 462, 92 + ]; + promoted[x % 64] +} diff --git a/tests/mir-opt/const_array_locals.main.GVN.diff b/tests/mir-opt/const_array_locals.main.GVN.diff index 6cf2f9707e4f5..6dcb2974b0481 100644 --- a/tests/mir-opt/const_array_locals.main.GVN.diff +++ b/tests/mir-opt/const_array_locals.main.GVN.diff @@ -59,7 +59,7 @@ _17 = const main::promoted[0]; _7 = &(*_17); - _6 = (*_7); -+ _6 = (*_17); ++ _6 = const [254_i32, 42_i32, 15_i32, 39_i32, 62_i32]; StorageDead(_7); StorageLive(_9); StorageLive(_10); @@ -122,6 +122,11 @@ + + ALLOC4 (size: 20, align: 4) { + 0x00 │ ff 00 00 00 69 00 00 00 0f 00 00 00 27 00 00 00 │ ....i.......'... ++ 0x10 │ 3e 00 00 00 │ >... ++ } ++ ++ ALLOC5 (size: 20, align: 4) { ++ 0x00 │ fe 00 00 00 2a 00 00 00 0f 00 00 00 27 00 00 00 │ ....*.......'... + 0x10 │ 3e 00 00 00 │ >... } diff --git a/tests/mir-opt/const_array_locals.rs b/tests/mir-opt/const_array_locals.rs index bc6d98314a8ac..9871b7ff1d484 100644 --- a/tests/mir-opt/const_array_locals.rs +++ b/tests/mir-opt/const_array_locals.rs @@ -21,7 +21,7 @@ pub fn main() { // CHECK: [[_foo]] = [move [[subarray1]], move [[subarray2]]]; let _foo = [[178, 9, 4, 56, 221], [193, 164, 194, 197, 6]]; // CHECK: [[PROMOTED:_[0-9]+]] = const main::promoted[0]; - // CHECK: [[_darr]] = (*[[PROMOTED]]); + // CHECK: [[_darr]] = const [254_i32, 42_i32, 15_i32, 39_i32, 62_i32]; let _darr = *&[254, 42, 15, 39, 62]; // CHECK: [[ARG:_[0-9]+]] = const [31_u32, 96_u32, 173_u32, 50_u32, 1_u32]; From 96b505eaa4c05e068ca33c64c105e8a1ecae82b2 Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Sun, 14 Jul 2024 02:40:17 +0000 Subject: [PATCH 27/32] Let LLVM de-duplicates arrays has same value --- compiler/rustc_mir_transform/src/gvn.rs | 12 +----------- tests/mir-opt/const_array_locals.main.GVN.diff | 8 +++----- tests/mir-opt/const_array_locals.rs | 2 +- 3 files changed, 5 insertions(+), 17 deletions(-) diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index 0c3adfa9859bd..b5ebc1361dfed 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -1539,17 +1539,7 @@ impl<'tcx> MutVisitor<'tcx> for VnState<'_, 'tcx> { .or_else(|| self.simplify_rvalue(rvalue, location)); let Some(value) = value else { return }; - // De-duplicate locals has the same arrays assigned to prevent code bloat. - let disallowed_duplicated_array = if rvalue.ty(self.local_decls, self.tcx).is_array() - && let Some(locals) = self.rev_locals.get(value).as_deref() - && let [first, ..] = locals[..] - { - first != lhs.local - } else { - false - }; - - if !disallowed_duplicated_array && let Some(const_) = self.try_as_constant(value) { + if let Some(const_) = self.try_as_constant(value) { *rvalue = Rvalue::Use(Operand::Constant(Box::new(const_))); } else if let Some(local) = self.try_as_local(value, location) && *rvalue != Rvalue::Use(Operand::Move(local.into())) diff --git a/tests/mir-opt/const_array_locals.main.GVN.diff b/tests/mir-opt/const_array_locals.main.GVN.diff index 6dcb2974b0481..033db020f8276 100644 --- a/tests/mir-opt/const_array_locals.main.GVN.diff +++ b/tests/mir-opt/const_array_locals.main.GVN.diff @@ -37,13 +37,12 @@ } bb0: { -- StorageLive(_1); + StorageLive(_1); - _1 = [const 255_i32, const 105_i32, const 15_i32, const 39_i32, const 62_i32]; -+ nop; + _1 = const [255_i32, 105_i32, 15_i32, 39_i32, 62_i32]; StorageLive(_2); - _2 = [const 255_i32, const 105_i32, const 15_i32, const 39_i32, const 62_i32]; -+ _2 = _1; ++ _2 = const [255_i32, 105_i32, 15_i32, 39_i32, 62_i32]; StorageLive(_3); StorageLive(_4); - _4 = [const 178_i32, const 9_i32, const 4_i32, const 56_i32, const 221_i32]; @@ -94,8 +93,7 @@ StorageDead(_6); StorageDead(_3); StorageDead(_2); -- StorageDead(_1); -+ nop; + StorageDead(_1); return; } + } diff --git a/tests/mir-opt/const_array_locals.rs b/tests/mir-opt/const_array_locals.rs index 9871b7ff1d484..d8443a21c324f 100644 --- a/tests/mir-opt/const_array_locals.rs +++ b/tests/mir-opt/const_array_locals.rs @@ -14,7 +14,7 @@ struct F32x8([f32; 8]); pub fn main() { // CHECK: [[_arr]] = const [255_i32, 105_i32, 15_i32, 39_i32, 62_i32]; let _arr = [255, 105, 15, 39, 62]; - // CHECK: [[_duplicated_arr]] = [[_arr]]; + // CHECK: [[_duplicated_arr]] = const [255_i32, 105_i32, 15_i32, 39_i32, 62_i32]; let _duplicated_arr = [255, 105, 15, 39, 62]; // CHECK: [[subarray1:_[0-9]+]] = const [178_i32, 9_i32, 4_i32, 56_i32, 221_i32]; // CHECK: [[subarray2:_[0-9]+]] = const [193_i32, 164_i32, 194_i32, 197_i32, 6_i32]; From 604a3384fca6698e5768cd1b5df81aa57f3ce4fc Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Sun, 14 Jul 2024 05:30:50 +0000 Subject: [PATCH 28/32] gvn: const promote arrays of any sizes --- compiler/rustc_mir_transform/src/gvn.rs | 9 ---- .../mir-opt/const_array_locals.main.GVN.diff | 47 ++++++++----------- tests/mir-opt/const_array_locals.rs | 7 +-- ...ray_index.main.GVN.32bit.panic-unwind.diff | 5 +- ...ray_index.main.GVN.64bit.panic-unwind.diff | 5 +- tests/mir-opt/const_prop/array_index.rs | 1 + 6 files changed, 32 insertions(+), 42 deletions(-) diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index b5ebc1361dfed..e05063a948f2b 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -366,12 +366,6 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { #[instrument(level = "trace", skip(self), ret)] fn eval_to_const(&mut self, value: VnIndex) -> Option> { use Value::*; - // LLVM optimizes the load of `sizeof(size_t) * 2` as a single `mov`, - // which is cheap. Bigger values make more `mov` instructions generated. - // After GVN, it became a single load (`lea`) of an address in `.rodata`. - // But to avoid blessing differences between 32-bit and 64-bit target, - // let's choose `size_t = u64`. - const STACK_THRESHOLD: u64 = std::mem::size_of::() as u64 * 2; let op = match *self.get(value) { Opaque(_) => return None, // Do not bother evaluating repeat expressions. This would uselessly consume memory. @@ -423,9 +417,6 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { let ptr_imm = Immediate::new_pointer_with_meta(data, meta, &self.ecx); ImmTy::from_immediate(ptr_imm, ty).into() } else if matches!(kind, AggregateTy::Array) { - if ty.layout.size().bytes() <= STACK_THRESHOLD { - return None; - } let dest = self.ecx.allocate(ty, MemoryKind::Stack).ok()?; // FIXME: Can we speed it up by using `ecx.write_immediate(.ScalarPair(_), dest)`? for (field_index, op) in fields.iter().copied().enumerate() { diff --git a/tests/mir-opt/const_array_locals.main.GVN.diff b/tests/mir-opt/const_array_locals.main.GVN.diff index 033db020f8276..cb88116f1fb25 100644 --- a/tests/mir-opt/const_array_locals.main.GVN.diff +++ b/tests/mir-opt/const_array_locals.main.GVN.diff @@ -78,11 +78,14 @@ StorageDead(_12); StorageLive(_13); StorageLive(_14); - _14 = [const 1_i32, const 0_i32, const 0_i32]; +- _14 = [const 1_i32, const 0_i32, const 0_i32]; ++ _14 = const [1_i32, 0_i32, 0_i32]; StorageLive(_15); - _15 = [const 0_i32, const 1_i32, const 0_i32]; +- _15 = [const 0_i32, const 1_i32, const 0_i32]; ++ _15 = const [0_i32, 1_i32, 0_i32]; StorageLive(_16); - _16 = [const 0_i32, const 0_i32, const 1_i32]; +- _16 = [const 0_i32, const 0_i32, const 1_i32]; ++ _16 = const [0_i32, 0_i32, 1_i32]; _13 = [move _14, move _15, move _16]; StorageDead(_16); StorageDead(_15); @@ -96,35 +99,23 @@ StorageDead(_1); return; } -+ } + } + -+ ALLOC0 (size: 32, align: 4) { -+ 0x00 │ 00 00 80 3f 00 00 00 40 00 00 40 40 00 00 80 3f │ ...?...@..@@...? -+ 0x10 │ 00 00 80 3f 00 00 80 3f 00 00 80 3f 00 00 28 42 │ ...?...?...?..(B -+ } ++ ALLOC0 (size: 12, align: 4) { .. } + -+ ALLOC1 (size: 20, align: 4) { -+ 0x00 │ 1f 00 00 00 60 00 00 00 ad 00 00 00 32 00 00 00 │ ....`.......2... -+ 0x10 │ 01 00 00 00 │ .... -+ } ++ ALLOC1 (size: 12, align: 4) { .. } + -+ ALLOC2 (size: 20, align: 4) { -+ 0x00 │ c1 00 00 00 a4 00 00 00 c2 00 00 00 c5 00 00 00 │ ................ -+ 0x10 │ 06 00 00 00 │ .... -+ } ++ ALLOC2 (size: 12, align: 4) { .. } + -+ ALLOC3 (size: 20, align: 4) { -+ 0x00 │ b2 00 00 00 09 00 00 00 04 00 00 00 38 00 00 00 │ ............8... -+ 0x10 │ dd 00 00 00 │ .... -+ } ++ ALLOC3 (size: 32, align: 4) { .. } + -+ ALLOC4 (size: 20, align: 4) { -+ 0x00 │ ff 00 00 00 69 00 00 00 0f 00 00 00 27 00 00 00 │ ....i.......'... -+ 0x10 │ 3e 00 00 00 │ >... -+ } ++ ALLOC4 (size: 20, align: 4) { .. } + -+ ALLOC5 (size: 20, align: 4) { -+ 0x00 │ fe 00 00 00 2a 00 00 00 0f 00 00 00 27 00 00 00 │ ....*.......'... -+ 0x10 │ 3e 00 00 00 │ >... - } ++ ALLOC5 (size: 20, align: 4) { .. } ++ ++ ALLOC6 (size: 20, align: 4) { .. } ++ ++ ALLOC7 (size: 20, align: 4) { .. } ++ ++ ALLOC8 (size: 20, align: 4) { .. } diff --git a/tests/mir-opt/const_array_locals.rs b/tests/mir-opt/const_array_locals.rs index d8443a21c324f..9041f759793a2 100644 --- a/tests/mir-opt/const_array_locals.rs +++ b/tests/mir-opt/const_array_locals.rs @@ -1,4 +1,5 @@ //@ test-mir-pass: GVN +//@ compile-flags: -Zdump-mir-exclude-alloc-bytes #![feature(repr_simd)] #[repr(simd)] @@ -33,9 +34,9 @@ pub fn main() { let _f = F32x8([1.0, 2.0, 3.0, 1.0, 1.0, 1.0, 1.0, 42.0]); // ice with small arrays - // CHECK: [[A:_[0-9]+]] = [const 1_i32, const 0_i32, const 0_i32]; - // CHECK: [[B:_[0-9]+]] = [const 0_i32, const 1_i32, const 0_i32]; - // CHECK: [[C:_[0-9]+]] = [const 0_i32, const 0_i32, const 1_i32]; + // CHECK: [[A:_[0-9]+]] = const [1_i32, 0_i32, 0_i32]; + // CHECK: [[B:_[0-9]+]] = const [0_i32, 1_i32, 0_i32]; + // CHECK: [[C:_[0-9]+]] = const [0_i32, 0_i32, 1_i32]; // CHECK: {{_[0-9]+}} = [move [[A]], move [[B]], move [[C]]]; [[1, 0, 0], [0, 1, 0], [0, 0, 1]]; // 2D array } diff --git a/tests/mir-opt/const_prop/array_index.main.GVN.32bit.panic-unwind.diff b/tests/mir-opt/const_prop/array_index.main.GVN.32bit.panic-unwind.diff index 7e2f72ab31bce..982c6caee2f57 100644 --- a/tests/mir-opt/const_prop/array_index.main.GVN.32bit.panic-unwind.diff +++ b/tests/mir-opt/const_prop/array_index.main.GVN.32bit.panic-unwind.diff @@ -15,7 +15,8 @@ bb0: { StorageLive(_1); StorageLive(_2); - _2 = [const 0_u32, const 1_u32, const 2_u32, const 3_u32]; +- _2 = [const 0_u32, const 1_u32, const 2_u32, const 3_u32]; ++ _2 = const [0_u32, 1_u32, 2_u32, 3_u32]; StorageLive(_3); _3 = const 2_usize; - _4 = Len(_2); @@ -36,4 +37,6 @@ return; } } ++ ++ ALLOC0 (size: 16, align: 4) { .. } diff --git a/tests/mir-opt/const_prop/array_index.main.GVN.64bit.panic-unwind.diff b/tests/mir-opt/const_prop/array_index.main.GVN.64bit.panic-unwind.diff index 7e2f72ab31bce..982c6caee2f57 100644 --- a/tests/mir-opt/const_prop/array_index.main.GVN.64bit.panic-unwind.diff +++ b/tests/mir-opt/const_prop/array_index.main.GVN.64bit.panic-unwind.diff @@ -15,7 +15,8 @@ bb0: { StorageLive(_1); StorageLive(_2); - _2 = [const 0_u32, const 1_u32, const 2_u32, const 3_u32]; +- _2 = [const 0_u32, const 1_u32, const 2_u32, const 3_u32]; ++ _2 = const [0_u32, 1_u32, 2_u32, 3_u32]; StorageLive(_3); _3 = const 2_usize; - _4 = Len(_2); @@ -36,4 +37,6 @@ return; } } ++ ++ ALLOC0 (size: 16, align: 4) { .. } diff --git a/tests/mir-opt/const_prop/array_index.rs b/tests/mir-opt/const_prop/array_index.rs index aff72268223b2..99aaf22dca9dd 100644 --- a/tests/mir-opt/const_prop/array_index.rs +++ b/tests/mir-opt/const_prop/array_index.rs @@ -1,4 +1,5 @@ //@ test-mir-pass: GVN +//@ compile-flags: -Zdump-mir-exclude-alloc-bytes // EMIT_MIR_FOR_EACH_PANIC_STRATEGY // EMIT_MIR_FOR_EACH_BIT_WIDTH From 3abc3219556bbab6165d885b98546ce61ba4b419 Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Sun, 14 Jul 2024 05:43:03 +0000 Subject: [PATCH 29/32] gnv: Merge array and scalar branch together --- compiler/rustc_mir_transform/src/gvn.rs | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index e05063a948f2b..77f91645bfb65 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -416,16 +416,9 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { }; let ptr_imm = Immediate::new_pointer_with_meta(data, meta, &self.ecx); ImmTy::from_immediate(ptr_imm, ty).into() - } else if matches!(kind, AggregateTy::Array) { - let dest = self.ecx.allocate(ty, MemoryKind::Stack).ok()?; - // FIXME: Can we speed it up by using `ecx.write_immediate(.ScalarPair(_), dest)`? - for (field_index, op) in fields.iter().copied().enumerate() { - let field_dest = self.ecx.project_field(&dest, field_index).ok()?; - self.ecx.copy_op(op, &field_dest).ok()?; - } - let dest = dest.map_provenance(|prov| prov.as_immutable()); - dest.into() - } else if matches!(ty.abi, Abi::Scalar(..) | Abi::ScalarPair(..)) { + } else if matches!(kind, AggregateTy::Array) + || matches!(ty.abi, Abi::Scalar(..) | Abi::ScalarPair(..)) + { let dest = self.ecx.allocate(ty, MemoryKind::Stack).ok()?; let variant_dest = if let Some(variant) = variant { self.ecx.project_downcast(&dest, variant).ok()? @@ -437,9 +430,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { self.ecx.copy_op(op, &field_dest).ok()?; } self.ecx.write_discriminant(variant.unwrap_or(FIRST_VARIANT), &dest).ok()?; - self.ecx - .alloc_mark_immutable(dest.ptr().provenance.unwrap().alloc_id()) - .ok()?; + let dest = dest.map_provenance(|prov| prov.as_immutable()); dest.into() } else { return None; From 86727000128ec5c3ec6e41425141e7fd2933ff64 Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Sun, 14 Jul 2024 05:56:33 +0000 Subject: [PATCH 30/32] Remove redundant nested array checks Already checked by 8093f11f0c7 - ignore arrays in operands --- compiler/rustc_mir_transform/src/gvn.rs | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index 77f91645bfb65..22efae6d2c231 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -383,15 +383,6 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { AggregateTy::Array => { assert!(fields.len() > 0); let field_ty = fields[0].layout.ty; - // FIXME: Ignore nested arrays, because arrays is large. Nested arrays are rarer and bigger - // while we already process 1-dimension arrays, which is enough? - if field_ty.is_array() { - trace!( - "ignoring nested array of type: [{field_ty}; {len}]", - len = fields.len(), - ); - return None; - } Ty::new_array(self.tcx, field_ty, fields.len() as u64) } AggregateTy::Tuple => { @@ -899,13 +890,8 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { } let (mut ty, variant_index) = match *kind { - AggregateKind::Array(ty) => { + AggregateKind::Array(_) => { assert!(!field_ops.is_empty()); - // FIXME: Ignore nested arrays, because arrays is large. Nested arrays are rarer and bigger - // while we already process 1-dimension arrays, which is enough? - if ty.is_array() { - return None; - } (AggregateTy::Array, FIRST_VARIANT) } AggregateKind::Tuple => { From a275a8ffa20645eae5f3d09d07c0c974c3bba536 Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Sun, 14 Jul 2024 14:03:38 +0000 Subject: [PATCH 31/32] gvn: Allow evaluating rvalue operands This reverts 8093f11f0c7. This makes nested arrays and operands evaluable to const. --- compiler/rustc_mir_transform/src/gvn.rs | 5 ---- .../mir-opt/const_array_locals.main.GVN.diff | 24 ++++++++++++------- tests/mir-opt/const_array_locals.rs | 8 +++---- 3 files changed, 20 insertions(+), 17 deletions(-) diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index 22efae6d2c231..83792e64d537c 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -778,11 +778,6 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { } Operand::Copy(ref mut place) | Operand::Move(ref mut place) => { let value = self.simplify_place_value(place, location)?; - // NOTE(tesuji): We just want to promote rvalues of array kind that assigned to a local, and - // not evaluate this local as a const operand of a function to avoid bloating MIR. - if let Value::Aggregate(AggregateTy::Array, ..) = self.get(value) { - return None; - } if let Some(const_) = self.try_as_constant(value) { *operand = Operand::Constant(Box::new(const_)); } diff --git a/tests/mir-opt/const_array_locals.main.GVN.diff b/tests/mir-opt/const_array_locals.main.GVN.diff index cb88116f1fb25..8095ff8124c73 100644 --- a/tests/mir-opt/const_array_locals.main.GVN.diff +++ b/tests/mir-opt/const_array_locals.main.GVN.diff @@ -49,8 +49,9 @@ + _4 = const [178_i32, 9_i32, 4_i32, 56_i32, 221_i32]; StorageLive(_5); - _5 = [const 193_i32, const 164_i32, const 194_i32, const 197_i32, const 6_i32]; +- _3 = [move _4, move _5]; + _5 = const [193_i32, 164_i32, 194_i32, 197_i32, 6_i32]; - _3 = [move _4, move _5]; ++ _3 = const [[178_i32, 9_i32, 4_i32, 56_i32, 221_i32], [193_i32, 164_i32, 194_i32, 197_i32, 6_i32]]; StorageDead(_5); StorageDead(_4); StorageLive(_6); @@ -63,8 +64,9 @@ StorageLive(_9); StorageLive(_10); - _10 = [const 31_u32, const 96_u32, const 173_u32, const 50_u32, const 1_u32]; +- _9 = consume(move _10) -> [return: bb1, unwind continue]; + _10 = const [31_u32, 96_u32, 173_u32, 50_u32, 1_u32]; - _9 = consume(move _10) -> [return: bb1, unwind continue]; ++ _9 = consume(const [31_u32, 96_u32, 173_u32, 50_u32, 1_u32]) -> [return: bb1, unwind continue]; } bb1: { @@ -73,8 +75,9 @@ StorageLive(_11); StorageLive(_12); - _12 = [const 1f32, const 2f32, const 3f32, const 1f32, const 1f32, const 1f32, const 1f32, const 42f32]; +- _11 = F32x8(move _12); + _12 = const [1f32, 2f32, 3f32, 1f32, 1f32, 1f32, 1f32, 42f32]; - _11 = F32x8(move _12); ++ _11 = F32x8(const [1f32, 2f32, 3f32, 1f32, 1f32, 1f32, 1f32, 42f32]); StorageDead(_12); StorageLive(_13); StorageLive(_14); @@ -85,8 +88,9 @@ + _15 = const [0_i32, 1_i32, 0_i32]; StorageLive(_16); - _16 = [const 0_i32, const 0_i32, const 1_i32]; +- _13 = [move _14, move _15, move _16]; + _16 = const [0_i32, 0_i32, 1_i32]; - _13 = [move _14, move _15, move _16]; ++ _13 = const [[1_i32, 0_i32, 0_i32], [0_i32, 1_i32, 0_i32], [0_i32, 0_i32, 1_i32]]; StorageDead(_16); StorageDead(_15); StorageDead(_14); @@ -101,21 +105,25 @@ } } + -+ ALLOC0 (size: 12, align: 4) { .. } ++ ALLOC0 (size: 36, align: 4) { .. } + + ALLOC1 (size: 12, align: 4) { .. } + + ALLOC2 (size: 12, align: 4) { .. } + -+ ALLOC3 (size: 32, align: 4) { .. } ++ ALLOC3 (size: 12, align: 4) { .. } + -+ ALLOC4 (size: 20, align: 4) { .. } ++ ALLOC4 (size: 32, align: 4) { .. } + + ALLOC5 (size: 20, align: 4) { .. } + -+ ALLOC6 (size: 20, align: 4) { .. } ++ ALLOC6 (size: 40, align: 4) { .. } + + ALLOC7 (size: 20, align: 4) { .. } + + ALLOC8 (size: 20, align: 4) { .. } ++ ++ ALLOC9 (size: 20, align: 4) { .. } ++ ++ ALLOC10 (size: 20, align: 4) { .. } diff --git a/tests/mir-opt/const_array_locals.rs b/tests/mir-opt/const_array_locals.rs index 9041f759793a2..5f17e58b8fc91 100644 --- a/tests/mir-opt/const_array_locals.rs +++ b/tests/mir-opt/const_array_locals.rs @@ -19,25 +19,25 @@ pub fn main() { let _duplicated_arr = [255, 105, 15, 39, 62]; // CHECK: [[subarray1:_[0-9]+]] = const [178_i32, 9_i32, 4_i32, 56_i32, 221_i32]; // CHECK: [[subarray2:_[0-9]+]] = const [193_i32, 164_i32, 194_i32, 197_i32, 6_i32]; - // CHECK: [[_foo]] = [move [[subarray1]], move [[subarray2]]]; + // CHECK{LITERAL}: const [[178_i32, 9_i32, 4_i32, 56_i32, 221_i32], [193_i32, 164_i32, 194_i32, 197_i32, 6_i32]]; let _foo = [[178, 9, 4, 56, 221], [193, 164, 194, 197, 6]]; // CHECK: [[PROMOTED:_[0-9]+]] = const main::promoted[0]; // CHECK: [[_darr]] = const [254_i32, 42_i32, 15_i32, 39_i32, 62_i32]; let _darr = *&[254, 42, 15, 39, 62]; // CHECK: [[ARG:_[0-9]+]] = const [31_u32, 96_u32, 173_u32, 50_u32, 1_u32]; - // CHECK: consume(move [[ARG]]) + // CHECK: consume(const [31_u32, 96_u32, 173_u32, 50_u32, 1_u32]) consume([31, 96, 173, 50, 1]); // CHECK: [[OP:_[0-9]+]] = const [1f32, 2f32, 3f32, 1f32, 1f32, 1f32, 1f32, 42f32]; - // CHECK: [[_f]] = F32x8(move [[OP]]); + // CHECK: [[_f]] = F32x8(const [1f32, 2f32, 3f32, 1f32, 1f32, 1f32, 1f32, 42f32]); let _f = F32x8([1.0, 2.0, 3.0, 1.0, 1.0, 1.0, 1.0, 42.0]); // ice with small arrays // CHECK: [[A:_[0-9]+]] = const [1_i32, 0_i32, 0_i32]; // CHECK: [[B:_[0-9]+]] = const [0_i32, 1_i32, 0_i32]; // CHECK: [[C:_[0-9]+]] = const [0_i32, 0_i32, 1_i32]; - // CHECK: {{_[0-9]+}} = [move [[A]], move [[B]], move [[C]]]; + // CHECK{LITERAL}: const [[1_i32, 0_i32, 0_i32], [0_i32, 1_i32, 0_i32], [0_i32, 0_i32, 1_i32]]; [[1, 0, 0], [0, 1, 0], [0, 0, 1]]; // 2D array } From c15eb60be0d21e978da111c52e7678bd9a84f79e Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Sun, 14 Jul 2024 14:21:33 +0000 Subject: [PATCH 32/32] do not merge(perf): reduce llvm stress by not make llvm de-duplicates arrays between promote temp pass and gvn. --- compiler/rustc_mir_transform/src/gvn.rs | 9 +++++++++ tests/mir-opt/const_array_locals.main.GVN.diff | 4 +--- tests/mir-opt/const_array_locals.rs | 2 +- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index 83792e64d537c..1f0458baa1ec8 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -1451,6 +1451,15 @@ impl<'tcx> VnState<'_, 'tcx> { let op = self.evaluated[index].as_ref()?; + // Ignore promoted arrays. Promoted arrays are already placed in `.rodata`. + // Which is what we try to archive for running gvn on constant local arrays. + if let Either::Left(mplace) = op.as_mplace_or_imm() + && mplace.layout.ty.is_array() + && let Value::Projection(_index, ProjectionElem::Deref) = self.get(index) + { + return None; + } + let value = op_to_prop_const(&mut self.ecx, op)?; // Check that we do not leak a pointer. diff --git a/tests/mir-opt/const_array_locals.main.GVN.diff b/tests/mir-opt/const_array_locals.main.GVN.diff index 8095ff8124c73..6ca40fb42983d 100644 --- a/tests/mir-opt/const_array_locals.main.GVN.diff +++ b/tests/mir-opt/const_array_locals.main.GVN.diff @@ -59,7 +59,7 @@ _17 = const main::promoted[0]; _7 = &(*_17); - _6 = (*_7); -+ _6 = const [254_i32, 42_i32, 15_i32, 39_i32, 62_i32]; ++ _6 = (*_17); StorageDead(_7); StorageLive(_9); StorageLive(_10); @@ -124,6 +124,4 @@ + ALLOC8 (size: 20, align: 4) { .. } + + ALLOC9 (size: 20, align: 4) { .. } -+ -+ ALLOC10 (size: 20, align: 4) { .. } diff --git a/tests/mir-opt/const_array_locals.rs b/tests/mir-opt/const_array_locals.rs index 5f17e58b8fc91..df28894ead49c 100644 --- a/tests/mir-opt/const_array_locals.rs +++ b/tests/mir-opt/const_array_locals.rs @@ -22,7 +22,7 @@ pub fn main() { // CHECK{LITERAL}: const [[178_i32, 9_i32, 4_i32, 56_i32, 221_i32], [193_i32, 164_i32, 194_i32, 197_i32, 6_i32]]; let _foo = [[178, 9, 4, 56, 221], [193, 164, 194, 197, 6]]; // CHECK: [[PROMOTED:_[0-9]+]] = const main::promoted[0]; - // CHECK: [[_darr]] = const [254_i32, 42_i32, 15_i32, 39_i32, 62_i32]; + // CHECK: [[_darr]] = (*[[PROMOTED]]); let _darr = *&[254, 42, 15, 39, 62]; // CHECK: [[ARG:_[0-9]+]] = const [31_u32, 96_u32, 173_u32, 50_u32, 1_u32];