1. 背景及需求
由于项目需求及硬件资源约束,笔者需要基于RK3588板端的NEON寄存器,对当前的hot pot算子进行加速实现。作为SIMD指令集小白,笔者不得不从熟悉相关内联函数的使用开始,逐渐揭开SIMD的神秘面纱!该系列博文,以学习过程中涉及的诸多CV类或其他类算子为切入点,结合内联函数及纯汇编代码等进行逐个的精讲及剖析。
2. 实现思路

图1. 4*4矩阵分步转置示意(共计两大步)
如图1所示,4*4矩阵可按照行向量方式划分为4行,后续SSE操作时,以上述的行向量为基本操作单位,数据类型统一为float32。为方便结果的对比,矩阵数值设置如下:

图2. 输入矩阵示意
因而,其转置后的输出结果应为:

图3. 输出矩阵示意
3. 相关SSE指令用法及功能说明
本次涉及的内联函数主要包括两大类,即:
(1) _mm_load_ps() / _mm_store_ps() :利用XMM寄存器单次获取/存储4个fp32的浮点型数据;
(2) _mm_unpacklo_ / _mm_unpackhi_():从源XMM寄存器中去除低32(或高32)位数据后,交叉存储在目的寄存器中。以_mm_unpacklo_ps()函数为例,其具体示意如下(其余函数同理):

图4. _mm_unpacklo_ps()函数操作过程说明
4. 源码说明
#include <ctime>
#include <iostream>
#include <chrono>
#include <mmintrin.h>
#include <xmmintrin.h>
#include <emmintrin.h>
#include <x86intrin.h>
using namespace std;
#define M 4
#define N 4
// 满足内存对齐要求的malloc函数
void* aligned_malloc(size_t size, size_t alignment)
{
size_t offset = alignment - 1 + sizeof(void*);
void * originalP = malloc(size + offset);
size_t originalLocation = reinterpret_cast<size_t>(originalP);
size_t realLocation = (originalLocation + offset) & ~(alignment - 1);
void * realP = reinterpret_cast<void*>(realLocation);
size_t originalPStorage = realLocation - sizeof(void*);
*reinterpret_cast<void**>(originalPStorage) = originalP;
return realP;
}
// 内存释放
void aligned_free(void* p)
{
size_t originalPStorage = reinterpret_cast&l

本文介绍了使用SSE指令对4x4矩阵进行行向量转置的方法,对比了传统方法和SSE方法的性能,结果显示SSE方法显著提高了效率。
最低0.47元/天 解锁文章
2174





