怎么把矩阵一列的连续四个元素装入一个NEON寄存器

由于C语言是行主序存储的,所以如果要把矩阵一行中的连续四个元素装入NEON寄存器很简单:

1
src1 = vld1q_f32(m_a[i] + k); // 将m_a第i行中从第k列开始的四个连续元素装入src1

那如果我想把矩阵m_bj列中从第k行开始的四个连续元素装入src2怎么写呢?

当然,用vsetq_lane_f32来写是可行的:

1
2
3
4
src2 = vsetq_lane_f32(m_b[k][j]src20);
src2 = vsetq_lane_f32(m_b[k + 1][j],src21);
src2 = vsetq_lane_f32(m_b[k + 2][j]src22);
src2 = vsetq_lane_f32(m_b[k + 3][j]src2,3);

或者写成一行:

1
src2 = vsetq_lane_f32(m_b[k][j], vsetq_lane_f32(m_b[k + 1][j], vsetq_lane_f32(m_b[k + 2][j], vsetq_lane_f32(m_b[k + 3][j], accum, 3), 2), 1), 0);

怎么看怎么蠢,优化掉的那点时间全拿来寻址了。

经测试,两个$1300$阶方阵相乘,用上面这种写法“优化”过的代码,总是比普通的三重循环要慢。

你是懂负优化的。

所以应该怎么写呢?

观察一下就能发现,算$\boldsymbol{A}\times\boldsymbol{B}$需要取列耗时长,取行的话倒是很方便算,自然想到$\boldsymbol{A}\times\boldsymbol{B}^{\mathrm T}$很好算,$\boldsymbol{A}$和$\boldsymbol{B}$都只需要取一行中的连续元素,于是自然想到可以算$\boldsymbol{A}\times\left(\boldsymbol{B}^{\mathrm T}\right)^{\mathrm T}=\boldsymbol{A}\times\boldsymbol{B}$,于是终极解法是:

1
2
3
4
5
6
7
for(i = 0; i < N; i++){
    for(j = i + 1; j < N; j++){
        tmp = m_b[i][j];
        m_b[i][j] = m_b[j][i];
        m_b[j][i] = tmp;
    }
}