Optimization 创建掩蔽kreg值的有效方法

Optimization 创建掩蔽kreg值的有效方法,optimization,x86,simd,avx512,Optimization,X86,Simd,Avx512,Intel的AVX-512扩展的一个好处是,除了向量寄存器外,还可以提供一个kreg来指定要应用于操作的掩码,从而几乎可以屏蔽所有操作:掩码排除的元素可以设置为零,也可以保留其以前的值 kreg的一个特别常见的用途是创建一个掩码,该掩码在向量的开始或结束处排除N个连续元素,例如,作为向量化循环中的第一次或最后一次迭代,其中将处理少于完整向量。例如,对于121int32\t值上的循环,前112个元素可由7个完整的512位向量处理,但剩下9个元素可由仅对前9个元素进行操作的屏蔽操作处理 因此,问题是

Intel的AVX-512扩展的一个好处是,除了向量寄存器外,还可以提供一个kreg来指定要应用于操作的掩码,从而几乎可以屏蔽所有操作:掩码排除的元素可以设置为零,也可以保留其以前的值

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

因此,问题是,给定一个(运行时值)整数
r
,它是0-16范围内表示剩余元素的某个值,加载16位kreg的最有效方法是什么,以便设置低位
r
位,而不设置剩余位
KSHIFTLW
似乎不适合此用途,因为它只需要一个立即数。

正是您想要的:从指定位位置开始的零高位。到目前为止,每个使用AVX512的CPU都有BMI2

__mmask16 k = _bzhi_u32(-1UL, r);
这需要2条指令,包括单uop:mov立即指令和
BZI
。甚至是单周期延迟。(或KNL上的3个循环)

  • 对于
    r=0
    ,它将给出0的所有位置零
  • 对于
    r=1
    ,它只保留低位(位0)表示1
  • 对于
    r=12
    ,它将位#12或更高归零,留下
    0x0FFF
    (设置了12位)
  • 对于
    r>=32
    BZHI保留所有32位设置(并设置CF)
索引由第二个源操作数的位7:0指定

如果在展开的向量循环之后有一个一次一个向量的清理循环,您甚至可以在每次循环迭代中使用该循环,将剩余长度向下计数到零,而不是单独的最后一个向量清理。它将所有位设置为高长度。但这在循环内需要2个UOP,包括端口5
kmovw
,这意味着您的主循环必须使用屏蔽指令。这只适用于rI ASSUBE/hope
(~0)>>(16-r)
高效编译为32位MOV immediate+SHRX+KMOVW。呃,我猜这里也有一个sub或neg,x86移位只能通过
&31
来屏蔽计数,而不是
&15
来屏蔽15位移位。英特尔CPU上更好的序列可能是xor(异或)-zero/BTS/DEC/kmovw的可能重复序列。