对于C / C ++程序员而言,内联汇编并不是一项新功能,可帮助我们充分利用计算能力。 但是,大多数程序员很少改变这种做法。 实际上,内联汇编仅满足特定的要求,尤其是在涉及高级编程语言的最前沿时。
本文介绍了有关IBM POWER处理器体系结构的两种方案。 使用本文提供的示例,我们可以找出在哪里应用内联汇编。
方案1:一个更好的库
C / C ++编程语言支持逻辑操作。 因此,在该示例中,用户将比特作为基本单位。 用户编写了一种算法来计算一个32位变量占用的位数。
代码A:计算占用的位数
01 inline int bit_taken(int data)
02 {
03 int taken = 0;
04 while (data) {
05 data = (data >> 1);
06 taken++;
07 }
08 return taken;
09 }
该代码显示了使用循环和移位操作。 如果用户以最高优化级别(对于gcc为-O3,对于xlc为-O5)编译代码,则用户可能会发现自动进行了一些优化(例如展开,持续数据传播等)以生成最快的代码世界上的代码。 算法的基本思想虽然没有改变。
清单A: cntlzw的描述
cntlzw(C OU nt下 大号 eadingŽ性爱W¯¯ORD)指令
目的
将源通用寄存器中前导零的数目放入通用寄存器中。
cntlzw指令能够获取前导零的数量。 假设我们有一个数字15,其二进制表示形式是0000、0000、0000、0000、0000、0000、0000、0000、1111, cntlzw会说总共有28个前导零。 重新考虑之后,用户决定简化自己的算法,如代码B所示。
代码B:计算内联汇编所占用的位数
01 #ifdef __ARCH_PPC__
02 inline int bit_taken(int data)
03 {
04 int taken;
05 asm("cntlzw %0, %1\n\t"
06 : "=b" (taken)
07 : "b" (data)
08 );
09 return sizeof(data) * 8 – taken;
10 }
11 #else
... ...
21 #endif
名为__ARCH_PPC__的宏仅包装PowerPC体系结构的新代码。 与代码A相比,新代码消除了所有循环或移位。 库提供者的客户可能很高兴看到bit_taken
性能有所提高。 它在PowerPC上运行得更快。 而且,应用程序绑定bit_taken
甚至可以更好地工作。
这个故事不仅说明用户可以通过丰富的指令改进其算法,而且内联汇编是执行性能工作的最佳助手。 通过将汇编代码嵌入C / C ++,可以最大程度地减少用户在代码更改方面的工作。
方案2:原子比较和交换(CAS)
最近,随着整个计算机行业将重点转移到多处理,多线程上,它不可避免地带来了更多的元素(例如编程中的同步。要在多线程环境中组成信号量和互斥量之类的同步原语,我们经常提到原子操作称为比较交换(CAS)。清单B显示了CAS的伪代码。
清单B:CAS的伪代码
清单1。
compare_and_swap (*p, oldval, newval):
if (*p == oldval)
*p = newval;
success;
else
fail;
在清单B中,首先将内存位置p(* p)的内容与已知值oldval (在当前线程中应为* p的值)进行比较。 仅当它们相同时, 才将newval写入* p。 当另一个线程修改了前面的内存位置时,比较将失败。
为准确起见,应使CAS原子化。 原子性超出了C / C ++的处理能力,但可以通过使用一小段内联汇编代码来保证。 代码C显示了为PowerPC体系结构实现的简单CAS。
代码C:在PowerPC上的简单CAS实现
01 void inline compare_and_swap (volatile int * p, int oldval, int newval)
02 {
03 int fail;
04 __asm__ __volatile__ (
05 "0: lwarx %0, 0, %1\n\t"
06 " xor. %0, %3, %0\n\t"
07 " bne 1f\n\t"
08 " stwcx. %2, 0, %1\n\t"
09 " bne- 0b\n\t"