├── ARMV7 NEON汇编指令详解中文版.pdf ├── Cortex_A57_Software_Optimization_Guide_external.pdf ├── IHI0073B_arm_neon_intrinsics_ref.pdf └── README.md /ARMV7 NEON汇编指令详解中文版.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rogerou/Arm-neon-intrinsics/887a828146f526676a82effb8f3efd33fa2eb186/ARMV7 NEON汇编指令详解中文版.pdf -------------------------------------------------------------------------------- /Cortex_A57_Software_Optimization_Guide_external.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rogerou/Arm-neon-intrinsics/887a828146f526676a82effb8f3efd33fa2eb186/Cortex_A57_Software_Optimization_Guide_external.pdf -------------------------------------------------------------------------------- /IHI0073B_arm_neon_intrinsics_ref.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rogerou/Arm-neon-intrinsics/887a828146f526676a82effb8f3efd33fa2eb186/IHI0073B_arm_neon_intrinsics_ref.pdf -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Arm-neon-intrinsics 2 | arm neon 方面的文档真的很少,所以整理下intrinsics指令的内容和文档 :) 3 | 4 | ### 更详细的armeabi-v7a文档可以看[ARMV7 NEON汇编指令详解中文版.pdf](https://github.com/rogerou/Arm-neon-intrinsics/blob/master/ARMV7%20NEON%E6%B1%87%E7%BC%96%E6%8C%87%E4%BB%A4%E8%AF%A6%E8%A7%A3%E4%B8%AD%E6%96%87%E7%89%88.pdf) 5 | ### 指令周期,吞吐量可以看[Cortex_A57_Software_Optimization_Guide_external.pdf](https://github.com/rogerou/Arm-neon-intrinsics/blob/master/Cortex_A57_Software_Optimization_Guide_external.pdf) 6 | ### [asm写法参考gcc内联汇编](https://github.com/tidyjiang8/arm-gcc-inline-assembler) 7 | ### [intrinsics对应aarch64或aarch32 asm 指令说明](https://github.com/rogerou/Arm-neon-intrinsics/blob/master/IHI0073B_arm_neon_intrinsics_ref.pdf) 8 | ## 初始化寄存器 9 | - vcreate_type: 将一个64bit的数据装入vector中,并返回元素类型为type的vector。r=a 10 | - vdup_n_type/vmov_n_type: 用类型为type的数值,初始化一个元素类型为type的新vector的所有元素。ri=a 11 | - vdupq_n_type/vmovq_n_type: 12 | - vdup_lane_type: 用元素类型为type的vector的某个元素,初始化一个元素类型为type的新vector的所有元素。ri=a[b] 13 | - vdupq_lane_type: 14 | - vmovl_type: 将vector的元素bit位扩大到原来的两倍,元素值不变。 15 | - vmovn_type: 用旧vector创建一个新vector,新vector的元素bit位是旧vector的一半。新vector元素只保留旧vector元素的低半部分。 16 | - vqmovn_type: 用旧vector创建一个新vector,新vector的元素bit位是旧vector的一半。如果旧vector元素的值超过新vector元素的最大值,则新vector元素就取最大值。否则新vector元素就等于旧vector元素的值。 17 | - vqmovun_type: 作用与vqmovn_type类似,但它输入的是有符号vector,输出的是无符号vector。 18 | ## 从内存加载数据进neon寄存器 19 | - vld1_type: 按顺序将内存的数据装入neon寄存器,并返回元素类型为type格式的vector 20 | - vld1q_type: 21 | - vld1_lane_type:用旧vector创建一个同类型的新vector,同时将新vector中指定元素的值改为内存中的值。 22 | - vld1q_lane_type: 23 | - vld1_dup_type:用type类型的内存中第一个值,初始化一个元素类型为type的新vector的所有元素。 24 | - vld1q_dup_type: 25 | - vld2_type: 按交叉顺序将内存的数据装入2个neon寄存器(内存第1个数据放入第1个neon寄存器的第1个通道,内存第2个数据放入第2个neon寄存器的第1个通道,内存第3个数据放入第1个neon寄存器的第2个通道,内存第4个数据放入第2个neon寄存器的第2个通道。。。)。并返回有两个vector的结构体 26 | - vld2q_type: 27 | - vld2_lane_type: 28 | - vld2q_lane_type: 29 | - vld2_dup_type: 用type类型的内存中第一个值,初始化第一个新vector的所有元素,用内存中第二个值,初始化第二个新vector的所有元素。 30 | - vld3_type: 交叉存放,本质上与vld2_type类似,只是这里装载3个neon寄存器 31 | - vld3q_type: 32 | - vld3_lane_type: 33 | - vld3q_lane_type: 34 | - vld3_dup_type: 本质上与vld2_dup_type类似 35 | - vld4_type: 交叉存放,本质上与vld2_type类似,只是这里装载4个neon寄存器 36 | - vld4q_type: 37 | - vld4_lane_type: 38 | - vld4q_lane_type: 39 | - vld4q_dup_type: 本质上与vld2_dup_type类似 40 | 41 | ## 从neon寄存器加载数据进内存 42 | - vst1_type: 将元素类型为type格式的vector的所有元素装入内存 43 | - vst1q_type: 44 | - vst1_lane_type: 将元素类型为type格式的vector中指定的某个元素装入内存 45 | - vst1q_lane_type: 46 | - vst2_type: 交叉存放,vld2_type的逆过程 47 | - vst2q_type: 48 | - vst2_lane_type: 49 | - vst2q_lane_type: 50 | - vst3_type: 交叉存放,vld3_type的逆过程 51 | - vst3q_type: 52 | - vst3_lane_type: 53 | - vst3q_lane_type: 54 | - vst4_type: 交叉存放,vld4_type的逆过程 55 | - vst4q_type: 56 | - vst4_lane_type: 57 | - vst4q_lane_type: 58 | ## 直接获取neon寄存器某个通道的值 59 | - vget_low_type: 获取128bit vector的低半部分元素,输出的是元素类型相同的64bit vector。 60 | - vget_high_type: 获取128bit vector的高半部分元素,输出的是元素类型相同的64bit vector。 61 | - vget_lane_type: 获取元素类型为type的vector中指定的某个元素值。 62 | - vgetq_lane_type: 63 | ## 直接设置neon寄存器某个通道的值 64 | - vset_lane_type: 设置元素类型为type的vector中指定的某个元素的值,并返回新vector。 65 | - vsetq_lane_type: 66 | ## 寄存器数据重排 67 | - vext_type: 取第2个输入vector的低n个元素放入新vector的高位,新vector剩下的元素取自第1个输入vector最高的几个元素(可实现vector内元素位置的移动) 68 | - vextq_type: 69 | 如:src1 = {1,2,3,4,5,6,7,8} 70 | src2 = {9,10,11,12,13,14,15,16} 71 | dst = vext_type(src1,src2,3)时,则dst = {4,5,6,7,8, 9,10,11} 72 | 73 | - vtbl1_type: 第二个vector是索引,根据索引去第一个vector(相当于数组)中搜索相应的元素,并输出新的vector,超过范围的索引返回的是0. 74 | 如:src1 = {1,2,3,4,5,6,7,8} 75 | src2 = {0,0,1,1,2,2,7,8} 76 | dst = vtbl1_u8(src1,src2)时,则dst = {1,1,2,2,3,3,8,0} 77 | 78 | - vtbl2_type: 数组长度扩大到2个vector 79 | 如:src.val[0] = {1,2,3,4,5,6,7,8} 80 | src.val[1] = {9,10,11,12,13,14,15,16} 81 | src2 = {0,0,1,1,2,2,8,10} 82 | dst = vtbl2_u8(src,src2)时,则dst = {1,1,2,2,3,3,9,11} 83 | 84 | - vtbl3_type: 85 | - vtbl4_type: 86 | - vtbx1_type: 根vtbl1_type功能一样,不过搜索到的元素是用来替换第一个vector中的元素,并输出替换后的新vector,当索引超出范围时,则不替换第一个vector中相应的元素。 87 | - vtbx2_type: 88 | - vtbx3_type: 89 | - vtbx4_type: 90 | - vrev16_type: 将vector中的元素位置反转 91 | 92 | - vrev16q_type: 93 | 如:src1 = {1,2,3,4,5,6,7,8} 94 | dst = vrev16_u8(src1)时,则dst = {2,1,4,3,6,5,8,7} 95 | 96 | - vrev32_type: 97 | 98 | - vrev32q_type: 99 | 如:src1 = {1,2,3,4,5,6,7,8} 100 | dst = vrev32_u8(src1)时,则dst = {4,3,2,1,8,7,6,5} 101 | - vrev64_type: 102 | 103 | - vrev64q_type: 104 | 如:src1 = {1,2,3,4,5,6,7,8} 105 | dst = vrev32_u8(src1)时,则dst = {8,7,6,5,4,3,2,1} 106 | 107 | - vtrn_type: 将两个输入vector的元素通过转置生成一个有两个vector的矩阵 108 | - vtrnq_type: 109 | 如:src.val[0] = {1,2,3,4,5,6,7,8} 110 | src.val[1] = {9,10,11,12,13,14,15,16} 111 | dst = vtrn_u8(src.val[0], src.val[1])时, 112 | 则 dst.val[0] = {1,9, 3,11,5,13,7,15} 113 | dst.val[1] = {2,10,4,12,6,14,8,16} 114 | 115 | - vzip_type: 将两个输入vector的元素通过交叉生成一个有两个vector的矩阵 116 | - vzipq_type: 117 | 如:src.val[0] = {1,2,3,4,5,6,7,8} 118 | src.val[1] = {9,10,11,12,13,14,15,16} 119 | dst = vzip_u8(src.val[0], src.val[1])时, 120 | 则dst.val[0] = {1,9, 2,10,3,11,4,12} 121 | dst.val[1] = {5,13,6,14,7,15,8,16} 122 | 123 | - vuzp_type: 将两个输入vector的元素通过反交叉生成一个有两个vector的矩阵(通过这个可实现n-way 交织) 124 | - vuzpq_type: 125 | 如:src.val[0] = {1,2,3,4,5,6,7,8} 126 | src.val[1] = {9,10,11,12,13,14,15,16} 127 | dst = vuzp_u8(src.val[0], src.val[1])时, 128 | 则dst.val[0] = {1,3,5,7,9, 11,13,15} 129 | dst.val[1] = {2,4,6,8,10,12,14,16} 130 | 131 | - vcombine_type: 将两个元素类型相同的输入vector拼接成一个同类型但大小是输入vector两倍的新vector。新vector中低部分元素存放的是第一个输入vector元素。 132 | - vbsl_type:按位选择,参数为(mask, src1, src2)。mask的某个bit为1,则选择src1中对应的bit,为0,则选择src2中对应的bit。 133 | - vbslq_type: 134 | 135 | ## 加法 136 | - vadd_type: ri = ai + bi 137 | - vaddq_type: 138 | - vaddl_type: 变长加法运算,为了防止溢出 139 | - vaddw_type: 第一个vector元素宽度大于第二个vector元素 140 | - vaddhn_type: 结果vector元素的类型大小是输入vector元素的一半 141 | - vqadd_type: ri = sat(ai + bi) 饱和指令,相加结果超出元素的最大值时,元素就取最大值。 142 | - vqaddq_type: 143 | - vhadd_type: 相加结果再除2。ri = (ai + bi) >> 1; 144 | - vhaddq_type: 145 | - vrhadd_type: 相加结果再除2(四舍五入)。ri = (ai + bi + 1) >> 1 146 | - vrhaddq_type: 147 | - vpadd_type: r0 = a0 + a1, ..., r3 = a6 + a7, r4 = b0 + b1, ..., r7 = b6 + b7 148 | - vpaddl_type: r0 = a0 + a1, ..., r3 = a6 + a7; 149 | - vpaddlq_type: 150 | - vpadal_type: r0 = a0 + (b0 + b1), ..., r3 = a3 + (b6 + b7); 151 | ## 减法 152 | - vsub_type: ri = ai - bi 153 | - vsubq_type: 154 | - vsubl_type: 155 | - vsubw_type: 156 | - vsubhn_type: 157 | - vqsub_type: 饱和指令 ri = sat(ai - bi) 158 | - vqsubq_type: 159 | - vhsub_type: 相减结果再除2。ri = (ai - bi) >> 1 160 | - vhsubq_type: 161 | - vrsubhn_type: 相减结果再除2(四舍五入)。ri = (ai - bi + 1) >> 1 162 | ## 乘法 163 | - vmul_type: ri = ai * bi 164 | - vmulq_type: 165 | - vmul_n_type: ri = ai * b 166 | - vmulq_n_type: 167 | - vmul_lane_type: ri = ai * b[c] 168 | - vmulq_lane_type: 169 | - vmull_type: 变长乘法运算,为了防止溢出 170 | - vmull_n_type: 171 | - vmull_lane_type: 172 | - vqdmull_type: 变长乘法运算,参与运算的值是有符号数(所以可能溢出),当结果溢出时,取饱和值 173 | - vqdmull_n_type: 174 | - vqdmull_lane_type: 175 | - vqdmulh_type: 176 | - vqdmulhq_type: 177 | - vqdmulh_n_type: 178 | - vqdmulhq_n_type: 179 | - vqdmulh_lane_type: 180 | - vqdmulhq_lane_type: 181 | - vqrdmulh_type: 182 | - vqrdmulhq_type: 183 | - vqrdmulh_n_type: 184 | - vqrdmulhq_n_type: 185 | - vqrdmulh_lane_type: 186 | - vqrdmulhq_lane_type: 187 | ## 乘加组合运算 188 | - vmla_type: ri = ai + bi * ci 189 | - vmlaq_type: 190 | - vmla_n_type: ri = ai + bi * c 191 | - vmlaq_n_type: 192 | - vmla_lane_type: ri = ai + bi * c[d] 193 | - vmlaq_lane_type: 194 | - vmlal_type: 长指令 ri = ai + bi * ci 195 | - vmlal_n_type: 196 | - vmlal_lane_type: 197 | - vfma_f32:ri = ai + bi * ci 在加法之前,bi、ci相乘的结果不会被四舍五入 198 | - vqdmlal_type: ri = sat(ai + bi * ci) bi/ci的元素大小是ai的一半 199 | - vqdmlal_n_type: ri = sat(ai + bi * c) 200 | - vqdmlal_lane_type: ri = sat(ai + bi * c[d]) 201 | ## 乘减组合运算 202 | - vmls_type: ri = ai - bi * ci 203 | - vmlsq_type: 204 | - vmls_n_type: ri = ai - bi * c 205 | - vmlsq_n_type: 206 | - vmls_lane_type: ri = ai - bi * c[d] 207 | - vmlsq_lane_type: 208 | - vmlsl_type: 长指令 ri = ai - bi * ci 209 | - vmlsl_n_type: 210 | - vmlsl_lane_type: 211 | - vfms_f32:ri = ai - bi * ci 在减法之前,bi、ci相乘的结果不会被四舍五入 212 | - vqdmlsl_type: ri = sat(ai - bi * ci) bi/ci的元素大小是ai的一半 213 | - vqdmlsl_n_type: ri = sat(ai - bi * c) 214 | - vqdmlsl_lane_type: ri = sat(ai - bi * c[d]) 215 | ## 取整 216 | - vrndn_f32: to nearest, ties to even 217 | - vrndqn_f32: 218 | - vrnda_f32: to nearest, ties away from zero 219 | - vrndqa_f32: 220 | - vrndp_f32: towards +Inf 221 | - vrndqp_f32: 222 | - vrndm_f32: towards -Inf 223 | - vrndqm_f32: 224 | - vrnd_f32: towards 0 225 | - vrnqd_f32: 226 | ## 比较运算(结果为true,则所有的bit位被设置为1) 227 | 228 | - vceq_type: ri = ai == bi ? 1...1 : 0...0 229 | - vceqq_type: 230 | - vcge_type: ri = ai >= bi ? 1...1:0...0 231 | - vcgeq_type: 232 | - vcle_type: ri = ai <= bi ? 1...1:0...0 233 | - vcleq_type: 234 | - vcgt_type: ri = ai > bi ? 1...1:0...0 235 | - vcgtq_type: 236 | - vclt_type: ri = ai < bi ? 1...1:0...0 237 | - vcltq_type: 238 | - vcage_f32: ri = |ai| >= |bi| ? 1...1:0...0 239 | - vcageq_f32: 240 | - vcale_f32: ri = |ai| <= |bi| ? 1...1:0...0 241 | - vcaleq_f32: 242 | - vcagt_f32: ri = |ai| > |bi| ? 1...1:0...0 243 | - vcagtq_f32: 244 | - vcalt_f32: ri = |ai| < |bi| ? 1...1:0...0 245 | - vcaltq_f32: 246 | - vtst_type: ri = (ai & bi != 0) ? 1...1:0...0 247 | - vtstq_type: 248 | ## 绝对值 249 | - vabs_type: ri = |ai| 250 | - vabsq_type: 251 | - vqabs_type: ri = sat(|ai|) 252 | - vqabsq_type: 253 | - vabd_type: ri = |ai - bi| 254 | - vabdq_type: 255 | - vabdl_type: 长指令 256 | - vaba_type: ri = ai + |bi - ci| 257 | - vabaq_type: 258 | - vabal_type: 长指令 259 | ## 取最大最小值 260 | - vmax_type: ri = ai >= bi ? ai : bi 261 | - vmaxq_type: 262 | - vpmax_type: r0 = a0 >= a1 ? a0 : a1, ..., r4 = b0 >= b1 ? b0 : b1, ... 263 | - vmin_type: ri = ai <= bi ? ai : bi 264 | - vminq_type: 265 | - vpmin_type: r0 = a0 <= a1 ? a0 : a1, ..., r4 = b0 <= b1 ? b0 : b1, ... 266 | ## 倒数 267 | - vrecpe_type: 求近似倒数,type是f32或者u32 268 | - vrecpeq_type: 269 | - vrecps_f32:(牛顿 - 拉夫逊迭代) 270 | - vrecpsq_f32 271 | 注:vrecpe_type计算倒数能保证千分之一左右的精度,如1.0的倒数为0.998047。执行完如下语句后能提高百万分之一精度 272 | float32x4_t recip = vrecpeq_f32(src);此时能达到千分之一左右的精度,如1.0的倒数为0.998047 273 | recip = vmulq_f32 (vrecpsq_f32 (src, rec), rec);执行后能达到百万分之一左右的精度,如1.0的倒数为0.999996 274 | recip = vmulq_f32 (vrecpsq_f32 (src, rec), rec);再次执行后能基本能达到完全精度,如1.0的倒数为1.000000 275 | ## 平方根倒数 276 | - vrsqrte_type: 计算输入值的平方根的倒数,type是f32或者u32。输入值不能是负数,否则计算出来的值是nan。 277 | - vrsqrteq_type: 278 | - vrsqrts_f32 279 | - vrsqrtsq_f32 280 | ## 移位运算 281 | - vshl_type: ri = ai << bi 如果bi是负数,则变成右移 282 | - vshlq_type: 283 | - vshl_n_type: ri = ai << b 这里b是常数,如果传入的不是常数(即在编译的时候就要知道b的值),编译时会报错 284 | - vshlq_n_type: 285 | - vqshl_type: ri = sat(ai << bi) 286 | - vqshlq_type: 287 | - vrshl_type: ri = round(ai << bi) 288 | - vrshlq_type: 289 | - vqrshl_type: ri = sat&round(ai << bi) 290 | - vqrshlq_type: 291 | - vqshl_n_type: ri = sat(ai << b) 292 | - vqshlq_n_type: 293 | - vqshlu_n_type: ri = ai << b 输入vector是有符号,输出vector是无符号 294 | - vqshluq_n_type: 295 | - vshll_n_type: 296 | 297 | - vshr_n_type: ri = ai >> b 298 | - vshrq_n_type: 299 | - vrshr_n_type: ri = round(ai >> b) 300 | - vrshrq_n_type: 301 | - vsra_n_type: ri = (ai >> c) + (bi >> c) 302 | - vsraq_n_type: 303 | - vrsra_n_type: ri = round((ai >> c) + (bi >> c)) 304 | - vrsraq_n_type: 305 | - vshrn_n_type: 窄指令ri = ai >> b 306 | - vqshrun_n_type: 307 | - vqrshrun_n_type: 308 | - vqshrn_n_type: 309 | - vrshrn_n_type: 310 | - vqrshrn_n_type: 311 | 312 | - vsri_n_type: 313 | - vsriq_n_type: 314 | - vsli_n_type: 315 | - vsliq_n_type: 316 | 317 | ## 取负 318 | - vneg_type: ri = -ai 319 | - vnegq_type: 320 | - vqneg_type: ri = sat(-ai) 321 | - vqnegq_type: 322 | ## 按位运算 323 | - vmvn_type: ri = ~ai 324 | - vmvnq_type: 325 | - vand_type: ri = ai & bi 326 | - vandq_type: 327 | - vorr_type: ri = ai | bi 328 | - vorrq_type: 329 | - veor_type: ri = ai ^ bi 330 | - veorq_type: 331 | - vbic_type: ri = ~ai & bi 332 | - vbicq_type: 333 | - vorn_type: ri = ai | (~bi) 334 | -vornq_type: 335 | ## 统计 336 | - vcls_type: 337 | - vclz_type: 338 | - vcnt_type: 统计向量每个元素有多少bit位是1 339 | - vcntq_type: 340 | ## 数据类型转换 341 | - vcvt_type1_type2: f32、u32、s32之间的转换。在f32转到u32时,是向下取整,且如果是负数,则转换后为0 342 | - vcvtq_type1_type2: 343 | - vcvt_n_type1_type2: 344 | - vcvtq_n_type1_type2: 345 | - vreinterpret_type1_type2: 将元素类型为type2的vector转换为元素类型为type1的vector。数据重新解析 346 | - vreinterpretq_type1_type2: 347 | 348 | 349 | 350 | --------------------------------------------------------------------------------