相关疑难解决方法(0)

在大数组中有效地找到最低有效设置位?

我有一个巨大的内存块(位向量),在一个内存页中大小为N位,考虑N平均为 5000,即 5k 位来存储一些标志信息。
在某个时间点(超级频繁 - 关键),我需要在整个大位向量中找到第一个位集。现在我每 64 个字都这样做,即在 ) 的帮助下__builtin_ctzll。但是当N增长并且搜索算法无法改进时,可以通过扩展内存访问宽度来扩展此搜索。这是几句话的主要问题

有一条被调用的汇编指令BSF 给出了最高设置位(GCC's __builtin_ctzll())的位置。因此,在 arch 中,我可以在 64 位字中廉价地找到最高位。

但是通过内存宽度进行缩放呢?
例如,有没有办法用 128 / 256 / 512 位寄存器有效地做到这一点?
基本上我对一些 C API 函数来实现这个感兴趣,但也想知道这个方法是基于什么的。

UPD:至于 CPU,我对这种优化感兴趣,以支持以下 CPU 阵容:
英特尔至强 E3-12XX、英特尔至强 E5-22XX/26XX/E56XX、英特尔酷睿 i3-5XX/4XXX/8XXX、英特尔酷睿 i5- 7XX、英特尔赛扬 G18XX/G49XX(英特尔凌动 N2600、英特尔赛扬 N2807、Cortex-A53/72 可选)

PS在最终位扫描之前提到的算法中,我需要将k(平均 20-40)个N位向量与 CPU AND相加(AND 结果只是位扫描的准备阶段)。这也适用于内存宽度缩放(即比每 64 位字 AND 更有效)

另请阅读:查找第一组

c assembly bit-manipulation x86-64 avx

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

为什么XCHG reg,注册了关于现代英特尔架构的3微操作指令?

我正在对代码的性能关键部分进行微优化,并且遇到了指令序列(在AT&T语法中):

add %rax, %rbx
mov %rdx, %rax
mov %rbx, %rdx
Run Code Online (Sandbox Code Playgroud)

我以为我终于有一个用例xchg可以让我刮一个指令并写:

add  %rbx, %rax
xchg %rax, %rdx
Run Code Online (Sandbox Code Playgroud)

然而,根据Agner Fog的指令表,我发现这xchg是一个3微操作指令,在Sandy Bridge,Ivy Bridge,Broadwell,Haswell甚至Skylake上有2个周期延迟.3个完整的微操作和2个周期的延迟!3微操作抛出了我的4-1-1-1的节奏和2周期延迟使得它比在最好的情况下原来的,因为在原来的并行执行可能最后2条指令差.

现在......我得知CPU可能会将指令分解为相当于以下内容的微操作:

mov %rax, %tmp
mov %rdx, %rax
mov %tmp, %rdx 
Run Code Online (Sandbox Code Playgroud)

哪里tmp是匿名内部寄存器,我想最后两个微操作可以并行运行,因此延迟是2个周期.

鉴于寄存器重命名发生在这些微架构上,但对我来说这是以这种方式完成的.为什么寄存器重命名器不会交换标签?理论上,这将只有1个周期(可能是0?)的延迟,并且可以表示为单个微操作,因此它会便宜得多.

performance x86 assembly intel

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

某些通用寄存器是否比其他寄存器更快?

在 x86-64 中,如果某些通用寄存器比其他寄存器更受欢迎,某些指令会执行得更快吗?

例如,mov eax, ecx执行速度会比mov r8d, ecx? 我可以想象后者需要一个 REX 前缀,这会使指令获取速度变慢?

使用rax而不是怎么样rcx?怎么样add还是xor?其他操作?较小的寄存器,如r15bvs al? alah?

AMD VS 英特尔?较新的处理器?旧处理器?指令组合?

澄清:某些通用寄存器是否应该优先于其他寄存器,它们是哪些?

performance x86 assembly x86-64 cpu-registers

11
推荐指数
2
解决办法
307
查看次数

LSD可以从检测到的循环的下一次迭代中发出uOP吗?

我正在使用一个非常简单的循环开始调查我的Haswell端口0上的分支单元的功能:

BITS 64
GLOBAL _start

SECTION .text

_start:

 mov ecx, 10000000

.loop:

 dec ecx             ;|
  jz .end            ;| 1 uOP (call it D)

jmp .loop            ;| 1 uOP (call it J)

.end:
 mov eax, 60
 xor edi, edi
 syscall
Run Code Online (Sandbox Code Playgroud)

使用perf我们看到循环以1c/iter运行

Performance counter stats for './main' (50 runs):

        10,001,055      uops_executed_port_port_6   ( +-  0.00% )
         9,999,973      uops_executed_port_port_0   ( +-  0.00% )
        10,015,414      cycles:u                    ( +-  0.02% )
                23      resource_stalls_rs          ( +- 64.05% )
Run Code Online (Sandbox Code Playgroud)

我对这些结果的解释是:

  • D和J都是并行发送的.
  • J具有1个周期的倒数吞吐量.
  • D和J都以最佳方式发送.

但是,我们也可以看到RS永远不会满员.
它最多可以以2 uOPs/c的速率发送uOP,但理论上可以得到4 …

x86 assembly cpu-architecture intel-pmu

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

为什么 GCC 再次使用 movzbl 对已经零扩展的寄存器进行零扩展?

我想知道为什么这段代码:

size_t hash_word(const char* c, size_t size) {
    size_t hash = uchar(c[0]);
    hash ^= uchar(c[size - 1]);
    hash ^= uchar(c[size - 2]);
    return hash;
}
Run Code Online (Sandbox Code Playgroud)

编译时:

    movzbl  -1(%rcx,%rdx), %eax
    xorb    -2(%rcx,%rdx), %al
    xorb    (%rcx), %al
    movzbl  %al, %eax            <-
    ret
Run Code Online (Sandbox Code Playgroud)

结果是第二条 movzbl 行。

我转换为asmg++ -Wall -O3 -S file.cpp

按照我的理解,%eax 的所有高位应该已经从第一个 movzbl 开始设置为零。那么下面的两个 xorb 不应该修改任何高位,因为它只触及 %al 中的位。那么为什么还需要额外的说明呢?不是应该在前三个之后再做吗?

c++ assembly gcc x86-64 cpu-architecture

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

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
查看次数

在长模式下使用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
查看次数

使用FPU和MMX寄存器作为"通用寄存器"

大多数汇编程序利用4个通用寄存器eax ebx ecx edx,但我发现,很多时候我需要使用超过4个寄存器来轻松地完成我的任务,而不必pushpop从堆栈得多.由于我的程序无意使用FPU或MMX寄存器进行浮点计算或"预期用途",在程序中使用这些额外的寄存器是否可以接受?

例如.使用xmm0一个循环递增计数器腾出ecx寄存器做其他事情.

x86 assembly cpu-registers

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

如何检测Intel Alder Lake CPU中的P/E-Core?

哪个逻辑处理器属于 P 核心组,哪个属于 E 核心组?

我的第一个想法是检查每个逻辑处理器的基本时钟,然后假设最低的基本时钟属于 E 核(根据英特尔规范,E 核的基本时钟总是明显低于 P 核)。

我希望HKEY_LOCAL_MACHINE\HARDWARE\DESCRIPTION\System\CentralProcessor在注册表中进行检查就足够了。不幸的~MHz是始终包含 P 核的基本时钟。

x86 intel cpu-cores cpuid

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

为什么EAX中的高16位不能按名称访问(如AX,AH和AL)?

为什么没有特定的寄存器来访问寄存器的其他部分(16-32)?

al一样访问ax寄存器的8位部分.

在此输入图像描述

x86 assembly

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