相关疑难解决方法(0)

为什么INC和ADD 1有不同的表现?

多年来我多次读过你应该做XOR ax,ax因为它更快......或者用C编程时使用counter ++或counter + = 1因为它们会INC或ADD ......或者在Netburst Pentium中4 INC比ADD 1慢,因此必须警告编译器你的目标是一个Netburst所以它会将所有var ++翻译成ADD 1 ......

我的问题是:为什么INC和ADD有不同的表现?为什么例如INC声称在Netburst上速度较慢而在其他处理器中比ADD快?

hardware optimization x86 assembly cpu-architecture

11
推荐指数
1
解决办法
2128
查看次数

如何BSWAP低32位的64位寄存器?

我一直在寻找如何将BSWAP用于64位寄存器的低32位子寄存器的答案.例如,0x0123456789abcdef在RAX寄存器中,我想0x01234567efcdab89用一条指令将其更改为(由于性能).

所以我尝试了以下内联函数:

#define BSWAP(T) {  \
    __asm__ __volatile__ (  \
            "bswap %k0" \
            : "=q" (T)  \
            : "q" (T)); \
}
Run Code Online (Sandbox Code Playgroud)

结果是0x00000000efcdab89.我不明白为什么编译器就像这样.有人知道有效的解决方案吗?

c 64-bit gcc endianness

8
推荐指数
1
解决办法
5006
查看次数

64位汇编,何时使用较小尺寸的寄存器

我理解在x86_64汇编中有例如(64位)rax寄存器,但它也可以作为32位寄存器,eax,16位,ax和8位来访问.在什么情况下我不会只使用完整的64位,以及为什么会有什么优势?

举个例子,通过这个简单的hello world程序:

section .data
msg: db "Hello World!", 0x0a, 0x00
len: equ $-msg

section .text
global start

start:
mov rax, 0x2000004      ; System call write = 4
mov rdi, 1              ; Write to standard out = 1
mov rsi, msg            ; The address of hello_world string
mov rdx, len            ; The size to write
syscall                 ; Invoke the kernel
mov rax, 0x2000001      ; System call number for exit = 1
mov rdi, 0              ; Exit success = 0
syscall …
Run Code Online (Sandbox Code Playgroud)

64-bit assembly x86-64 nasm cpu-registers

8
推荐指数
2
解决办法
4135
查看次数

在%x86-64上,mov%esi,%esi是否为no-op?

我对Linux内核的一个头文件(arch/x86/include/asm/nops.h)中的注释感到有些困惑.它说明了这一点

<...>以下指令在64位模式下不是nops,对于64位模式,使用K8或P6 nops而不是
movl%esi,%esi
leal 0x00(%esi),%esi
<...>

我想作者暗示机器指令(分别是'89 F6'和'8D 76 00')而不是汇编指令.根据LEA英特尔软件开发人员手册第2A卷中的描述,后一条指令(lea 0x00(%rsi), %esi)与前者相同,mov %esi,%esi.

所以这简化了问题,是否mov %esi,%esi实际上是x86-64上的无操作.

mov不会改变旗帜.这种mov也不会改变记忆.似乎,如果它改变了一些东西%rip,那应该是通用寄存器.但我不知道它如何改变内容%rsi或其他内容.如果你操纵通用寄存器的下半部分,上半部分不应该改变,对吧?

assembly x86-64 linux-kernel

8
推荐指数
2
解决办法
1845
查看次数

x86 NOP和FNOP指令有什么区别?

我正在阅读英特尔指令手册并注意到有一条'NOP'指令在主CPU上没有任何作用,而且一条'FNOP'指令在FPU上什么都不做.为什么有两个单独的指令什么都不做?

我看到的唯一不同之处是它们会抛出不同的异常,因此您可能会从FNOP中查看异常,以检测是否有可用的FPU.但是没有像CPUID这样的其他机制来检测这个吗?有什么实际的理由有两个单独的NOP指令?

x86 assembly x87

8
推荐指数
1
解决办法
1650
查看次数

在长模式下使用64/32位寄存器可能会有任何处罚吗?

可能这甚至都不是微观但纳米优化,但主题让我感兴趣,我想知道在长模式下使用非本机寄存器大小时是否存在任何惩罚?

我从各种来源了解到,部分寄存器更新(比如ax代替eax)会导致eflags停顿并降低性能.但我不确定长模式.对于此处理器操作模式,哪个寄存器大小被视为原生?x86-64仍然是x86架构的扩展,因此我相信32位仍然是原生的.还是我错了?

例如,像

sub eax, r14d
Run Code Online (Sandbox Code Playgroud)

要么

sub rax, r14
Run Code Online (Sandbox Code Playgroud)

具有相同的尺寸,但在使用其中任何一种时可能会有任何处罚吗?在如下连续指令中混合寄存器大小时可能会有任何处罚吗?(假设高dword在所有情况下均为零)

sub ecx, eax
sub r14, rax
Run Code Online (Sandbox Code Playgroud)

optimization x86 assembly micro-optimization

8
推荐指数
1
解决办法
186
查看次数

xorl%eax,g86生成的x86_64汇编代码中的%eax

我在集会上总是一个菜鸟,只是捅了一下看看发生了什么.无论如何,我写了一个非常简单的函数:

void multA(double *x,long size)
{
  long i;
  for(i=0; i<size; ++i){
    x[i] = 2.4*x[i];
  }
}
Run Code Online (Sandbox Code Playgroud)

我编译它:

gcc -S -m64 -O2 fun.c
Run Code Online (Sandbox Code Playgroud)

我得到了这个:

    .file   "fun.c"
    .text
    .p2align 4,,15
    .globl  multA
    .type   multA, @function
multA:
.LFB34:
    .cfi_startproc
    testq   %rsi, %rsi
    jle .L1
    movsd   .LC0(%rip), %xmm1
    xorl    %eax, %eax
    .p2align 4,,10
    .p2align 3
.L3:
    movsd   (%rdi,%rax,8), %xmm0
    mulsd   %xmm1, %xmm0
    movsd   %xmm0, (%rdi,%rax,8)
    addq    $1, %rax
    cmpq    %rsi, %rax
    jne .L3
.L1:
    rep
    ret
    .cfi_endproc
.LFE34:
    .size   multA, .-multA
    .section    .rodata.cst8,"aM",@progbits,8
    .align …
Run Code Online (Sandbox Code Playgroud)

assembly gcc x86-64

7
推荐指数
1
解决办法
9307
查看次数

在x86-64中使用32位寄存器/指令的优点

有时gcc使用32位寄存器,当我希望它使用64位寄存器时.例如以下C代码:

unsigned long long 
div(unsigned long long a, unsigned long long b){
    return a/b;
}
Run Code Online (Sandbox Code Playgroud)

使用-O2选项编译(省略一些样板文件):

div:
    movq    %rdi, %rax
    xorl    %edx, %edx
    divq    %rsi
    ret
Run Code Online (Sandbox Code Playgroud)

对于无符号除法,寄存器%rdx需要0.这可以通过xorq %rdx, %rdxxorl %edx, %edx似乎具有相同的效果来实现.

至少在我的机器上没有性能提升(即加速)进行xorlxorq.

我实际上不只是一个问题:

  1. 为什么gcc更喜欢32位版本?
  2. 为什么gcc会停止xorl并且不使用xorw
  3. 有没有xorl比这更快的机器xorq
  4. 如果可能的话,总是更喜欢32位寄存器/操作而不是64位寄存器/操作吗?

assembly gcc x86-64 micro-optimization

7
推荐指数
2
解决办法
749
查看次数

编译器生成昂贵的MOVZX指令

我的探查器已将以下功能分析标识为热点.

typedef unsigned short ushort;

bool isInteriorTo( const std::vector<ushort>& point , const ushort* coord , const ushort dim )
{
    for( unsigned i = 0; i < dim; ++i )
    {
        if( point[i + 1] >= coord[i] ) return false;
    }

    return true;  
}
Run Code Online (Sandbox Code Playgroud)

特别是一个汇编指令MOVZX(Move with Zero-Extend)负责运行时的大部分.if语句被编译成

mov     rcx, QWORD PTR [rdi]
lea     r8d, [rax+1]
add     rsi, 2
movzx   r9d, WORD PTR [rsi-2]
mov     rax, r8
cmp     WORD PTR [rcx+r8*2], r9w
jae     .L5
Run Code Online (Sandbox Code Playgroud)

我想哄骗编译器生成这条指令,但我想我首先需要理解为什么生成这条指令.为什么扩展/零扩展,考虑到我使用相同的数据类型?

(在godbolt编译器资源管理器 …

c++ optimization assembly profiling

7
推荐指数
2
解决办法
2743
查看次数

“cqo”、“cdq”和“cwd”x86_64 指令。为什么不只使用 cqo?

我不是最有经验的汇编程序员,我遇到了“cqo”、“cdq”和“cwd”指令,它们都是有效的 x86_64 汇编。

我想知道在操作较小的值时使用 cdq 或 cwd 是否有任何优势。性能上有什么区别吗?

编辑:最初在计算一位数的绝对值时开始研究这一点。

例如,如果我们在 al 中有 -9 值:

cwd
xor al,dl
sub al,dl
Run Code Online (Sandbox Code Playgroud)

与将其作为 32 位值并计算

cdq
xor eax,edx
sub eax,edx
Run Code Online (Sandbox Code Playgroud)

或者如果我们有 -9 的 64 位值

cqo
xor rax,rdx
sub rax,rdx
Run Code Online (Sandbox Code Playgroud)

如果原始值是 64 位并且由一个值 -9 到 9 组成,那么实际上它们看起来都是一样的。

assembly x86-64

6
推荐指数
1
解决办法
6735
查看次数