VPERMIL2PS 和 VPERMIL2PD 所有 PERMIL2 指令都消失了——替换缺失的指令

VPERMIL2PS and VPERMIL2PD All PERMIL2 instructions are gone - Replacement of missing instructions

如何替换缺少的 VPERMIL2PS 指令,使用 AVX2 中的等效指令?

VPERMIL2PS ymm1, ymm2, ymm3, ymm4/m256, imz2

使用 ymm4/mem 中的控件置换 ymm2 和 ymm3 中的单精度浮点值,结果存储在带有 select 个零匹配控件的 ymm1 中。

VPERMIL2PS (VEX.256 encoded version)
DEST[31:0]  sel_and_condzerosp(SRC1[127:0], SRC2[127:0], SRC3[3:0])
DEST[63:32]  sel_and_condzerosp(SRC1[127:0], SRC2[127:0], SRC3[35:32])
DEST[95:64]  sel_and_condzerosp(SRC1[127:0], SRC2[127:0], SRC3[67:64])
DEST[127:96]  sel_and_condzerosp(SRC1[127:0], SRC2[127:0], SRC3[99:96])
DEST[159:128]  sel_and_condzerosp(SRC1[255:128], SRC2[255:128], SRC3[131:128])
DEST[191:160]  sel_and_condzerosp(SRC1[255:128], SRC2[255:128], SRC3[163:160])
DEST[223:192]  sel_and_condzerosp(SRC1[255:128], SRC2[255:128], SRC3[195:192])
DEST[255:224]  sel_and_condzerosp(SRC1[255:128], SRC2[255:128], SRC3[227:224])

Intel C/C++ 编译器内部等价物

VPERMIL2PS __m128 _mm_permute2_ps (__m128 a, __m128 b, __m128i ctrl, int imm)
VPERMIL2PS __m256 _mm256_permute2_ps (__m256 a, __m256 b, __m256i ctrl, int imm)

VPERMIL2PS ymm1, ymm2, ymm3,ymm4/m256, imz2 说明 - 使用 ymm4/mem 中的控件置换 ymm2 和 ymm3 中的单精度浮点值,结果存储在带有 select 个零匹配控件的 ymm1 中。 imz2:is4 立即字节的一部分,提供适用于双源置换指令的控制功能。

最接近的指令是 VPERMILPS .. 这条指令仍然有效

VPERMILPS (256-bit immediate version)
DEST[31:0]  Select4(SRC1[127:0], imm8[1:0]);
DEST[63:32]  Select4(SRC1[127:0], imm8[3:2]);
DEST[95:64]  Select4(SRC1[127:0], imm8[5:4]);
DEST[127:96]  Select4(SRC1[127:0], imm8[7:6]);
DEST[159:128]  Select4(SRC1[255:128], imm8[1:0]);
DEST[191:160]  Select4(SRC1[255:128], imm8[3:2]);
DEST[223:192]  Select4(SRC1[255:128], imm8[5:4]);
DEST[255:224]  Select4(SRC1[255:128], imm8[7:6]);

VPERMILPS ymm1, ymm2, ymm3/m256 描述 - RVM V/V AVX 使用来自 ymm3/mem 的控件置换 ymm2 中的单精度浮点值并将结果存储在 ymm1.

我也不好说到底怎样才对,因为为了可靠性,你需要模仿指令VPERMIL2PS,所以我呼吁当地专家!

最近的英特尔(R) AVX 架构更改 2009 年 1 月 29 日 删除:VPERMIL2PS 和 VPERMIL2PD

所有 PERMIL2 指令都消失了——包括 128 位和 256 位版本。就像下面的 FMA,他们使用 VEX.W 位来 select 哪个源来自内存——我们不再朝着使用 VEX.W 的方向发展。

英特尔编译器不理解这条 VPERMIL2PS 指令。

AVX-512 指令需要最新的处理器,这不是一个通用的解决方案.. visual studio 成功地汇编了这条指令,但是指令无法执行处理器,抛出异常。

反汇编代码

align 20h;
Yperm_msk ymmword 000000000100000006000000070000000C0000000D0000000A0000000B000000h

                vmovups ymm0, [rbp+920h+var_8C0]
                vmovdqu ymm1, Yperm_msk
                vpermil2ps ymm0, ymm0, [rbp+920h+var_880], ymm1, 920h+var_920
                vmovups [rbp+920h+var_1A0], ymm0

指令的完整描述

运营

select2sp(src1, src2, sel) // This macro is used by another macro “sel_and_condzerosp“ below
{
if (sel[2:0]=0) then TMP  src1[31:0]
if (sel[2:0]=1) then TMP  src1[63:32]
if (sel[2:0]=2) then TMP  src1[95:64]
if (sel[2:0]=3) then TMP  src1[127:96]
if (sel[2:0]=4) then TMP  src2[31:0]
if (sel[2:0]=5) then TMP  src2[63:32]
if (sel[2:0]=6) then TMP  src2[95:64]
if (sel[2:0]=7) then TMP  src2[127:96]
return TMP
}
sel_and_condzerosp(src1, src2, sel) // This macro is used by VPERMIL2PS
{
TMP[31:0]  select2sp(src1[127:0], src2[127:0], sel[2:0])
IF (imm8[1:0] = 2) AND (sel[3]=1) THEN TMP[31:0]  0
IF (imm8[1:0] = 3) AND (sel[3]=0) THEN TMP[31:0]  0
return TMP
}

VPERMIL2PS(VEX.256编码版本)

DEST[31:0]  sel_and_condzerosp(SRC1[127:0], SRC2[127:0], SRC3[3:0])
DEST[63:32]  sel_and_condzerosp(SRC1[127:0], SRC2[127:0], SRC3[35:32])
DEST[95:64]  sel_and_condzerosp(SRC1[127:0], SRC2[127:0], SRC3[67:64])
DEST[127:96]  sel_and_condzerosp(SRC1[127:0], SRC2[127:0], SRC3[99:96])
DEST[159:128]  sel_and_condzerosp(SRC1[255:128], SRC2[255:128], SRC3[131:128])
DEST[191:160]  sel_and_condzerosp(SRC1[255:128], SRC2[255:128], SRC3[163:160])
DEST[223:192]  sel_and_condzerosp(SRC1[255:128], SRC2[255:128], SRC3[195:192])
DEST[255:224]  sel_and_condzerosp(SRC1[255:128], SRC2[255:128], SRC3[227:224])

Bochs 模拟这条指令的方式

class bxInstruction_c;

void BX_CPP_AttrRegparmN(1) BX_CPU_C::VPERMIL2PS_VdqHdqWdqIbR(bxInstruction_c *i)
{
  BxPackedYmmRegister op1 = BX_READ_YMM_REG(i->src1());
  BxPackedYmmRegister op2 = BX_READ_YMM_REG(i->src2());
  BxPackedYmmRegister op3 = BX_READ_YMM_REG(i->src3()), result;
  unsigned len = i->getVL();

  result.clear();

  for (unsigned n=0; n < len; n++) {
    xmm_permil2ps(&result.ymm128(n), &op1.ymm128(n), &op2.ymm128(n), &op3.ymm128(n), i->Ib() & 3);
  }

  BX_WRITE_YMM_REGZ_VLEN(i->dst(), result, len);

  BX_NEXT_INSTR(i);
}

BX_CPP_INLINE void xmm_permil2ps(BxPackedXmmRegister *r, const BxPackedXmmRegister *op1, const BxPackedXmmRegister *op2, const BxPackedXmmRegister *op3, unsigned m2z)
{
  for(unsigned n=0; n < 4; n++) {
    Bit32u ctrl = op3->xmm32u(n);
    if ((m2z ^ ((ctrl >> 3) & 0x1)) == 0x3)
      r->xmm32u(n) = 0;
    else
      r->xmm32u(n) = (ctrl & 0x4) ? op1->xmm32u(ctrl & 0x3) : op2->xmm32u(ctrl & 0x3);
  }
}

它们不是 "gone",它们从一开始就不存在于任何真实的 CPU 中。 2009 年是第一个 CPU AVX1 发布之前,当时 AVX 仍处于规划阶段。 IDK 你在看什么,甚至提到了它们。

ISA 参考手册的当前版本,或 HTML extracts of it don't mention it. Neither does Intel's intrinsics guide。也许是 Sandybridge 发布之前的 "future extensions" 手册的 10 年前版本?

because for reliability, you need to emulate the instruction VPERMIL2PS

不,你不知道,它从一开始就不存在,所以没有使用它的代码。(或者很少;可能有些是基于早期的预测而编写的-发布 AVX 文档)。对于任何给定的问题,您只需要准确地实现所需的功能。

您标记了此 (AMD) XOP,但您只引用了 Intel 文档;我认为 XOP 确实有一些 2 输入洗牌,但我没有去查看文档。当然只适用于 128 位向量。


AVX1 确实有一些 2 输入随机播放,但 none 具有可变控制。 vshufps/pd with immediate control, and vunpckl/hps...pd 执行相应 128 位随机播放的两个单独的通道内版本。

最坏的情况,您可以从 2x vshufps + vblendps. 中构建任何固定的 2 输入通道内洗牌,最好的情况是一个vshufps,或中间是 vshufps + vblendps 或 2x vshufps(例如,将您想要的元素收集到一个向量中,然后将它们按正确的顺序排列)。任何 vshufps 洗牌都可以是 vunpcklpshps。请记住,立即 vblendps 很便宜,但洗牌在 Intel 上只有 1/clock 吞吐量(Ice Lake 之前只有端口 5)。

您甚至可以使用变量控制 2x vpermilps 并比较或移位 + vblendvps 来模拟 vpermil2ps,因为 vpermilps 会忽略索引中的高位。因此,这将是 (ctrl & 0x4) ? op2[ctrl & 0x3] : op2[ctrl & 0x3]; 的 BOCHS 实现,其中您将 ctrl 上的两个输入与 vpermilps 混洗(隐含地只查看低 2 位),然后混合 ctrl & 4 通过整数移位将该位移到顶部。

(可选地,还可以通过使用 vpslld 将第 3 个索引位放在混合的顶部,以及 vpsrad 或与零进行比较来使用 vandps 模拟条件归零结果为 vpand 创建一个 AND 掩码。或者在 Skylake 上,vblendvps 对任何端口都是 2 微指令,因此您可以使用它来混合零而不是 shift/and 或 cmp/and).

但是,如果您关心编译时常量随机播放控件的性能,请不要天真地将其放入。而是从可用的 2 输入操作中构建等效的洗牌。这就是为什么我懒得用 C 编写完整的实现。


AVX2 只添加了一些可能在这里有用的新的 2 输入洗牌:256 位 vpalignr 就像 2 个通道内 palignr 指令。它还添加了整数 vpunpckl/h b/w/d/q 但我们已经从 AVX1 获得了 vunpckl/hps


直到 AVX512F vpermt2psvpermi2ps/pd.

才出现真正的可变控制 2 输入随机播放

但它不支持基于索引元素高位的条件置零,例如 pshufb 或提议的 vpermil2ps;而是使用掩码寄存器进行零掩码。例如

  vmovd2m    k1, ymm0                              ; extract top bit of dword elements
  knotw      k1, k1                                ; cleared for elements to be zeroed
  vpermi2ps  ymm0{k1}{z}, ymm0, ymm1, ymm2         ; ymm0=indices   ymm1,ymm2 = table
  ; indices overwritten with result
  ; use vpermt2ps instead to overwrite one of the "table" inputs instead of the index vector.

或者最好使用 vpfclassps k1, ymm0, some_constant 来为非负值设置 k1,避免需要 knot。在 Skylake-X 上,它是一个 uop。

或者使用 vptestnmdset1(1UL<<31) 掩码来设置向量的掩码寄存器 = !signbit


它也不是 "in lane",因此您可能需要调整索引,我认为为索引 > 4 添加 8。 vpermi/t2ps 索引到两个向量的串联中,因此在选择另一个输入之前发生一个源内的交叉通道。