考虑以下汇编代码循环:
#include <iostream>
#define ADD_LOOP(i, n, v) \
asm volatile ( \
"movw %1, %%cx ;" \
"movq %2, %%rax ;" \
"movq $0, %%rbx ;" \
"for: ;" \
"addq %%rax, %%rbx ;" \
"decw %%cx ;" \
"jnz for ;" \
"movq %%rbx, %0 ;" \
: "=x"(v) \
: "n"(i), "x"(n) \
: "%cx", "%rax", "%rbx" \
);
int main() {
uint16_t iter(10000);
uint64_t num(5);
uint64_t val;
ADD_LOOP(iter, num, val)
std::cout << val << std::endl;
return 0;
}
可以在循环中调用C函数(或它的机器代码输出),如上所述吗?
例如:
#include <wmmintrin.h>
int main() {
__m128i x, y;
for(int i = 0; i < 10; i++) {
x = __builtin_ia32_aesenc128(x, y);
}
return 0;
}
由于
答案 0 :(得分:10)
没有。内置函数不是可以使用call
调用的实际函数。在C / C ++中使用时,它们总是内联。
例如,如果您希望int __builtin_popcount (unsigned int x)
为popcnt
的目标获取-mpopcnt
指令,或者为不支持{popcnt
的目标获取逐字节查找表1}}指示,你运气不好。您必须自己#ifdef
并使用popcnt
或其他指令序列。
您正在谈论的功能,__builtin_ia32_aesenc128
只是the aesenc
assembly instruction的包装,如果以asm身份书写,您可以直接使用它。
如果您正在编写asm而不是使用C ++内在函数(例如#include <immintrin.h>
)来提高性能,则需要查看http://agner.org/optimize/以编写更高效的asm(例如,使用%ecx
作为一个循环计数器,而不是%cx
。使用16位部分寄存器,你什么也得不到。)
您还可以编写更有效的内联asm约束,例如: movq %%rbx, %0
是浪费指令。您可以一直使用%0
而不是明确%rbx
。如果你的内联asm以一个mov指令开始或结束来复制到输出/输入操作数,那么通常你做错了。让编译器为您分配寄存器。请参阅inline-assembly代码wiki。
或者更好,https://gcc.gnu.org/wiki/DontUseInlineAsm。具有内在函数的代码通常可以很好地编译x86。请参阅Intel's intrinsics guide:#include <immintrin.h>
并使用__m128i _mm_aesenc_si128 (__m128i a, __m128i RoundKey)
。 (在gcc中,它只是__builtin_ia32_aesenc128
的包装器,但它使您的代码可以移植到其他x86编译器。)
答案 1 :(得分:3)