位移效率

时间:2016-12-05 22:31:59

标签: c++ bit-manipulation

比一个整数上的位移(对于AMD64或x86架构)更快(比需要更少的CPU周期)更快(比至少1个位置)?我怀疑答案是肯定的,因为在这两种情况下都会使用相同的32位或64位CPU指令,两者都需要相同的时钟周期。这是真的吗?

3 个答案:

答案 0 :(得分:2)

这取决于。一般来说,如果你有一个N位处理器,那么很可能任何高达N位的东西都需要相同的时间来移位,较大的变量需要更长的时间。如果您正在对字节进行操作,但希望确保使用适当大小的整数来表示速度,则使用类型uint_fast8_t

但是:如果你在循环中进行位移,那么编译器可能能够对代码进行矢量化。如果您的处理器具有SSE2指令,则它可以在一条指令中执行8次16位移位。如果你有AVX甚至AVX512,那么它可以在一条指令中进行16位甚至32位16位移位。但是,这是否比使用常规指令更有效取决于将许多变量加载到SSE寄存器中的容易程度,以及如果您执行的操作多于对它们进行位移的操作。

查看编译器的汇编器输出是有益的(例如,使用gcc -save-temps编译程序并查看生成的.s文件。请注意,所选的优化级别对生成的汇编程序有很大的影响。

确定最快变量大小的最佳方法就是测量它。

答案 1 :(得分:2)

我的假设是8位或16位(无符号)整数的移位与32位字机器上32位量的位移相同。

大多数32位字长处理器在内部以32位数量运行。桶形移位器,算术单元等设计用于32位操作。数据获取机制将在移位操作发生之前将8位或16位数量转换为32位数量。 32位数量不需要任何调整,因此较小的整数可能会有轻微的延迟。

另一方面,可能存在具有特殊数据路径的处理器,用于8位或16位大小的整数。

验证的方法是在您的系统和其他目标系统上进行配置。

另外,问问自己执行时间差异是重要还是重要。

答案 2 :(得分:1)

我之前发布的代码不正确。虽然代码包含一个移位,但由于结果未存储,编译器只是跳过它。这是一个简单的int示例:

void main() {
    int value = 0;
    value = value << 3;
}

简短的例子:

void foo() {
    short value = 0;
    value = value << 3;
}

整数示例生成:

    .file   "main.c"
    .text
    .globl  _Z3foov
    .def    _Z3foov;    .scl    2;  .type   32; .endef
    .seh_proc   _Z3foov
_Z3foov:
.LFB0:
    pushq   %rbp
    .seh_pushreg    %rbp
    movq    %rsp, %rbp
    .seh_setframe   %rbp, 0
    subq    $16, %rsp
    .seh_stackalloc 16
    .seh_endprologue
    movl    $0, -4(%rbp)
    sall    $3, -4(%rbp)
    nop
    addq    $16, %rsp
    popq    %rbp
    ret
    .seh_endproc
    .ident  "GCC: (GNU) 5.4.0"

简短示例生成:

    .file   "main.c"
    .text
    .globl  _Z3foov
    .def    _Z3foov;    .scl    2;  .type   32; .endef
    .seh_proc   _Z3foov
_Z3foov:
.LFB0:
    pushq   %rbp
    .seh_pushreg    %rbp
    movq    %rsp, %rbp
    .seh_setframe   %rbp, 0
    subq    $16, %rsp
    .seh_stackalloc 16
    .seh_endprologue
    movw    $0, -2(%rbp)
    movswl  -2(%rbp), %eax
    sall    $3, %eax
    movw    %ax, -2(%rbp)
    nop
    addq    $16, %rsp
    popq    %rbp
    ret
    .seh_endproc
    .ident  "GCC: (GNU) 5.4.0"

简短的例子执行:

movw    $0, -2(%rbp)
movswl  -2(%rbp), %eax
sall    $3, %eax
movw    %ax, -2(%rbp)

整数示例执行:

movl    $0, -4(%rbp)
sall    $3, -4(%rbp)

所以看起来没有任何编译器优化,整数移位实际上更快。