C 如何使这种按位操作更快?

C 如何使这种按位操作更快?,c,optimization,bitwise-operators,C,Optimization,Bitwise Operators,代码非常简单 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; } intfoo(inta,intb,intc,intd,inte,

代码非常简单

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;
}
intfoo(inta,intb,intc,intd,inte,intf,intg)
{    

intr=(128)指令相当快。 考虑一下你在这里做什么,你有:

  • 7班制作业
  • 6或业务
  • 1内存分配操作
这已经需要至少14条指令。现在需要额外的指令,如存储中间结果和将操作数加载到寄存器中

如果需要更深入的分析,请发布程序集输出

编辑:现在开始对算法进行可能的优化


您可以通过牺牲一些内存来获得更快的速度。预计算在32位值中设置的每个可能位的值,例如:
int bit2value[32]={1,2,4,8,16,32,64,…}
在函数中,您可以通过查找预计算的映射来代替移位操作:
int r=bit2value[a]| bit2value[b]| bit2value[c]…;
这在理论上可以节省一些中间存储操作的需要。

28指令相当快。 考虑一下你在这里做什么,你有:

  • 7班制作业
  • 6或业务
  • 1内存分配操作
这已经需要至少14条指令。现在需要额外的指令,如存储中间结果和将操作数加载到寄存器中

如果需要更深入的分析,请发布程序集输出

编辑:现在开始对算法进行可能的优化

您可以通过牺牲一些内存来获得更快的速度。预计算在32位值中设置的每个可能位的值,例如:
int bit2value[32]={1,2,4,8,16,32,64,…};
在您的函数中,您可以通过查找预计算的映射来替换移位操作:
int r=bit2value[a]| bit2value[b]| bit2value[c]…;
这在理论上可以节省一些中间存储操作的需要。

使用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;
}
使用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;
}

对于您需要的每个参数:

mov cl, argument
mov edx, 1
shl edx, cl
or eax, edx

我相信您的函数有7个参数?最多为
g
?27(4*7-1)由于您可以在
eax
中直接计算第一个参数的移位结果,因此它的值很低。您不能将每个参数加载到寄存器中,因为指令不会直接在内存上运行。如果每次都不将某个值设为1,则无法移位1。显然,如果没有移位指令或您需要的每个参数的

mov cl, argument
mov edx, 1
shl edx, cl
or eax, edx


我相信您的函数有7个参数?最多为
g
?27(4*7-1)由于您可以在
eax
中直接计算第一个参数的移位结果,因此它的值很低。您不能将每个参数加载到寄存器中,因为指令不会直接在内存上运行。如果每次都不将某个值设为1,则无法移位1。显然,如果没有移位指令或

您用“unsigned char”试过了吗数据类型,或者编译器已经在优化类型了?如果你正在尝试优化汇编代码,为什么不自己编写呢?@Miguel当可能有30位移位时,
无符号字符
会有什么帮助?你能解释一下为什么你认为代码不是最优的吗?英特尔有BTS指令,类似于
a |=1。你试过吗“无符号字符"数据类型,或者编译器已经在优化类型了?如果你正在尝试优化汇编代码,为什么不自己编写呢?@Miguel当可能有30位移位时,
unsigned char
会有什么帮助?你能解释一下为什么你认为代码不是最优的吗?英特尔有BTS指令,类似于
a |=1那么你不需要首先是
,所以只有27条指令,但你的观点仍然站得住脚。你需要用一条归零的
xor eax,eax
替换它。你可以把第一条指令放在
eax
中,不过,
mov eax,1\etc
你不需要第一条
,所以只有27条指令,但你的观点仍然站得住脚要用一个调零
xor eax,eax
来替换它,您只需将第一个放在
eax
中,
mov eax,1\etc
内存不多(上限int[30]),并且不需要将移位位的值加载到寄存器。
mov edx[arg];或eax[precalcArray+edx*4]
是每个参数所需的全部内容。因此,在这里您可以将其减半。但是,不要混淆指令数和速度。与整数数学相比,内存访问成本相当高。@是的,它的内存不是很多,但在这种情况下,这种微优化可能是过度工程。它不会将指令数减半。将移位位加载到寄存器并不构成指令的一半。28指令每个参数只有4条,这是我的答案。2是4的一半,我相信。谢谢你们。我在发布此内容后提出了相同的方法。我刚才做了一个测试,似乎这确实节省了一半指令。@henrylee您分析过它吗?我很想知道当你将指令减半,但将内存回迁增加了一倍,并且可能引入了大量管道暂停时发生了什么。如果你只需要小代码,那就太好了。它没有太多内存(上限int[30]),而且你不需要将移位位的值加载到寄存器中。
mov-edx,[arg];或eax,[precalcArray+edx*4]
就是这些