【问题标题】:Efficient way to create masking kreg values [duplicate]创建掩蔽 kreg 值的有效方法 [重复]
【发布时间】:2019-11-19 04:55:33
【问题描述】:

英特尔的 AVX-512 扩展的一个好处是,除了向量寄存器之外,几乎所有操作都可以通过提供一个 kreg 来屏蔽,该 kreg 指定了应用于操作的屏蔽:排除的元素通过掩码可以设置为零或保留其先前的值。

kreg 的一个特别常见的用途是创建一个掩码,该掩码在向量的开头或结尾排除 N 个连续元素,例如,作为向量化循环中的第一次或最后一次迭代,其中将处理少于完整向量的向量.例如,对于超过 121 个int32_t 值的循环,前 112 个元素可以由 7 个完整的 512 位向量处理,但剩下的 9 个元素可以通过仅对前 9 个元素进行操作的掩码操作来处理。

所以问题是,给定一个(运行时值)整数 r,它是 0 - 16 范围内的某个值,代表剩余元素,加载 16 位 kreg 的最有效方法是什么,使得低 @987654324 @ 位已设置,其余位未设置? KSHIFTLW 似乎不适合这个目的,因为它只需要立即。

【问题讨论】:

  • 我假设/希望(~0) >> (16-r) 可以有效地编译为 32 位 MOV-immediate + SHRX + KMOVW。错误我猜那里也有一个 sub 或 neg,x86 移位仅用 &31 掩盖它们的计数,而不是 &15 用于 15 位移位。英特尔 CPU 上的更好序列可能是 xor-zero / BTS / DEC / KMOVW
  • this question 的可能重复项。

标签: optimization x86 simd avx512


【解决方案1】:

BMI2 bzhi 完全符合您的要求:从指定位位置开始的零高位。到目前为止,每个带有 AVX512 的 CPU 都有 BMI2。

__mmask16 k = _bzhi_u32(-1UL, r);

这需要 2 条指令,都是单微指令:mov-immediate 和 bzhi。它甚至是单周期延迟。 (或在 KNL 上 3 个周期)

  • 对于r=0,它会将所有位归零,给出 0。
  • 对于r=1,它只留下低位(位#0)给出1
  • 对于r=12,它会将第 12 位及更高位清零,留下 0x0FFF(设置 12 位)
  • 对于r>=32 BZHI 保留所有 32 位设置(并设置 CF)

INDEX 由第二个源操作数的位 7:0 指定

如果您有一个在展开的向量循环之后运行的一次单个向量清理循环,您可以甚至在每次循环迭代时都使用它,将剩余长度向下计数为零,而不是单独的最后一个向量清理。它将所有位设置为高长度。但这会在循环内消耗 2 微指令,包括端口 5 kmovw,这意味着您的主循环必须使用屏蔽指令。这仅适用于 rmov reg, -1 可以被提升,因为bzhi 不会破坏它。


PS。通常我认为您希望安排清理以处理 1..16 个元素(如果您分支可能跳过它,则为 0..15 个)。但是,如果此清理还处理根本不进入主循环的小长度,并且 len=0 是可能的,那么完整的 17 种可能性 0..16 是有意义的。 (并且您的主循环以剩余长度 = 1..16 退出,因此最终迭代可以是无条件的)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-08-18
    • 2016-08-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多