优化汇编例程(5)

5. 在C++中使用固有函数

正如已经提及的,有3个不同的方式制作汇编代码:在C++中使用固有函数与向量类,在C++中使用内联汇编,以及独立的汇编模块。固有函数在本章描述。其他两个方法在下面章节描述。

固有函数与向量类是高度推荐的,因为它们比汇编语言语法更容易、也更安全。

Microsoft,Intel,Gnu与Clang C++编译器都支持固有函数。大多数固有函数产生一条机器指。因此,一个固有函数等同于一条机器指令。

使用固有函数编程是一种高级汇编。它很容易与C++语言构造结合,比如if语句、循环、函数、类及重载操作符。使用固有函数是比在汇编器中使用.if构造,或使用所谓的高级汇编器(HLA)更容易的方法。

固有函数的发明使之前要求汇编语法编写的编程任务,变得大为容易。使用固有函数的好处有:

  • 无需学习汇编语法。
  • 与C++代码的无缝整合。
  • 分支、循环、方式、类等很容易使用C++语法制作。
  • 编译器负责调用惯例、寄存器使用惯例等。
  • 代码对几乎所有x86平台可移植:32位与64位Windows、Linux、Mac OS等。某些固有函数甚至可以用在Itanium及其他非x86平台上。
  • 代码与Microsoft、Gnu、Clang及Intel编译器兼容。
  • 编译器负责寄存器变量、寄存器分配与寄存器溅出。程序员无需关心哪个寄存器用于哪个变量。
  • 同一个内联函数或操作符的不同实例可以对其参数使用不同的寄存器。这消除了寄存器到寄存器移动的需要。以汇编编写的相同函数通常对每个参数使用一个特定的寄存器,如果值恰好在另一个寄存器中,将需要一条移动指令。
  • 对固有函数定义一个重载操作符是可能的。例如,将两个4元素浮点向量相加的指令,在汇编中,被编码为ADDPS,而在使用固有函数时,是_mm_add_ps。但对后者,可以定义一个重载操作符,使在使用所谓的向量类时,这被简单地编码为一个+。这使得代码看起来像普通、旧式的C++。
  • 编译器可以进一步优化代码,例如通过公共子表达式消除、循环不变代码移动、调度与重排等。如果使用汇编,这将必须手动进行。Gnu与Intel编译器提供了最好的优化。

使用固有函数的不利之处有:

  • 不是所有的汇编指令都有等价的固有函数。
  • 函数名有时很长,很难记住。
  • 有许多固有函数的表达式看起来杂乱、难以阅读。
  • 要求对底下机制有良好的理解。
  • 编译器可能不能像其他代码那样优化包含固有函数的代码,特别是在需要常量传播时。
  • 缺乏技巧地使用固有函数会使代码比简单的C++代码还要低效。
  • 编译器会修改代码或一个比程序员预期的更低效的方式实现它。观察编译器产生的代码,看它是否以程序员预期的方式优化了,可能是必要的。
  • 如果程序员不遵守特定的规则,混用__m128与__m256类型会导致严重的时延。在从启用AVX编译的模块进入没有AVX编译的模块或库函数前,调用_mm256_zeropper()。

5.1. 对系统代码使用固有函数

固有函数有助于系统代码制作,以及访问标准C++不能访问的系统寄存器。某些这样的函数列出如下。

访问系统寄存器的函数:

__rdtsc, __readpmc, __readmsr, __readcr0, __readcr2, __readcr3, __readcr4, __readcr8, __writecr0, __writecr3, __writecr4, __writecr8, __writemsr, _mm_getcsr, _mm_setcsr, __getcallerseflags。

输入与输出函数:

__inbyte, __inword, __indword, __outbyte, __outword, __outdword。

原子内存读/写操作函数:

_InterlockedExchange等。

访问FS与GS段的函数:

__readfsbyte, __writefsbyte等。

缓存控制指令(要求SSE或SSE2指令集):

_mm_prefetch, _mm_stream_si32, _mm_stream_pi, _mm_stream_si128, _ReadBarrier, _WriteBarrier, _ReadWriteBarrier, _mm_sfence。

其他系统函数:

__cpuid, __debugbreak, _disable, _enable。

5.2. 对标准C++中不可用的指令使用固有函数

某些在标准C++中不可用的简单指令,可使用固有函数编写,例如用于比特旋转,比特扫描等的函数:

_rotl8, _rotr8, _rotl16, _rotr16, _rotl, _rotr, _rotl64, _rotr64, _BitScanForward, _BitScanReverse。

5.3. ​​​​​​​对向量操作使用固有函数

向量指令对提升具有内在并发性代码的速度很有帮助。几乎所有向量寄存器上的指令都有固有函数。

对向量操作使用这些固有函数,在手册1《优化C++软件》中有细致描述。

5.4. ​​​​​​​固有函数的可用性

固有函数在Microsoft、Gnu与Intel编译器的较新版本上可用。在所有这3个编译器上,大多数固有函数都相同的名字。要访问固有函数,你必须包含名为intrin.h或emmintrin.h的头文件。Codeplay编译器对固有向量函数有有限的支持,但函数名与其他编译器不兼容。

固有函数在每个编译器的帮助文档、合适的头文件、在msdn.microsoft.com、在《Intel 64 and IA-32 Architectures Software Developer’s Manual》(developer.intel.com),以及在《Intel Intrinsic Guide》(softwareprojects.intel.com/avx/)中列出。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值