相关疑难解决方法(0)

通过计算条件早期避免拖延管道

在谈论ifs的表现时,我们通常会谈论错误预测如何阻止管道.我看到的推荐解决方案是:

  1. 相信通常有一个结果的条件的分支预测器; 要么
  2. 如果合理可能的话,避免使用一点点魔法分支; 要么
  3. 有条件的移动尽可能.

我找不到的是我们是否能尽早计算出病情,以便在可能的情况下提供帮助.所以,而不是:

... work
if (a > b) {
    ... more work
}
Run Code Online (Sandbox Code Playgroud)

做这样的事情:

bool aGreaterThanB = a > b;
... work
if (aGreaterThanB) {
    ... more work
}
Run Code Online (Sandbox Code Playgroud)

这样的事情可能会完全避免这个条件的停顿(取决于管道的长度和我们可以放在bool和if之间的工作量)?这并不一定是因为我写的,但有什么办法,以评估条件语句早,所以CPU不必尝试和预测的分支

此外,如果这有帮助,编译器可能会做什么呢?

language-agnostic performance cpu-architecture compiler-optimization branch-prediction

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

汇编语言(x86):如何创建循环来计算Fibonacci序列

我正在使用Visual Studio 2013 Ultimate在MASM中编写汇编语言(x86).我试图使用数组来计算使用数组的n个元素的Fibonacci序列.换句话说,我试图去一个数组元素,获取它之前的两个元素,添加它们,并将结果存储在另一个数组中.

我无法设置索引寄存器以使其工作.

我的程序设置如下:

TITLE fibonacci.asm

INCLUDE Irvine32.inc

.data
    fibInitial  BYTE 0, 1, 2, 3, 4, 5, 6
    fibComputed BYTE 5 DUP(0)

.code
main PROC

    MOVZX si, fibInitial
    MOVZX di, fibComputed
    MOV   cl, LENGTHOF fibInitial

L1:
    MOV   ax, [si - 1]
    MOV   dx, [si - 2]
    MOV   bp, ax + dx
    MOV   dl, TYPE fibInitial
    MOVZX si, dl
    MOV   [edi], bp
    MOV   dh, TYPE fibComputed
    MOVZX di, dl
    loop L1

exit
main ENDP
END main
Run Code Online (Sandbox Code Playgroud)

我无法编译这个,因为该行的错误消息"错误A2031:必须是索引或基址寄存器" MOV ebp, …

x86 assembly masm irvine32

5
推荐指数
1
解决办法
2万
查看次数

Intel Nehalem 微架构可以实现的最大 IPC 是多少?

是否有对英特尔 Nehalem 架构可实现的最大每周期指令的估计?另外,影响每周期最大指令数的瓶颈是什么?

x86 intel cpu-architecture nehalem

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

用于使用AVX512生成掩模的BMI

我受到了这个链接的启发 https://www.sigarch.org/simd-instructions-considered-harmful/来研究AVX512的表现.我的想法是使用AVX512掩码操作可以删除循环后的清理循环.

这是我正在使用的代码

void daxpy2(int n, double a, const double x[], double y[]) {
  __m512d av = _mm512_set1_pd(a);
  int r = n&7, n2 = n - r;
  for(int i=-n2; i<0; i+=8) {
    __m512d yv = _mm512_loadu_pd(&y[i+n2]);
    __m512d xv = _mm512_loadu_pd(&x[i+n2]);
    yv = _mm512_fmadd_pd(av, xv, yv);
    _mm512_storeu_pd(&y[i+n2], yv);
  }
  __m512d yv = _mm512_loadu_pd(&y[n2]);
  __m512d xv = _mm512_loadu_pd(&x[n2]);
  yv = _mm512_fmadd_pd(av, xv, yv);
  __mmask8 mask = (1 << r) -1;
  //__mmask8 mask = _bextr_u32(-1, 0, r);
  _mm512_mask_storeu_pd(&y[n2], mask, yv);
}
Run Code Online (Sandbox Code Playgroud)

我认为使用BMI1和/或BMI2指令可以生成具有更少指令的掩码.然而, …

x86 simd riscv avx512 bmi

5
推荐指数
2
解决办法
250
查看次数

性能:Mod 和赋值与条件和赋值

我在 ISR 中有一个计数器(由 50us 的外部 IRQ 触发)。计数器递增并环绕 MAX_VAL (240)。

我有以下代码:

if(condition){
  counter++;
  counter %= MAX_VAL;
  doStuff(table[counter]);
}
Run Code Online (Sandbox Code Playgroud)

我正在考虑另一种实现:

if(condition){
  //counter++;//probably I would increment before the comparison in production code
  if(++counter >= MAX_VAL){
    counter=0;
  }
  doStuff(table[counter]);
}
Run Code Online (Sandbox Code Playgroud)

我知道人们建议不要尝试这样优化,但这让我想知道。在 x86 上什么更快?MAX_VAL 的什么值可以证明第二个实现是合理的?

大约每 50us 调用一次,因此减少指令集并不是一个坏主意。if(++counter >= MAX_VAL) 将被预测为 false,因此在绝大多数情况下它将删除对 0 的赋值。出于我的目的,我更喜欢 %= 实现的一致性。

c x86 assembly micro-optimization

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

现代x86处理器中的指令融合是什么?

我了解的是,指令融合有两种类型:

  1. 微操作融合
  2. 宏操作融合

微操作是指可以在1个时钟周期内执行的操作。如果几个微操作融合在一起,我们将获得一个“指令”。

如果融合了多条指令,我们将获得宏操作。

如果几个宏操作融合在一起,我们将获得宏操作融合。

我对么?

x86 assembly cpu-architecture

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

为什么 x86 通常不允许目标寄存器不是第一个源寄存器?

在RISC-V中,可以Regs[x1] <- Regs[x2]+Regs[x3]使用指令执行整数运算

add x1,x2,x3
Run Code Online (Sandbox Code Playgroud)

在 x86 中,相同的操作显然需要两条指令,

mov x1,x2
add x1,x3
Run Code Online (Sandbox Code Playgroud)

该模式对于 x86 中的其他基本指令(例如、和 )src1 <- src1 op src2似乎很常见。然而,x86 确实有浮点数的eg 。andorsubdest <- src1 op src2add

是双指令模式mov x1,x2op x1,x3; 通常将宏融合到单个微操作中?或者,对于这些操作来说,独立目标是如此不常见,以至于 x86 架构不会费心在单个 uop 中允许它?如果是这样,禁止独立目的地会带来什么效率?

x86 assembly cpu-architecture riscv

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

有没有更好的方法来检测 16 字节标志数组中设置的位?

    ALIGNTO(16) uint8_t noise_frame_flags[16] = { 0 };

    // Code detects noise and sets noise_frame_flags omitted

    __m128i xmm0            = _mm_load_si128((__m128i*)noise_frame_flags);
    bool    isNoiseToCancel = _mm_extract_epi64(xmm0, 0) | _mm_extract_epi64(xmm0, 1);

    if (isNoiseToCancel)
        cancelNoises(audiobuffer, nAudioChannels, audio_samples, noise_frame_flags);
Run Code Online (Sandbox Code Playgroud)

这是我在 Linux 上的 AV Capture 工具的代码片段。这里的noise_frame_flags是16通道音频的标志数组。对于每个通道,相应的字节可以是 0 或 1。1 表示该通道有一些噪声需要消除。例如,如果noise_frame_flags[0] == 1,则意味着设置了第一个通道噪声标志(通过省略的代码)。

即使设置了一个“标志”,我也需要调用cancelNoises. 这段代码在这方面似乎工作得很好。正如您所看到的,我曾经_mm_load_si128加载正确对齐的整个标志数组,然后加载两个_mm_extract_epi64来提取“标志”。我的问题是有更好的方法来做到这一点(也许使用流行计数)?

注意:ALIGNTO(16)是一个宏扩展以纠正 GCC 等效项,但外观更好。

c++ sse x86-64 simd micro-optimization

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