Repository: rust
Issue: Vec of 2D or 3D arrays generates very slow code
Labels: I-slow,C-bug,A-array

Using fixed sized arrays is very useful because the back-end knows their length, and this allows some significant optimizations.

But allocating large ones is a problem, here I'm using a solution that's generally good enough (it's more efficient than using the "box" keyword), based on vec! + into_boxed_slice + try_into. This solution breaks when you have 2D+ arrays:

```rust
const L1: usize = 100_000;
const L2: usize = 200;

pub struct Foo {
    m1: Box<[[u32; 50]; L1]>,
    t1: Box<[[[f64; L2]; L1]; 2]>,
}

impl Foo {
    pub fn new() -> Self {
        Self {
            m1: vec![[0; 50]; L1].into_boxed_slice().try_into().unwrap(),
            t1: vec![[[0.0; L2]; L1]; 2].into_boxed_slice().try_into().unwrap(),
        }
    }
}
```

Gives the unreasonable and very slow asm with copies:

```asm
example::Foo::new:
        push    r15
        push    r14
        push    r12
        push    rbx
        mov     eax, 160000008
        call    __rust_probestack
        sub     rsp, rax
        mov     edi, 20000000
        mov     esi, 4
        call    qword ptr [rip + __rust_alloc@GOTPCREL]
        test    rax, rax
        je      .LBB0_7
        mov     r14, rax
        xor     eax, eax
        vxorps  xmm0, xmm0, xmm0
.LBB0_2:
        vmovups ymmword ptr [r14 + rax + 160], ymm0
        vmovups ymmword ptr [r14 + rax + 128], ymm0
        vmovups ymmword ptr [r14 + rax + 96], ymm0
        vmovups ymmword ptr [r14 + rax + 64], ymm0
        vmovups ymmword ptr [r14 + rax + 32], ymm0
        vmovups ymmword ptr [r14 + rax], ymm0
        mov     qword ptr [r14 + rax + 192], 0
        vmovups ymmword ptr [r14 + rax + 200], ymm0
        vmovups ymmword ptr [r14 + rax + 232], ymm0
        vmovups ymmword ptr [r14 + rax + 264], ymm0
        vmovups ymmword ptr [r14 + rax + 296], ymm0
        vmovups ymmword ptr [r14 + rax + 328], ymm0
        vmovups ymmword ptr [r14 + rax + 360], ymm0
        mov     qword ptr [r14 + rax + 392], 0
        vmovups ymmword ptr [r14 + rax + 400], ymm0
        vmovups ymmword ptr [r14 + rax + 432], ymm0
        vmovups ymmword ptr [r14 + rax + 464], ymm0
        vmovups ymmword ptr [r14 + rax + 496], ymm0
        vmovups ymmword ptr [r14 + rax + 528], ymm0
        vmovups ymmword ptr [r14 + rax + 560], ymm0
        mov     qword ptr [r14 + rax + 592], 0
        vmovups ymmword ptr [r14 + rax + 760], ymm0
        vmovups ymmword ptr [r14 + rax + 728], ymm0
        vmovups ymmword ptr [r14 + rax + 696], ymm0
        vmovups ymmword ptr [r14 + rax + 664], ymm0
        vmovups ymmword ptr [r14 + rax + 632], ymm0
        vmovups ymmword ptr [r14 + rax + 600], ymm0
        mov     qword ptr [r14 + rax + 792], 0
        vmovups ymmword ptr [r14 + rax + 800], ymm0
        vmovups ymmword ptr [r14 + rax + 832], ymm0
        vmovups ymmword ptr [r14 + rax + 864], ymm0
        vmovups ymmword ptr [r14 + rax + 896], ymm0
        vmovups ymmword ptr [r14 + rax + 928], ymm0
        vmovups ymmword ptr [r14 + rax + 960], ymm0
        mov     qword ptr [r14 + rax + 992], 0
        vmovups ymmword ptr [r14 + rax + 1000], ymm0
        vmovups ymmword ptr [r14 + rax + 1032], ymm0
        vmovups ymmword ptr [r14 + rax + 1064], ymm0
        vmovups ymmword ptr [r14 + rax + 1096], ymm0
        vmovups ymmword ptr [r14 + rax + 1128], ymm0
        vmovups ymmword ptr [r14 + rax + 1160], ymm0
        mov     qword ptr [r14 + rax + 1192], 0
        vmovups ymmword ptr [r14 + rax + 1360], ymm0
        vmovups ymmword ptr [r14 + rax + 1328], ymm0
        vmovups ymmword ptr [r14 + rax + 1296], ymm0
        vmovups ymmword ptr [r14 + rax + 1264], ymm0
        vmovups ymmword ptr [r14 + rax + 1232], ymm0
        vmovups ymmword ptr [r14 + rax + 1200], ymm0
        mov     qword ptr [r14 + rax + 1392], 0
        vmovups ymmword ptr [r14 + rax + 1560], ymm0
        vmovups ymmword ptr [r14 + rax + 1528], ymm0
        vmovups ymmword ptr [r14 + rax + 1496], ymm0
        vmovups ymmword ptr [r14 + rax + 1464], ymm0
        vmovups ymmword ptr [r14 + rax + 1432], ymm0
        vmovups ymmword ptr [r14 + rax + 1400], ymm0
        mov     qword ptr [r14 + rax + 1592], 0
        vmovups ymmword ptr [r14 + rax + 1760], ymm0
        vmovups ymmword ptr [r14 + rax + 1728], ymm0
        vmovups ymmword ptr [r14 + rax + 1696], ymm0
        vmovups ymmword ptr [r14 + rax + 1664], ymm0
        vmovups ymmword ptr [r14 + rax + 1632], ymm0
        vmovups ymmword ptr [r14 + rax + 1600], ymm0
        mov     qword ptr [r14 + rax + 1792], 0
        add     rax, 1800
        cmp     rax, 19999800
        jne     .LBB0_2
        vxorps  xmm0, xmm0, xmm0
        vmovups ymmword ptr [r14 + rax + 160], ymm0
        vmovups ymmword ptr [r14 + rax + 128], ymm0
        vmovups ymmword ptr [r14 + rax + 96], ymm0
        vmovups ymmword ptr [r14 + rax + 64], ymm0
        vmovups ymmword ptr [r14 + rax + 32], ymm0
        vmovups ymmword ptr [r14 + rax], ymm0
        mov     qword ptr [r14 + rax + 192], 0
        lea     rbx, [rsp + 8]
        lea     r15, [rsp + 160000008]
        mov     r12, qword ptr [rip + memset@GOTPCREL]
.LBB0_4:
        mov     edx, 1600
        mov     rdi, rbx
        xor     esi, esi
        vzeroupper
        call    r12
        lea     rdi, [rbx + 1600]
        mov     edx, 1600
        xor     esi, esi
        call    r12
        lea     rdi, [rbx + 3200]
        mov     edx, 1600
        xor     esi, esi
        call    r12
        lea     rdi, [rbx + 4800]
        mov     edx, 1600
        xor     esi, esi
        call    r12
        lea     rdi, [rbx + 6400]
        mov     edx, 1600
        xor     esi, esi
        call    r12
        lea     rdi, [rbx + 8000]
        mov     edx, 1600
        xor     esi, esi
        call    r12
        lea     rdi, [rbx + 9600]
        mov     edx, 1600
        xor     esi, esi
        call    r12
        lea     rdi, [rbx + 11200]
        mov     edx, 1600
        xor     esi, esi
        call    r12
        lea     rdi, [rbx + 12800]
        mov     edx, 1600
        xor     esi, esi
        call    r12
        lea     rdi, [rbx + 14400]
        mov     edx, 1600
        xor     esi, esi
        call    r12
        lea     rdi, [rbx + 16000]
        mov     edx, 1600
        xor     esi, esi
        call    r12
        lea     rdi, [rbx + 17600]
        mov     edx, 1600
        xor     esi, esi
        call    r12
        lea     rdi, [rbx + 19200]
        mov     edx, 1600
        xor     esi, esi
        call    r12
        lea     rdi, [rbx + 20800]
        mov     edx, 1600
        xor     esi, esi
        call    r12
        lea     rdi, [rbx + 22400]
        mov     edx, 1600
        xor     esi, esi
        call    r12
        lea     rdi, [rbx + 24000]
        mov     edx, 1600
        xor     esi, esi
        call    r12
        lea     rdi, [rbx + 25600]
        mov     edx, 1600
        xor     esi, esi
        call    r12
        lea     rdi, [rbx + 27200]
        mov     edx, 1600
        xor     esi, esi
        call    r12
        lea     rdi, [rbx + 28800]
        mov     edx, 1600
        xor     esi, esi
        call    r12
        lea     rdi, [rbx + 30400]
        mov     edx, 1600
        xor     esi, esi
        call    r12
        lea     rdi, [rbx + 32000]
        mov     edx, 1600
        xor     esi, esi
        call    r12
        lea     rdi, [rbx + 33600]
        mov     edx, 1600
        xor     esi, esi
        call    r12
        lea     rdi, [rbx + 35200]
        mov     edx, 1600
        xor     esi, esi
        call    r12
        lea     rdi, [rbx + 36800]
        mov     edx, 1600
        xor     esi, esi
        call    r12
        lea     rdi, [rbx + 38400]
        mov     edx, 1600
        xor     esi, esi
        call    r12
        lea     rdi, [rbx + 40000]
        mov     edx, 1600
        xor     esi, esi
        call    r12
        lea     rdi, [rbx + 41600]
        mov     edx, 1600
        xor     esi, esi
        call    r12
        lea     rdi, [rbx + 43200]
        mov     edx, 1600
        xor     esi, esi
        call    r12
        lea     rdi, [rbx + 44800]
        mov     edx, 1600
        xor     esi, esi
        call    r12
        lea     rdi, [rbx + 46400]
        mov     edx, 1600
        xor     esi, esi
        call    r12
        lea     rdi, [rbx + 48000]
        mov     edx, 1600
        xor     esi, esi
        call    r12
        lea     rdi, [rbx + 49600]
        mov     edx, 1600
        xor     esi, esi
        call    r12
        lea     rdi, [rbx + 51200]
        mov     edx, 1600
        xor     esi, esi
        call    r12
        lea     rdi, [rbx + 52800]
        mov     edx, 1600
        xor     esi, esi
        call    r12
        lea     rdi, [rbx + 54400]
        mov     edx, 1600
        xor     esi, esi
        call    r12
        lea     rdi, [rbx + 56000]
        mov     edx, 1600
        xor     esi, esi
        call    r12
        lea     rdi, [rbx + 57600]
        mov     edx, 1600
        xor     esi, esi
        call    r12
        lea     rdi, [rbx + 59200]
        mov     edx, 1600
        xor     esi, esi
        call    r12
        lea     rdi, [rbx + 60800]
        mov     edx, 1600
        xor     esi, esi
        call    r12
        lea     rdi, [rbx + 62400]
        mov     edx, 1600
        xor     esi, esi
        call    r12
        add     rbx, 64000
        cmp     rbx, r15
        jne     .LBB0_4
        mov     edi, 320000000
        mov     esi, 8
        call    qword ptr [rip + __rust_alloc@GOTPCREL]
        test    rax, rax
        je      .LBB0_8
        mov     rbx, rax
        lea     r15, [rsp + 8]
        mov     r12, qword ptr [rip + memcpy@GOTPCREL]
        mov     edx, 160000000
        mov     rdi, rax
        mov     rsi, r15
        call    r12
        mov     rdi, rbx
        add     rdi, 160000000
        mov     edx, 160000000
        mov     rsi, r15
        call    r12
        mov     rax, r14
        mov     rdx, rbx
        add     rsp, 160000008
        pop     rbx
        pop     r12
        pop     r14
        pop     r15
        ret
.LBB0_7:
        mov     edi, 20000000
        mov     esi, 4
        call    qword ptr [rip + alloc::alloc::handle_alloc_error@GOTPCREL]
        ud2
.LBB0_8:
        mov     edi, 320000000
        mov     esi, 8
        call    qword ptr [rip + alloc::alloc::handle_alloc_error@GOTPCREL]
        ud2
```

I can regain some efficiency creating 1D boxed arrays and then transmuting them to 2D/3D, but it's error prone (even if I use a macro for this):


```rust
const L1: usize = 100_000;
const L2: usize = 200;

pub struct Foo {
    m1: Box<[[u32; 50]; L1]>,
    t1: Box<[[[f64; L2]; L1]; 2]>,
}

impl Foo {
    pub fn new() -> Self {
        use std::mem::transmute;

        let m1_data: Box<[u32; 50 * L1]> = vec![0; 50 * L1].into_boxed_slice().try_into().unwrap();
        let t1_data: Box<[f64; L2 * L1 * 2]> = vec![0.0; L2 * L1 * 2].into_boxed_slice().try_into().unwrap();

        Self {
            m1: unsafe { transmute(m1_data) },
            t1: unsafe { transmute(t1_data) },
        }
    }
}
```

It gives the reasonable asm:

```asm
example::Foo::new:
        push    rbx
        mov     edi, 20000000
        mov     esi, 4
        call    qword ptr [rip + __rust_alloc_zeroed@GOTPCREL]
        test    rax, rax
        je      .LBB0_3
        mov     rbx, rax
        mov     edi, 320000000
        mov     esi, 8
        call    qword ptr [rip + __rust_alloc_zeroed@GOTPCREL]
        test    rax, rax
        je      .LBB0_4
        mov     rdx, rax
        mov     rax, rbx
        pop     rbx
        ret
.LBB0_3:
        mov     edi, 20000000
        mov     esi, 4
        call    qword ptr [rip + alloc::alloc::handle_alloc_error@GOTPCREL]
        ud2
.LBB0_4:
        mov     edi, 320000000
        mov     esi, 8
        call    qword ptr [rip + alloc::alloc::handle_alloc_error@GOTPCREL]
        ud2
```