相关疑难解决方法(0)

Haswell/Skylake的部分寄存器究竟如何表现?写AL似乎对RAX有假依赖,而AH是不一致的

此循环在英特尔Conroe/Merom上每3个周期运行一次,imul按预期方式在吞吐量方面存在瓶颈.但是在Haswell/Skylake上,它每11个循环运行一次,显然是因为setnz al它依赖于最后一个循环imul.

; synthetic micro-benchmark to test partial-register renaming
    mov     ecx, 1000000000
.loop:                 ; do{
    imul    eax, eax     ; a dep chain with high latency but also high throughput
    imul    eax, eax
    imul    eax, eax

    dec     ecx          ; set ZF, independent of old ZF.  (Use sub ecx,1 on Silvermont/KNL or P4)
    setnz   al           ; ****** Does this depend on RAX as well as ZF?
    movzx   eax, al
    jnz  .loop         ; }while(ecx);
Run Code Online (Sandbox Code Playgroud)

如果setnz al …

x86 assembly intel cpu-architecture micro-optimization

30
推荐指数
2
解决办法
1537
查看次数

为什么这个函数将RAX作为第一个操作推送到堆栈?

在下面的C++源代码的汇编中.为什么RAX被推入堆栈?

正如我从ABI理解的那样,RAX可以包含来自调用函数的任何内容.但是我们将它保存在这里,然后将堆栈移回8个字节.所以堆栈上的RAX,我认为只与std::__throw_bad_function_call()操作相关......?

代码:-

#include <functional> 

void f(std::function<void()> a) 
{
  a(); 
}
Run Code Online (Sandbox Code Playgroud)

gcc.godbolt.org使用Clang 3.7.1 -O3 输出:

f(std::function<void ()>):                  # @f(std::function<void ()>)
        push    rax
        cmp     qword ptr [rdi + 16], 0
        je      .LBB0_1
        add     rsp, 8
        jmp     qword ptr [rdi + 24]    # TAILCALL
.LBB0_1:
        call    std::__throw_bad_function_call()
Run Code Online (Sandbox Code Playgroud)

我确定原因很明显,但我很难弄清楚.

这是一个没有std::function<void()>包装器的尾部调用,用于比较:

void g(void(*a)())
{
  a(); 
}
Run Code Online (Sandbox Code Playgroud)

琐碎的:

g(void (*)()):             # @g(void (*)())
        jmp     rdi        # TAILCALL
Run Code Online (Sandbox Code Playgroud)

c++ x86 assembly x86-64 abi

22
推荐指数
3
解决办法
2098
查看次数

使用CMP reg测试寄存器是否为零,0与OR reg,reg?

使用以下代码是否存在任何执行速度差异:

cmp al, 0
je done
Run Code Online (Sandbox Code Playgroud)

以下内容:

or al, al
jz done
Run Code Online (Sandbox Code Playgroud)

我知道JE和JZ指令是相同的,并且使用OR可以提供一个字节的大小改进.但是,我也关心代码速度.逻辑运算符似乎比SUB或CMP更快,但我只是想确定.这可能是规模和速度之间的权衡,或双赢(当然代码将更加不透明).

optimization x86 assembly micro-optimization

13
推荐指数
2
解决办法
3755
查看次数

为什么GCC不使用部分寄存器?

write(1,"hi",3)在linux上反汇编,gcc -s -nostdlib -nostartfiles -O3结果如下:

ba03000000     mov edx, 3 ; thanks for the correction jester!
bf01000000     mov edi, 1
31c0           xor eax, eax
e9d8ffffff     jmp loc.imp.write
Run Code Online (Sandbox Code Playgroud)

我不是到编译器的开发,但由于移动到这些寄存器的每一个值是恒定的和已知的编译时间,我很好奇,为什么不GCC使用dl,dilal来代替.也许有人会说,此功能不会让任何性能上的差异,但有一个在之间的可执行文件的大小有很大的区别mov $1, %rax => b801000000,并mov $1, %al => b001当我们谈论数千寄存器的程序访问.如果软件的优雅部分不仅体积小,它确实会对性能产生影响.

有人可以解释为什么"海湾合作委员会决定"它无所谓?

x86 assembly gcc x86-64

13
推荐指数
2
解决办法
1655
查看次数

Sandybridge微体系结构中的堆栈引擎是什么?

我正在阅读http://www.realworldtech.com/sandy-bridge/,我在理解一些问题时面临一些问题:

专用堆栈指针跟踪器也存在于Sandy Bridge中并重命名堆栈指针,消除了串行依赖性并删除了多个uop.

什么是dedicated stack pointer tracker实际?

对于Sandy Bridge(和P4),英特尔仍然使用术语ROB.但重要的是要理解,在这种情况下,它只引用了飞行中uops的状态数组

事实上它意味着什么?请说清楚.

x86 assembly intel cpu-architecture

9
推荐指数
1
解决办法
979
查看次数

哪个Intel微体系结构引入了ADC reg,0单Uop特殊情况?

Haswell及更早版本的ADC通常为2 uops,有2个周期延迟,因为Intel uops传统上只能有2个输入(https://agner.org/optimize/).在Haswell为FMA引入3输入微指令和某些情况下的索引寻址模式的微融合之后,Broadwell/Skylake及其后来都有单uop ADC/SBB/CMOV .

(但不适用于adc al, imm8短格式编码,或其他al/ax/eax/rax,imm8/16/32/32短格式,没有ModRM.我的答案中有更详细的说明.)

但是adc,即时0是特殊的Haswell解码为只有一个uop. @BeeOnRope测试了这个,并在他的uarch-bench中包含了对这个性能怪癖的检查:https://github.com/travisdowns/uarch-bench.从输出样本CI一个的Haswell服务器上示出之间的差adc reg,0adc reg,1adc reg,zeroed-reg.

(对于SBB也是如此.就我所见,在任何CPU上具有相同立即数的等效编码,ADC和SBB性能之间从来没有任何差别.)


这个优化何时adc bl,0推出?

我测试了Core 2 1,发现imm=0延迟是2个周期,相同adc eax,0.同时,也是循环计数是与吞吐量测试一些变化相同的adc eax,3对比0,所以第一代的Core 2(Conroe处理器/ Merom处理器)并没有这样做优化.

回答这个问题的最简单方法可能是在Sandybridge系统上使用我的测试程序,看看是否3比它快adc eax,0.但基于可靠文档的答案也可以.

(顺便说一句,如果有人可以访问Sandybridge上的perf计数器,你还可以通过运行@ BeeOnRope的测试代码来清除在执行uop计数不是处理器宽度倍数的循环时性能降低的谜团.或者是性能我在不再工作的SnB上观察到的只是因为未分层与正常的uops有什么不同?)


脚注1:我在运行Linux的Core 2 E6600(Conroe/Merom)上使用了这个测试程序.

;; NASM / YASM
;; assemble / link this …
Run Code Online (Sandbox Code Playgroud)

performance x86 assembly intel micro-optimization

6
推荐指数
2
解决办法
279
查看次数

编写程序集时使用哪些寄存器重要吗?

如果您正在编写程序集,那么将值分配给哪个寄存器重要吗?假设您将累积/中间值存储在 %ebx 而不是 %eax 中,后者传统上用于此目的。这是不好的做法吗?会影响性能吗?

换句话说,您是否可以将它们等同于存储空间,还是应该坚持将它们用于特定目的?

x86 assembly cpu-registers accumulator

6
推荐指数
4
解决办法
1194
查看次数

rbp不允许作为SIB基础?

我对x86-64二进制编码很新.我正在尝试修复一些旧的"汇编程序"代码.

无论如何,我正在尝试做这样的事情(英特尔语法):

mov    [rbp+rcx], al
Run Code Online (Sandbox Code Playgroud)

汇编程序目前正在生成:

88 04 0D
Run Code Online (Sandbox Code Playgroud)

但这似乎不是一个有效的指示.如果我将SIB字节中的基数更改rbp为其他寄存器,则可以正常工作.另一种使其工作的方法是添加一个零字节的位移(88 44 0D 00).这似乎与其他类似的操作码一起发生.

为什么我不能rbp在那里使用mod=00

x86 assembly x86-64 machine-code addressing-mode

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