X86 如何在xmm寄存器中旋转压缩四字?
给定一个包含两个四字(即两个64位整数)的128位X86 如何在xmm寄存器中旋转压缩四字?,x86,sse2,X86,Sse2,给定一个包含两个四字(即两个64位整数)的128位xmm寄存器: 如何对单个四字执行旋转?例如: prorqw xmm0, 32 // rotate right packed quadwords ╭──────────────────┬──────────────────╮ xmm0 │ bbaa9988ffeeddcc │ 3322110077665544 │ ╰──────────────────┴──────────────────╯ 我知道SSE2提供: P
xmm
寄存器:
如何对单个四字执行旋转?例如:
prorqw xmm0, 32 // rotate right packed quadwords
╭──────────────────┬──────────────────╮
xmm0 │ bbaa9988ffeeddcc │ 3322110077665544 │
╰──────────────────┴──────────────────╯
我知道SSE2提供:
:无序排列压缩的字(16位)PSHUFW
:无序压缩双字(32位)PSHUFD
xmm
寄存器的ROR
- 将右压缩双字旋转16位:
╭──────────┬──────────┬──────────┬──────────╮ xmm0 │ ffeeddcc │ bbaa9988 │ 77665544 │ 33221100 │ ╰──────────┴──────────┴──────────┴──────────╯ ⇓ ╭──────────┬──────────┬──────────┬──────────╮ xmm0 │ ddccffee │ 9988bbaa │ 55447766 │ 11003322 │ ╰──────────┴──────────┴──────────┴──────────╯
- 将右压缩字旋转8位:
╭──────┬──────┬──────┬──────┬──────┬──────┬──────┬──────╮ xmm0 │ ffee │ ddcc │ bbaa │ 9988 │ 7766 │ 5544 │ 3322 │ 1100 │ ╰──────┴──────┴──────┴──────┴──────┴──────┴──────┴──────╯ ⇓ ╭──────┬──────┬──────┬──────┬──────┬──────┬──────┬──────╮ xmm0 │ eeff │ ccdd │ aabb │ 8899 │ 6677 │ 4455 │ 2233 │ 0011 │ ╰──────┴──────┴──────┴──────┴──────┴──────┴──────┴──────╯
ymm
寄存器,您将如何执行上述操作
╭──────────────────────────────────┬──────────────────────────────────╮
ymm0 │ 2f2e2d2c2b2a29282726252423222120 │ ffeeddccbbaa99887766554433221100 │ packed doublequadwords
╰──────────────────────────────────┴──────────────────────────────────╯
╭──────────────────┬──────────────────┬──────────────────┬──────────────────╮
ymm0 │ 2f2e2d2c2b2a2928 │ 2726252423222120 │ ffeeddccbbaa9988 │ 7766554433221100 │ packed quadwords
╰──────────────────┴──────────────────┴──────────────────┴──────────────────╯
╭──────────┬──────────┬──────────┬──────────┬──────────┬──────────┬──────────┬──────────╮
ymm0 │ 2f2e2d2c │ 2b2a2928 │ 27262524 │ 23222120 │ ffeeddcc │ bbaa9988 │ 77665544 │ 33221100 │ packed doublewords
╰──────────┴──────────┴──────────┴──────────┴──────────┴──────────┴──────────┴──────────╯
╭──────┬──────┬──────┬──────┬──────┬──────┬──────┬──────┬──────┬──────┬──────┬──────┬──────┬──────┬──────┬──────╮
ymm0 │ 2f2e │ 2d2c │ 2b2a │ 2928 │ 2726 │ 2524 │ 2322 │ 2120 │ ffee │ ddcc │ bbaa │ 9988 │ 7766 │ 5544 │ 3322 │ 1100 │ packed words
╰──────┴──────┴──────┴──────┴──────┴──────┴──────┴──────┴──────┴──────┴──────┴──────┴──────┴──────┴──────┴──────╯
额外阅读
\u MM\u SHUFFLE(2,3,0,1)
,或者在asmpshufd xmm0、xmm0、0b10\u 11\u 00\u 01
(NASM支持将\u
作为可选分隔符,就像C++11用于数字文本一样。)
对于16个计数中的多个,对于没有SSSE3的函数版本来说并不坏,但是对于低/高qword,您需要单独的洗牌。(imm8控制字节仅包含四个2位字段。)或使用AVX2,用于每个通道内的奇数/偶数Q字
如果旋转计数不是8的倍数,则存在AVX512F和
vprorq
。也可在可变计数版本中使用,每元素计数来自另一个向量,而不是立即数<代码>vprolvq/vprorvq
。还提供dword粒度,但不提供字或字节
否则,如果只有SSE2和计数不是16的倍数,则需要左+右移位+或才能在asm中实际实现将C中的旋转表示为
(x>(64-n))
。(指出了从超出范围的移位计数中绕过潜在C UB的方法,这对于Intrinsic或asm来说不是问题,因为asm和Intrinsic的行为由Intel明确定义:SIMD移位使移位计数饱和,而不是像标量移位一样将其掩蔽。)
SSE2的移位粒度只有16位,所以您可以直接进行
对于字节粒度,您需要额外的屏蔽,以将字中字节之间移位的位归零。或者使用类似于
pmullw
的技巧,使用2个元素的幂向量,允许每个元素的计数可变。(其中AVX2通常只对dword/qword进行可变计数移位)。尽管我询问了执行右旋转的问题,但ROR的一个子集是当您执行两个64位值的ROR时正好是32位。这使您的任意旋转变成了高32位和低32位的简单交换:
知道您只是在执行32位(即,双字)交换,您可以使用其他指令:
- pshufd:将压缩的双字混洗
pshufd xmm0, xmm0, 0x02030001
因为我在推四个双字,所以掩码由四个块组成:
02
03
00
01
它们从左到右排列,告诉您32位双字应混洗到哪里的索引:
如果将压缩到xmm
寄存器中的64位四字旋转32位,则可以使用:
pshufd xmm0, xmm0, 0x02030001 //rotate packed quadwords by 32-bits¹
旋转光(16)
现在,如果:
- 而不是打包到xmm中的64位四字的ROR(32)
- 我想
ROR(16)
- 而不是打包到xmm中的64位四字的ROR(32)
- 我想
ROR(24)
我想。我不确定我的编码是否正确。如何使用
pshufd
将xmm0
中的两个四字旋转32位?@IanBoyd:交换每个四字的32位半。像\u MM\u SHUFFLE(2,3,0,1)
一样使用内部函数。或者直接在asm中,pshufd xmm0,xmm0,0b10_11_00_01
(您可能必须删除我在位对之间使用的
分隔符,除非您的汇编支持C++11样式的分隔符语法)。您链接到的“模糊文档”是《英特尔内部技术指南》。它的目的是用C或C++编写具有本质的人。对于4x 2位字段,始终可以使用\u MM\u SHUFFLE
宏。但是,如果您直接在asm中编写,则应参考英特尔第2卷指令集参考手册或类似的HTML摘录。这次手术很成功
pshufd xmm0, xmm0, 0x02030001 //rotate packed quadwords by 32-bits¹
pshufw xmm0, xmm0, 0x0605040702010003 //shuffle packed words¹