相关疑难解决方法(0)

为什么破坏LZCNT的"输出依赖性"很重要?

在测量某些东西的同时,我测量的吞吐量比我计算的要低得多,我将其缩小到LZCNT指令(它也发生在TZCNT中),如以下基准所示:

  xor ecx, ecx
_benchloop:
  lzcnt eax, edx
  add ecx, 1
  jnz _benchloop
Run Code Online (Sandbox Code Playgroud)

和:

  xor ecx, ecx
_benchloop:
  xor eax, eax  ; this shouldn't help, but it does
  lzcnt eax, edx
  add ecx, 1
  jnz _benchloop
Run Code Online (Sandbox Code Playgroud)

第二个版本要快得多.它不应该.LZCNT没有理由对其输出有输入依赖性.与BSR/BSF不同,xZCNT指令总是覆盖其输出.

我在4770K上运行它,所以LZCNT和TZCNT没有被执行为BSR/BSF.

这里发生了什么?

x86 assembly

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

如何使用MSVC内在函数来获得相当于这个GCC代码?

以下代码在GCC中调用clz/ctz的内置函数,在其他系统上调用C版本.显然,如果系统有内置的clz/ctz指令,如x86和ARM,则C版本有点不理想.

#ifdef __GNUC__
#define clz(x) __builtin_clz(x)
#define ctz(x) __builtin_ctz(x)
#else
static uint32_t ALWAYS_INLINE popcnt( uint32_t x )
{
    x -= ((x >> 1) & 0x55555555);
    x = (((x >> 2) & 0x33333333) + (x & 0x33333333));
    x = (((x >> 4) + x) & 0x0f0f0f0f);
    x += (x >> 8);
    x += (x >> 16);
    return x & 0x0000003f;
}
static uint32_t ALWAYS_INLINE clz( uint32_t x )
{
    x |= (x >> 1);
    x |= (x >> 2);
    x |= …
Run Code Online (Sandbox Code Playgroud)

c intrinsics visual-c++

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

x86 bsr/bsf如何具有固定的延迟,而不是数据依赖?它不像伪代码那样循环比特吗?

我正在试图分析一些x86二进制代码的"时序通道".我发布了一个问题来理解bsf/bsr操作码.

如此高级,这两个操作码可以被建模为"循环",它计算给定操作数的前导零和尾随零.该x86手册对这些操作码具有良好的形式化,如下所示:

IF SRC = 0
  THEN
    ZF ? 1;
    DEST is undefined;
  ELSE
    ZF ? 0;
    temp ? OperandSize – 1;
    WHILE Bit(SRC, temp) = 0
    DO
      temp ? temp - 1;
    OD;
    DEST ? temp;
FI;
Run Code Online (Sandbox Code Playgroud)

但令我惊讶的是,bsf/bsr指令似乎有固定的cpu周期.根据我在这里找到的一些文档:https://gmplib.org/~tege/x86-timing.pdf,似乎它们总是需要8个CPU周期来完成.

所以这是我的问题:

  1. 我确认这些指令有固定的cpu周期.换句话说,无论给出什么操作数,它们总是花费相同的时间来处理,并且没有"时序通道".我在英特尔的官方文档中找不到相应的规格.

  2. 那么为什么有可能呢?显然这是一个"循环"或某种程度,至少是高级别的.背后的设计决策是什么?CPU流水线更容易?

performance x86 assembly intel cpu-architecture

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

VS:_BitScanReverse64内在的意外优化行为

以下代码在调试模式下工作正常,因为如果没有设置Bit,_BitScanReverse64被定义为返回0.引用MSDN :(返回值为)"如果设置了索引则为非零,如果未找到设置位,则为0."

如果我在发布模式下编译此代码它仍然有效,但如果我启用编译器优化,例如\ O1或\ O2,则索引不为零且assert()失败.

#include <iostream>
#include <cassert>

using namespace std;

int main()
{
  unsigned long index = 0;
  _BitScanReverse64(&index, 0x0ull);

  cout << index << endl;

  assert(index == 0);

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

这是预期的行为吗?我正在使用Visual Studio Community 2015,版本14.0.25431.01更新3.(我离开了cout,因此在优化期间不会删除变量索引).还有一个有效的解决方法或我不应该直接使用此编译器内在?

c++ optimization x86-64 intrinsics visual-studio

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