代码非常简单。
int foo(int a, int b, int c, int d, int e, int f, int g)
{
int r = (1 << a) | (1 << b) | (1 << c) | (1 << d) | (1 << e ) | (1 << f) | (1 << g);
return r;
}
假设所有参数都不大于30。
它似乎是一个非常原始的函数,但在使用“-Ofast”标志进行编译后,它仍需要28条指令来计算r。
是否有替代代码可以使这些按位运算更快?
答案 0 :(得分:5)
28条指令相当快。 考虑一下你在这做什么。你有:
这已经需要至少14条指令。现在还有其他必要的指令,例如存储中间结果和将操作数加载到寄存器中。
如果您想进行更深入的分析,请发布程序集输出。
修改:现在可以优化您的算法。
你可能能够通过牺牲一些内存来获得更快的速度。预先计算以32位值设置的每个可能位的值,例如,类似的东西:int bit2value[32]={1,2,4,8,16,32,64,...};
在您的函数中,您可以通过查找预先计算的映射替换它们而不是执行移位操作:int r = bit2value[a] | bit2value[b] | bit2value[c]...;
理论上这可以节省一些中间存储操作的需要。
答案 1 :(得分:0)
使用 Visual Studio 2015 (32位,针对空间进行了优化),以下代码会生成21
而不是24
指令:
typedef struct container
{
int a, b, c, d, e, f, g;
} CONTAINER;
int foo2(CONTAINER *ct)
{
int r = (1 << ct->a) | (1 << ct->b) | (1 << ct->c) | (1 << ct->d) | (1 << ct->e) | (1 << ct->f) | (1 << ct->g);
return r;
}
汇编代码(21而不是20条指令,抱歉!):
1 push esi
2 mov edx, ecx
3 xor esi, esi
4 inc esi
5 mov ecx, DWORD PTR [edx+24]
6 mov eax, DWORD PTR [edx+20]
7 shl esi, cl
8 mov ecx, DWORD PTR [edx+8]
9 bts esi, eax
10 mov eax, DWORD PTR [edx+16]
11 bts esi, eax
12 mov eax, DWORD PTR [edx+12]
13 bts esi, eax
14 bts esi, ecx
15 mov ecx, DWORD PTR [edx+4]
16 bts esi, ecx
17 mov ecx, DWORD PTR [edx]
18 bts esi, ecx
19 mov eax, esi
20 pop esi
21 ret 0
答案 2 :(得分:0)
对于您需要的每个参数:
mov cl, argument
mov edx, 1
shl edx, cl
or eax, edx
我相信你的功能有7个参数?最高g
? 27(4 * 7 - 1)尽可能低,因为你可以直接在eax
计算第一个参数的移位结果。您不能 将每个参数加载到寄存器中,因为指令不直接在内存上运行。每次不设置为1时,您无法移动1。显然,你不能没有转换指令或or
。