1、资源

1.1、ARM开发者官网

https://developer.arm.com/

http://infocenter.arm.com

1.2、纯汇编和inline汇编参考资源

32位ARM优化可以参考文档:

https://developer.arm.com/products/architecture/a-profile/docs/ddi0406/latest/arm-architecture-reference-manual-armv7-a-and-armv7-r-edition

64位ARM优化可以参考文档:

https://developer.arm.com/products/architecture/a-profile/docs/ddi0487/latest/arm-architecture-reference-manual-armv8-for-armv8-a-architecture-profile

其他资源(均来源于http://infocenter.arm.com):

RealView编译工具《编译器参考指南》:

http://infocenter.arm.com/help/topic/com.arm.doc.dui0348bc/DUI0348BC_rvct_comp_ref_guide.pdf

RealView编译工具《汇编器指南》:

http://infocenter.arm.com/help/topic/com.arm.doc.dui0204ic/DUI0204IC_rvct_assembler_guide.pdf

RealView编译工具《链接器用户指南》:

http://infocenter.arm.com/help/topic/com.arm.doc.dui0206ic/DUI0206IC_rvct_linker_user_guide.pdf

1.3、Neon Intrinsics参考资源

https://developer.arm.com/technologies/neon/intrinsics

http://infocenter.arm.com/help/topic/com.arm.doc.ihi0073a/IHI0073A_arm_neon_intrinsics_ref.pdf

http://infocenter.arm.com/help/topic/com.arm.doc.ihi0073b/IHI0073B_arm_neon_intrinsics_ref.pdf

2、介绍

2.1、ARM优化简介

ARM是三大CPU架构(X86、ARM、MIPS)之一,是精简指令集计算机的代表,其功耗低、功能强的特点使之广泛应用于移动设备。目前常见的是ARM32和ARM64,下面对其分别简单介绍:

(1)ARM32以ARMv7为主要架构,是32位的,常见的设备有:iphone5、Cortex-A15;

(2)ARM64以ARMv8为主要架构,是64位的,常见的设备有:Cortex-A53、Cortex-A57、iphone5s的A7、iphone6和iphone6Plus的A8等。

2.2、ARM指令集简介

Thumb指令、ARM指令和NEON指令的区别和联系:Thumb指令是ARM指令中一种16位的指令集,具有16bit的代码密度;ARM指令集包含ARM32和ARM64,分别适用于ARM32位优化和ARM64位优化;NEON指令集同样包含NEON32和NEON64,分别适用于ARM32位优化和ARM64位优化。不管ARM指令集还是NEON指令集,虽然都包含适用于ARM32位优化和ARM64位优化的指令集,但是它们的指令名称、个数和使用方法均是不一样的,需要特别注意,尤其是在ARM32位优化改写为ARM64位优化时。

2.3、callee和caller简介

3、ARM32位优化

3.1、ARM32位寄存器

ARM32位寄存器共有16个(R0~R15),均是32位宽的,ARM32遵循ATPCS(ARM-THUMB procedure call standard,ARM-Thumb过程调用标准)规则:

a. R0~R3寄存器用于子程序间传递参数,当参数大于4时,将多余的参数用数据栈进行传递,入栈的顺序与参数顺序恰好相反,被调用子程序返回前无需恢复寄存器R0~R3的值,也就是说R0~R3无需出栈和入栈;

b. R4~R11寄存器用于子程序间保存变量,这些寄存器在子程序进入时必须保存,返回时必须恢复,也就是说R4~R11使用时必须出栈和入栈;

c. R13是堆栈指针寄存器SP(在进入子程序时的值和退出子程序时的值必须相等),R14是链接寄存器LR,R15是一个程序计数器PC;

d. R12时一般的通用寄存器,使用时不需要保存;

e. 子程序返回32位的整数,使用R0返回;返回64位的整数时,使用R0返回低位、R1返回高位。

3.2、NEON32位寄存器

NEON32位寄存器主要包含如下寄存器,由于NEON寄存器是有重叠部分物理地址的,所以使用时需要特别注意:

32个单字(32bits)的S寄存器(S0~S31);

32个双字(64bits)的D寄存器(D0~D31);

16个四字(128bits)的Q寄存器(Q0~Q15)。

neon的S/D/Q寄存器之间的关系举例如下:

S0 S1 S2 S3 S4 S5 S6 S7 S8 S9 S10 S11 S12 S13 S14 S15
D0 D1 D2 D3 D4 D5 D6 D7
Q0 Q1 Q2 Q3

在使用neon32位寄存器时,如果用到d8~d15寄存器,需要先入栈vpush {d8~d15},使用完后要出栈vpop {d8~d15};若对应于S寄存器,则是S16~S31;对应于Q寄存器,则是Q4~Q7。

4、ARM32位优化模板

假设我们有如下三个文件:

arm32_opt_c.c        :待优化的c源码和demo模板

arm32_opt_arm.s    :arm32汇编优化源码

makefile                  :优化模板的makefile,编译出可执行文件测试出汇编性能提升倍数

arm32_opt_c.c内容如下:

#include <string.h>
#incldue <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <time.h>extern void arm32_opt_arm(unsigned short *output_asm,unsigned short *input,int width,int height,int blocksize,int stride);void arm32_opt_c(unsigned short *output_c,unsigned short *input,int width,int height,int blocksize);
{int x,y;for(x=0;x<width;x++){output_c[0*width+x]=0;for(y=0;y<blocksize;y++)output_c[0*width+x] += input[y*width+x]}
}int main(int argc,char *argv[])
{int m,loop_num=10000;int i,j;clock_t BeginTime1,EndTime1,BeginTime2,EndTime2;int width,height,blocksize;width=atoi(argv[1]);height=atoi(argv[2]);blcoksize=atoi(argv[3]);srand((int)time(0));unsigned short *input=NULL;unsigned short *output_c=NULL;unsigned short *output_asm=NULL;input=(unsigned short *)malloc(width*height*sizeof(unsigned short));output_c=(unsigned short *)malloc(width*height*sizeof(unsigned short));output_asm=(unsigned short *)malloc(width*height*sizeof(unsigned short));if(input==NULL||output_c==NULL||output_asm=NULL){return -1;}// 初始化输入和输出为0memset(input,0,width*height);memset(output_c,0,width*height);memset(output_asm,0,width*height);// 输入随机for(i=0;i<height;i++){ for(j=0;j<width;j++){ input[i*width+j]=rand()%0xFF; } }// arm优化BeginTime1=clock();for(m=0;m<loop_num;m++){ arm32_opt_asm(output_asm,input,width,height,blocksize,width); }EndTime1=clock();printf("now :%6.3fms\n",(double)(EndTime1-BeginTime1));// c源码BeginTime2=clock();for(m=0;m<loop_num;m++){ arm32_opt_c(output_asm,input,width,height,blocksize); }EndTime2=clock();printf("prev :%6.3fms\n",(double)(EndTime2-BeginTime2));// 打印优化性能提升结果printf("cycle_times = %d\n",loop_num);printf("perfo_impro:%f\n",(double)(EndTime2-BeginTime2)/(EndTime1-BeginTime1));// 验证优化结果是否正确for(i=0;i<height;i++){ for(j=0;j<width;j++){ if(output_c[i*width+j]!=output_asm[i*width+j]){ printf("error_data[%d,%d]:%d,%d\n",j,i,output_c[i*width+j],output_asm[i*width+j]); } } }printf("Opt success!!!\n");free(input);free(output_c);free(output_asm);return 0;
}

arm32_opt_arm.s内容如下:

    .text.arm.align 4.global arm32_opt_asm
arm32_opt_asm:PUSH {R4-R12,LR}    @ 入栈ADD R11,SP,#40      LDM R11,{R4,R5}     @ 加载多个寄存器 blcoksize strideMOV R8,R0           @ output_asmMOV R9,R1           @ inputMOV R6,R2           @ width
loop_x:MOV R7,R4MOV R10,R9VEOR Q1,Q1          @ 按位异或loop_y:VLD1.16 {Q1},[R10]  @ 向量加载VADD.U16 Q1,Q0,Q1   @ 向量加法ADD R10,R5,LSL#1SUBS R7,#1BGT loop_y          @ branch greater thanVST1.16 {Q1},[R8]!  @ 向量存储ADD R9,#16SUBS R6,#8BGT loop_xPOP {R4-R12,PC}
.end

makefile内容如下:

ROOTSRC = .
PLATFORM ?= 666888ifeq ($(PLATFORM),666888)
CORSS = arm-hisiv500-linux-
CFLAGS += -march=armv7-a -mfloat-abi=softfp
SFLAGS += -march=armv7-a -mfpu=neon
endifCC = $(CROSS)gcc
CPP = $(CROSS)g++
LD = $(CROSS)ld
AR = $(CROSS)ar
AS = $(CROSS)asCFALGS += -O3
CFLAGS += -I$(ROOTSRC)TARGET_APP = test
OBJS = $(ROOTSRC)/arm32_opt_c.o \$(ROOTSRC)/arm32_opt_asm.oall:$(TARGET_APP)
$(TARGET_APP):$(OBJS)$(CC) -O $@ $(OBJS)rm -f $(OBJS)rm -f *.o%.o:%.c$(CC) -c $< $(CFLAGS) -o $@%.o:%.cpp$(CPP) -c $< $(CFLAGS) -o $@%.o:%.S$(CC) -c $< $(CFLAGS) -o $@%.o:%.s$(AS) -c $< $(SFLAGS) -o $@clean:rm -rf $(OBJS)rm -rf $(TARGET_APP)

5、ARM64位优化

5.1、ARM64位寄存器

ARM64有32个寄存器(X0~X31),均是64位宽的,ARM64遵循AAPCS64(ARM Archtecture Procedure Call Standard)规则,其中:

a. 其中w0~w30分别是x0~x30的低32位;

b. x0~x7寄存器用于子程序间传递参数,当参数大于8时,将多余的参数用数据栈进行传递,入栈的顺序与参数顺序恰好相反,被调用子程序返回前无需恢复寄存器x0~x7的值

c. x8是XR,用于保存子程序返回地址;

d. x9~x15是临时寄存器,使用时不需要保存;

e. x16(IP0)、x17(IP1)是子程序内部调用寄存器,使用时不需要保存;

f. x18(PR)是平台寄存器,它的使用和平台有关;

g. x19~x28是临时寄存器,使用必须保存(入栈);

h. x29(FP)是帧指针寄存器,用于链接栈帧,使用时需要保存;

i. x30是链接寄存器LR,x31是堆栈指针寄存器SP;

j. PC是程序寄存器。

5.2、NEON64位寄存器

Neon64寄存器主要包含如下:

32个B寄存器(B0~B31),8bit;

32个H寄存器(H0~H31),16bit;

32个S寄存器(S0~S31),单字(32bit);

32个D寄存器(D0~D31),双字(64bit);

32个Q寄存器(V0~V31),四字(128bit)。

它们之间的关系举例如下:

S0是32位的,是D0(64位)的低半部分,D0是V0(128位)的低半部分;S1是32位的,是D1(64位)的低半部分,D1是V1(128位)的低半部分,这一点与NEON32是不同的,需要注意!!!

除此之外,仍需要特别注意的是NEON寄存器v0~v31的使用方法:

a. v0~v7:用于参数传递和返回值,callee(被调用者或者子程序)时不需要保存,即不需要出栈和入栈;

b. v8~v15:callee子程序调用时必须入栈保存(低64位进行保存即可);

c. v16~v31:callee不需要保存;

d. caller可能需要保存的是v0~v7,v16~v31。

6、ARM64位优化模板

假设我们有如下三个文件:

arm64_opt_c.c        :待优化的c源码和demo模板

arm64_opt_arm.s    :arm64汇编优化源码

makefile                  :优化模板的makefile,编译出可执行文件测试出汇编性能提升倍数

arm64_opt_c.c与arm32_opt_c.c一样;

arm64_opt_arm.s 如下:

    .text.align 4.global arm64_opt_asm
arm64_opt_asm:mov x9,x0            // output_asmmov x10,x1           // inputmov x11,x2           // width
loop_x:mov x12,x4mov x13,x10eor v1.16B,v1.16B,v1.16B  // 按位异或loop_y:ldl {v0.8H},[x13]         // 向量加载add v1.8H,v0.8H,v1.8H     // 向量加法add x13,x13,x5,lsl #1subs x12,x12,#1bgt loop_y                // branch greater thanst1 {v1.8H},[x9],#16      // 向量存储add x10,x10,#16subs x11,x11,#8bgt loop_xret                       // 汇编调用的子程序返回

makefile与ARM32的异同点如下:

CORSS = aarch64-himix100-linux-
CFLAGS += -march=armv8-a -mfpu=cortex-a73
SFLAGS += -march=armv8-a -mfpu=cortex-a73

或者

CORSS = aarch64-himix100v630-linux-
CFLAGS += -march=armv8-a
SFLAGS += -march=armv8-a

7、ARM的inline汇编

ARM32位的inline汇编与ARM64位的inline汇编格式一样,唯一不同的是里面使用的寄存器等,这也是ARM32位纯汇编和ARM64纯汇编的区别。除此之外,Inline汇编是由编译器管理入栈和出栈,而纯汇编则是由被调用者(子函数)管理寄存器入栈和出栈。还需注意的一点是汇编分“AT&T”和“Intel”格式。

模板如下:

__asm volatile
("汇编指令1\n\t""汇编指令1\n\t""汇编指令1\n\t":输出变量列表【可选】:输入变量列表【可选】:被破坏的寄存器列表【可选】
);

举例如下:

__asm volatile
("mov r0,%[dst]    \n\t""mov r1,%[src]    \n\t""mov r2,%[stride] \n\t""mov r3,#16       \n\t""指令              \n\t"::[dst] "r" (dst),[src] "r" (src),[stride] "r" (stride):"r0","r1","r2","memory"
);

8、ARM的intrinsic汇编

Intrinsic作为内联函数,直接在调用的地方插入代码,即避免了函数调用的额外开销,又能够使用比较高级的机器指令对函数进行优化。

需要说明的是:intrinsics下,arm32和aarch64下的代码是一致的。

9、ARM32位优化与ARM64位优化的区别与联系

(1)无论是ARM32位优化还是ARM64位优化,均可混合使用ARM寄存器和NEON寄存器;

(2)ARM32位优化的注释方法为“@”,而ARM64位优化的注释方法为“//”或者“/**/”。

10、ARM指令集在linux/ios/android下的区别

后续补充。。。

CPU架构之ARM优化相关推荐

  1. 【Android 逆向】ARM CPU 架构体系 ( ARM 处理器工作模式 | ARM 架构模型 )

    文章目录 一.ARM 处理器工作模式 二.ARM 架构模型 一.ARM 处理器工作模式 参考 [嵌入式开发]ARM 处理器工作模式 及 修改方法 ( 处理器模式 | 设置处理器模式 | 程序状态字寄存 ...

  2. 【Android 逆向】ARM CPU 架构体系 ( ARM 内存模型 | ARM 架构堆的实现 | ARM 架构栈的实现 )

    文章目录 一.ARM 内存模型 二.ARM 架构堆的实现 三.ARM 架构栈的实现 一.ARM 内存模型 ARM 架构体系中 , CPU 直接访问内存 , 控制内存中的状态和数据 , 内存中映射外部设 ...

  3. CPU架构 intel,amd和arm的关系

    1.指令集 所谓指令集,是CPU中用来计算和控制计算机系统的一套指令的集合.指令的强弱是CPU的重要指标,指令集是提高微处理器效率的最有效工具之一. CPU依靠指令来计算和控制系统,每款CPU在设计时 ...

  4. 【Linux operation 23】Win 10 64位(X86 架构CPU)安装ARM架构的虚拟机(银河麒麟高级服务器操作系统 V10)

    1.银河麒麟高级服务器操作系统 V10(鲲鹏版)下载: 官网下载 https://www.kylinos.cn/scheme/server/1.html 1.银河麒麟高级服务器操作系统V10x86/兆 ...

  5. 从LLVM说起,有关CPU架构,JIT等

    文章目录 LLVM CPU架构 PowerPC ARM X86 MIPS 编译执行和解释执行 JIT编译 LLVM LLVM(Low Level Virtual Machine,不过官方为了避免混淆已 ...

  6. iOS - CPU架构

    之所以提到CPU架构的问题,其实是iOS开发使用的静态库与动态库与之紧密相连.在运行项目的时候,Xcode需要分析当前运行平台的CPU架构,然后确定所使用的静态库是否支持这个CPU架构.如果不支持就会 ...

  7. Android CPU架构及so库兼容问题总结

    CPU架构分类 armeabi armeabi-v7a(目前大部分机器) arm64-v8a (高端机型) x86 x86_64 mips mips64 Android手机大部分采用的是ARM架构的C ...

  8. CPU架构解析:ARM和x86大比拼

    信不信,随便逮住一个人问他知不知道CPU,我想他的答案一定会是肯定的,但是如果你再问他知道ARM和X86架构么?这两者的区别又是什么?绝大多数的人肯定是一脸懵逼.今天小编就带你深入了解CPU的这两大架 ...

  9. 从CPU架构--x86架构和arm架构处理器--功耗

    目录: 1.两种cpu架构:冯洛伊曼和哈佛 2.x86架构和arm架构分析 3.x86架构和arm架构功耗探究 一.两种cpu架构: 目前主流的cpu 处理器都采用了冯洛伊曼架构或者哈佛架构,那么这和 ...

最新文章

  1. geany怎么创建文件夹_SAP事务码太多,记不住怎么办?
  2. 参会邀请 | “新时代与新范式:新兴交叉学科的研究议程与发展路径”——第三届全国计算社会科学高端论坛...
  3. 计算机成绩统计优秀率,基于决策树算法的成绩优秀率分析与研究.pdf
  4. 详细整理分层开发步骤!
  5. 计算机在轻化工程中的应用,计算机在轻化工程专业中的应用-中国大学mooc-题库零氪...
  6. wx.checkjsapi是写在config里面吗_用Python写一个程序,解密游戏内抽奖的秘密
  7. 移动端web开发技巧
  8. linux find mtime 用法,Linux find命令常见用法汇总(4)
  9. 用C语言来实现冒泡排序
  10. [混音插件]板岩混响效果器
  11. 关于.NET、ASP.NET和ASP
  12. 3D点云处理:点云曲率-主曲率/高斯曲率/平均曲率
  13. JavaScript中的时间与日期、正则表达式和Function类型
  14. python 数字转换为汉字大写
  15. 综合电商高保真移动端Axure原型模板
  16. Use Ant implementing Continous Integration.
  17. 移动端html尺寸,移动端页面的三种尺寸
  18. 2005年商业科技盘点:最被低估10大技术+最被高估10大技术
  19. 如何下载安装ubuntu系统
  20. c语言里函数rand()和srand()的用法

热门文章

  1. linux虚拟网桥 docker,Docker 使用自定义网桥
  2. 怎样使控件的背景色为透明色?
  3. CSS深度(穿透)选择器
  4. React使用antd的警告findDOMNode is deprecated in StrictMode. findDOMNode was passed an instance of Wave
  5. [CVPR2022]3D Photo Stylization: Learning to Generate Stylized Novel Views from a Single Image
  6. 简单有效的低照度增强
  7. vs2017 html插件推荐,收藏!推荐12个超实用的Visual Studio插件
  8. uniapp保存图片_uni-app项目保存图片到相册
  9. vue2.0 webApp保存图片到相册
  10. 转帖:一生必读经典书籍大全,看看你读过几本?