标签: bmi

关于bsr和lzcnt的困惑

我对这两个指令都有点困惑.首先,让我们丢弃的特殊情况下,当扫描的值是0和未定义/ BSR或bitsize/lzcnt结果 - 这种差异是明显的,而不是我的问题的一部分.

我们来看二进制值 0001 1111 1111 1111 1111 1111 1111 1111

根据英特尔的规格,结果为lzcnt3

根据英特尔的规格,结果为bsr28

lzcntcount,bsr从位0返回索引或距离(即lsb).

两个指令如何相同,如何在CPU上没有可用的BMI的情况下lzcnt进行仿真bsr?或者bsr在msb的情况下是0位?英特尔规范中的"代码操作"也不同,一个是左边的计数或索引,另一个来自右边.

也许有人可以提供一些线索这光,我没有CPU无BMI/lzcnt指令测试,如果退回到bsr同样的结果作品(如值为0的特殊情况下扫描从未发生过).

x86 assembly bmi

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

如何使用x86intrin.h

在我的一个应用程序中,我需要有效地对长数据流中的位进行解交织。理想情况下,我想使用BMI2 pext_u32()和/或pext_u64()x86_64内部指令(如果可用)。我在x86intrin.hGCC)上搜索了互联网上的文档,但在该主题上找不到太多东西;因此,我要求StackOverflow上的专家帮助我。

  1. 在哪里可以找到有关如何使用函数的文档x86intrin.h
  2. gcc的实现pext_*()背后是否已经有代码可以使用,还是我需要自己编写后备代码(用于条件编译)?
  3. 如果目标不支持内在函数,是否有可能编写一个二进制文件,该二进制文件会自动退回到备用实现?如果是这样,怎么做?
  4. 是否存在一种已知的编程模式,当启用并启用优化时,GCC会识别该模式并将其自动转换为?pext_*()-mbmi2

c gcc x86-64 intrinsics bmi

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

像 PEXT 这样的汇编指令实际上有什么用途?

我观看了有关十大最疯狂汇编语言指令的 YouTube 视频,其中一些指令对我来说没有明显的应用。像这样的东西有什么意义PEXT,它只取第二个参数中与第一个参数中的 1 索引相匹配的位?编译器如何知道何时使用该指令?关于无进位乘法的相同/相似问题。

免责声明:我对汇编语言知之甚少甚至一无所知。也许我应该读一下它!

我希望这个问题适合 stackoverflow。

x86 assembly bit-manipulation bmi

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

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

在位掩码中选择与选择器位图中的1位重叠的设置位的跨度

鉴于:

  • 一种位掩码a(例如std::uint64_t),其中至少包含一组(1)位。
  • 一种选择器位掩码b,它是aa & b == b)的子集,并至少设置了一位。

我想选择连续的1位跨度,a其中与1位重叠b

a = 0b1111001110001100;
b = 0b0000001010001000;
//c=0b0000001110001100
//    XXXX  YYY   ZZ
Run Code Online (Sandbox Code Playgroud)

XXXX组为0,c因为b & XXXX为false。复制ZZ组,因为b设置了Z位之一。c出于同样的原因,也设置了YYY组。 请注意,b的单个组中可以有多个设置位a

因此,对于1s in中的每个连续组a,将cif b中的所有这些位设置为1在这些位置中的任何位置。一个更复杂的示例:

std::uint64_t a = 0b1101110110101;
std::uint64_t b = 0b0001010010001;
// desired   c == 0b0001110110001
// contiguous groups   ^^^ …
Run Code Online (Sandbox Code Playgroud)

c++ x86 bit-manipulation bmi

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

不使用BMI2的便携式有效替代PDEP?

英特尔位操作指令集2(BMI2)中的并行存款指令(PDEP)的文档描述了该指令的以下串行实现(类似C的伪代码):

U64 _pdep_u64(U64 val, U64 mask) {
  U64 res = 0;
  for (U64 bb = 1; mask; bb += bb) {
    if (val & bb)
      res |= mask & -mask;
    mask &= mask - 1;
  }
  return res;
}
Run Code Online (Sandbox Code Playgroud)

另请参阅英特尔的pdepinsn参考手册.

该算法是O(n),其中n是设置位的数量mask,这显然具有O(k)的最坏情况,其中k是总的位数mask.

更有效的最坏情况算法是否可行?

是否有可能制作一个更快的版本,假设val最多有一个位设置,即等于0或等于0到63之间的1<<r某个值r

algorithm x86 assembly bit-manipulation bmi

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

如何让 Rust 编译器发出 BZHI 指令而不诉诸特定于平台的代码?

Rust 编译器和 LLVM 有时非常聪明。我曾经x = x & (x - 1)清除最低有效设置位。它识别了这个表达式并将其转换为blsr内在函数,并给我带来了很大的加速。而且我不必使用任何特定于平台的代码或显式调用内在函数。

我想让它对bzhi内在函数做同样的事情,它将从位索引位置开始的高位归零。执行此操作的规范表达式是,src & (1 << inx) - 1但不幸的是 Rust 无法识别它,而是发出五个指令,而不是一条指令。它知道指令,但不识别等效项。

我如何鼓励 Rust 编译器发出bzhi内在函数而不显式转到特定于平台的代码?

铁锈1.66.1,-C opt-level=3 -C target-cpu=native

assembly x86-64 llvm rust bmi

5
推荐指数
0
解决办法
189
查看次数

多重操作

如何不用循环来实现对位掩码的操作,这两个位掩码ab宽度的n给位掩码c宽度2 * n有以下特性:

  • i个位c只能设置是否有j在个位a,并k在第位bj + k == i

C++实现:

#include <bitset>
#include <algorithm>
#include <iostream>

#include <cstdint>
#include <cassert>

#include <x86intrin.h>

std::uint64_t multishift(std::uint32_t a, std::uint32_t b)
{
    std::uint64_t c = 0;
    if (_popcnt32(b) < _popcnt32(a)) {
        std::swap(a, b);
    }
    assert(a != 0);
    do {
        c |= std::uint64_t{b} << (_bit_scan_forward(a) + 1);
    } while ((a &= (a - 1)) …
Run Code Online (Sandbox Code Playgroud)

c++ x86 bit-manipulation bitwise-operators bmi

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

编译器宏以检测BMI2指令集

我在网上搜索以找到合适的解决方案,但没有成功。因此,我希望你们中的一些人对此有所了解:是否有任何方法可以检测“ Intel Bit Manipulation Instruction Sets 2 ”(BMI2)的编译时间?我想根据其可用性做出一些有条件的事情。

c++ x86 intel instruction-set bmi

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

mulx 指令的内在特征

mulx指令是从 Haswell 处理器开始随 BMI2 指令集引入的。

根据英特尔的文档,应该有一个内在的mulx

unsigned __int64 umul128(unsigned __int64 a, unsigned __int64 b, unsigned __int64 * hi);
Run Code Online (Sandbox Code Playgroud)

然而,我在BMI2 或一般情况下的英特尔在线内在指南中没有发现这样的内在。不过,我确实从 ADX 指令集中找到了 addcarry 内在函数。

根据此链接,内在是mulx_u64,但我也没有找到那个。

MSVC 在 MSVC 2005 中添加了_umul128 内在函数,但这只产生mul而不产生mulx(我不知道如何在 MSVC 中启用 BMI2)。

我可以在 GCC 中mulx使用(或) 间接生成指令,但我更喜欢使用内在函数更直接地执行此操作。__int128-mbmi2-march=haswell

为什么 ADX 内在函数存在,但不存在英特尔文档mulx中定义的for ?

x86 gcc icc intrinsics bmi

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

x64 支持是否意味着 BMI1 支持?

可以安全地假设 x64 构建可以使用TZCNT而无需通过 cpu 标志检查其支持吗?

assembly x86-64 instruction-set bmi

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

什么是在软件中模拟 PDEP 和 PEXT 的快速回退算法?

我想围绕 x86 指令PDEP(并行位存储)PEXT(并行位提取)创建一个包装器。在这些不可用的架构上(并且相应的内在函数也不可用),我需要一个快速的回退实现。

32 位整数的朴素算法如下所示:

constexpr std::uint32_t bit_deposit(std::uint32_t src, std::uint32_t mask) {
    std::uint32_t result = 0;
    for (std::uint32_t src_pos = 0, mask_pos = 0; mask_pos != 32; ++mask_pos) {
        if (mask >> mask_pos & 1) {
            result |= (src >> src_pos++ & 1) << mask_pos;
        }
    }
    return result;
}

static_assert(bit_deposit(0b000, 0b000000) == 0b000000);
static_assert(bit_deposit(0b101, 0b101010) == 0b100010);
static_assert(bit_deposit(0b111, 0b101010) == 0b101010);
Run Code Online (Sandbox Code Playgroud)
constexpr std::uint32_t bit_extract(std::uint32_t src, std::uint32_t mask) {
    std::uint32_t result = 0;
    for (std::uint32_t src_pos = …
Run Code Online (Sandbox Code Playgroud)

c++ optimization x86 bit-manipulation bmi

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