// vim: ft=arm

// C tile regs
// 
//      q8[0]    q10[0]   q12[0]    q14[0]
//      q8[1]    q10[1]   q12[1]    q14[1]
//      q8[2]    q10[2]   q12[2]    q14[2]
//      q8[3]    q10[3]   q12[3]    q14[3]
//
//      q9[0]    q11[0]   q13[0]    q15[0]
//      q9[1]    q11[1]   q13[1]    q15[1]
//      q9[2]    q11[2]   q13[2]    q15[2]
//      q9[3]    q11[3]   q13[3]    q15[3]

    .arm
    .text
    .global armv7neon_mmm_i32_8x4_{{suffix}}
    .type armv7neon_mmm_i32_8x4_{{suffix}}, %function

armv7neon_mmm_i32_8x4_{{suffix}}:

    pld     [r0]
    push    { r4-r12 }
    vpush   { q4-q7 }

{% include "dispatcher.tmpliq" %}

.add_mat_mul:
    cmp     r3, #0
    beq     .non_linear_loop

    mov     r1, r4 // packed A ptr
    pld     [r3]
    pld     [r5]

    .packed_packed:
    pld     [r5]                           // packed B ptr       

    cmp r3, #4
    blt .packed_packed_loop_1

    .packed_packed_loop_4:
    pld             [r1, #64]
    pld             [r5, #64]

    // q2: d4 -> d4,d5 A even cols (from r1)
    // q3: d6 -> d6,d7 A odd cols (from r1)
    // q0: s0 -> d0 : B even lines (from r5)
    // q1: s4 -> d2 : B odd lines (from r5)

    // 0
    vldmia          r1!, { d4 }
    vldmia          r5!, { s0 }

    vmovl.s8        q2, d4
    vmovl.s8        q0, d0

    vmlal.s16       q8, d4, d0[0]
    vmlal.s16       q9, d5, d0[0]

    vldmia          r1!, { d6 }

    vmlal.s16       q10, d4, d0[1]
    vmlal.s16       q11, d5, d0[1]

    vldmia          r5!, { s4 }

    vmlal.s16       q12, d4, d0[2]
    vmlal.s16       q13, d5, d0[2]

    vmlal.s16       q14, d4, d0[3]
    vmlal.s16       q15, d5, d0[3]

    // 1
    vmovl.s8        q3, d6
    vmovl.s8        q1, d2

    vmlal.s16       q8, d6, d2[0]
    vldmia          r1!, { d4 }
    vmlal.s16       q9, d7, d2[0]
    vldmia          r5!, { s0 }

    vmlal.s16       q10, d6, d2[1]
    vmlal.s16       q11, d7, d2[1]

    vmlal.s16       q12, d6, d2[2]
    vmlal.s16       q13, d7, d2[2]

    vmlal.s16       q14, d6, d2[3]
    vmlal.s16       q15, d7, d2[3]

    // 2
    vmovl.s8        q2, d4
    vmovl.s8        q0, d0

    vmlal.s16       q8, d4, d0[0]
    vmlal.s16       q9, d5, d0[0]

    vldmia          r1!, { d6 }

    vmlal.s16       q10, d4, d0[1]
    vmlal.s16       q11, d5, d0[1]

    vldmia          r5!, { s4 }

    vmlal.s16       q12, d4, d0[2]
    vmlal.s16       q13, d5, d0[2]

    vmlal.s16       q14, d4, d0[3]
    vmlal.s16       q15, d5, d0[3]

    // 3
    vmovl.s8        q3, d6
    vmovl.s8        q1, d2

    vmlal.s16       q8, d6, d2[0]
    vmlal.s16       q9, d7, d2[0]

    vmlal.s16       q10, d6, d2[1]
    vmlal.s16       q11, d7, d2[1]

    vmlal.s16       q12, d6, d2[2]
    vmlal.s16       q13, d7, d2[2]

    vmlal.s16       q14, d6, d2[3]
    vmlal.s16       q15, d7, d2[3]

    sub r3, r3, #4
    cmp r3, #4
    bge .packed_packed_loop_4

    cmp r3, #0
    beq .non_linear_loop

    .packed_packed_loop_1:

    vldmia          r1!, { s0, s1 }
    vmovl.s8        q0, d0
    vldmia          r5!, { s4 }
    vmovl.s8        q1, d2

    vmlal.s16       q8, d0, d2[0]
    vmlal.s16       q9, d1, d2[0]

    vmlal.s16       q10, d0, d2[1]
    vmlal.s16       q11, d1, d2[1]

    vmlal.s16       q12, d0, d2[2]
    vmlal.s16       q13, d1, d2[2]

    vmlal.s16       q14, d0, d2[3]
    vmlal.s16       q15, d1, d2[3]

    subs r3, r3, #1
    bne .packed_packed_loop_1
    b   .non_linear_loop

{% include "armv7neon_mmm_i32_scalars.tmpliq" from:8, to:15 %}
{% include "armv7neon_mmm_i32_per_rows.tmpliq" mr:8, from:8, to:15 %}
{% include "armv7neon_mmm_i32_per_cols.tmpliq" mr:8, from:8, to:15 %}

.add_unicast:
    // r3, r4, r5, r6 <- ptr, rsc, csc, size
    cmp     r6, #4
    beq     .non_linear_addc_i32

    {% for col in (0..3) %}
        mov         r8, r3
        {% for reg in (0..3) %}
            vld1.s8     d0[0], [ r8 ], r4
            vld1.s8     d0[1], [ r8 ], r4
            vmovl.s8    q0, d0
            vmovl.s16   q0, d0
            vadd.i32    d{{col | times: 4 | plus: reg | plus : 16}}, d0
        {% endfor %}
        add r3, r3, r5
    {% endfor %}

    b .non_linear_loop

.non_linear_addc_i32:

    {% for col in (0..3) %}
        mov         r8, r3
        {% for reg in (0..3) %}
            vld1.s32    d0[0], [ r8 ], r4
            vld1.s32    d0[1], [ r8 ], r4
            vadd.i32    d{{col | times: 4 | plus: reg | plus : 16}}, d0
        {% endfor %}
        {% if col < 3 %}
            add r3, r3, r5
        {% endif %}
    {% endfor %}

b .non_linear_loop

.add_row_col_products:
    vldmia          r3!, { q0, q1 }
    vldmia          r4!, { q4 }

    vmla.s32        q8, q0, d8[0]
    vmla.s32        q9, q1, d8[0]

    vmla.s32        q10, q0, d8[1]
    vmla.s32        q11, q1, d8[1]

    vmla.s32        q12, q0, d9[0]
    vmla.s32        q13, q1, d9[0]

    vmla.s32        q14, q0, d9[1]
    vmla.s32        q15, q1, d9[1]

    b .non_linear_loop

    {% include "armv7neon_mmm_i32_scale_q8_q15.tmpliq" %}

.store:
    // r3, r4, r5, r6 <- ptr, rsc, csc, size
    cmp     r6, #4
    beq     .store_strides_i32

    {% for reg in (8..15) %}
        vmovn.s32 d{{reg | times: 2}}, q{{reg}}
        vmovn.s16 d{{reg | times: 2}}, q{{reg}}
    {% endfor %}
    {% for col in (0..3) %}
        mov         r8, r3
        {% for reg in (0..1) %}
            {%capture d%}{{col | times: 2 | plus: reg | times: 2 | plus: 16}}{%endcapture%}
            vst1.s8     d{{d}}[0], [ r8 ], r4
            vst1.s8     d{{d}}[1], [ r8 ], r4
            vst1.s8     d{{d}}[2], [ r8 ], r4
            vst1.s8     d{{d}}[3], [ r8 ], r4
        {% endfor %}
        {% if col < 3 %}
            add r3, r3, r5
        {% endif %}
    {% endfor %}

    b .non_linear_loop

.store_strides_i32:

    {% for col in (0..3) %}
        mov         r8, r3
        {% for reg in (0..3) %}
            {% for lane in (0..1) %}
                vst1.s32     d{{col | times: 4 | plus: reg | plus: 16}}[{{lane}}], [ r8 ], r4
            {% endfor %}
        {% endfor %}
        {% if col < 3 %}
            add r3, r3, r5
        {% endif %}
    {% endfor %}

    b .non_linear_loop

.return:
    vpop        { q4-q7 }
    pop         { r4-r12 }

    bx          lr

