在 SSE 中组合前缀

Posted

技术标签:

【中文标题】在 SSE 中组合前缀【英文标题】:Combining prefixes in SSE 【发布时间】:2010-03-08 20:09:34 【问题描述】:

在 SSE 中,前缀 066h(操作数大小覆盖)0F2H (REPNE) 和 0F3h (REPE) 是操作码的一部分。

在非 SSE 中 066h 在 32 位(或 64 位)和 16 位操作之间切换。 0F2h0F3h 用于字符串操作。它们可以组合在一起,以便066h0F2h(或0F3h)可以在同一条指令中使用,因为这是有意义的。 SSE 指令中的行为是什么?例如,我们有(暂时忽略 mod/rm):

0f 58      addps
66 0f 58   addpd
f2 0f 58   addsd
f3 0f 58   addss

但这是什么?

66 f2 0f 58

然后呢?

f2 66 0f 58

更不用说以下有两个冲突的 REP 前缀:

f2 f3 0f 58

这些的规格是什么?

【问题讨论】:

不是 f3 0f 58 ADDSS 而不是 ADDPD? 【参考方案1】:

我不记得看过任何关于在广泛组合随机前缀的情况下应该期待什么的规范,所以我猜 CPU 行为可能是“未定义的”并且可能是特定于 CPU 的。 (很明显,英特尔的文档中指定了一些内容,但许多情况并未涵盖)。并且可能会保留一些组合以供将来使用。

我的天真假设通常是额外的前缀是无操作的,但不能保证。这似乎是合理的,例如一些优化手册推荐多字节NOP(规范为90h),前缀为66h,例如:

db 66h, 90h; 2-byte NOP
db 66h, 66h, 90h; 3-byte NOP
db 66h, 66h, 66h, 90h; 4-byte NOP

但是,我也知道 CSDS 段覆盖前缀具有作为 SSE2 分支提示前缀的新功能(预测分支采用 = 3Eh = DS 覆盖;预测未采用分支 = 2Eh = CS override) 应用于条件跳转指令时。

无论如何,我看了你上面的例子,总是将XMM1 设置为所有0XMM7 设置为所有0FFh by

pxor xmm1, xmm1    ; xmm1 <- 0s
pcmpeqw xmm7, xmm7 ; xmm7 <- FFs 

然后是有问题的代码,带有xmm1, xmm7 参数。我观察到的(Win64 系统和 Intel T7300 Core 2 Duo 上的 32 位代码)是:

1) 通过添加 66h 前缀,addsd 没有观察到变化

db 66h 
addsd xmm1, xmm7 ;total sequence = 66 F2 0F 58 CF     

2) 通过添加 0F2h 前缀,addss 没有观察到变化

db 0f2h     
addss xmm1,xmm7 ;total sequence = F2 F3 0F 58 CF

3) 但是,我通过在 addpd 前加上 0F2h 观察到了变化:

db 0f2h    
addpd xmm1, xmm7 ;total sequence = F2 66 0F 58 CF

在这种情况下,XMM1 中的结果是 0000000000000000FFFFFFFFFFFFFFFFh 而不是 FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFh

所以我的结论是,不应做出任何假设并期待“未定义”的行为。不过,如果您能在 Agner fog 的 manuals 中找到一些线索,我不会感到惊讶。

【讨论】:

在最后一种情况下,显然0F2h优先于066h,并将指令转换为addsd,这就是为什么只写了一个块。 这是一个假设,是的。但是,我认为如果有人想依赖这种行为,那将是一个坏主意。【参考方案2】:

英特尔的 SDM vol.2 手册(指令集参考)将这些称为强制前缀。将它们视为操作码的一部分。

但是是的,它们前缀并且可以在实际的转义字节+操作码之前与其他前缀混合。事实上,REX 前缀必须跟在其他前缀之后。

像往常一样,使用来自同一组的多个冲突前缀恰好会解码,而最后一个前缀在当前的英特尔硬件上具有优先权。我认为英特尔手册说这样做会产生不可预测的行为,因此它保证或未来证明。这不是一件有意义的事情;如果您出于对齐原因想要填充指令以使其更长,我认为重复 same 前缀几次是安全的。

B.8 SSE INSTRUCTION FORMATS AND ENCODINGS

SSE 指令使用 ModR/M 格式并以 0FH 开头 前缀字节。一般来说,操作不重复提供两个 方向(即,单独的加载和存储变体)。

以下三个表(表 B-22、B-23 和 B-24)显示了 SSE SIMD 浮点、SIMD 整数的格式和编码, 和可缓存性和内存排序指令,分别。 一些 SSE 指令需要强制前缀(66H、F2H、F3H)作为 两字节操作码。表中包含强制性前缀。


还有

2.1.2 操作码

主操作码的长度可以是 1、2 或 3 个字节。一个额外的 3 位操作码字段有时被编码在 ModR/M 字节。可以在主操作码中定义较小的字段。这些字段定义了操作方向、位移大小、寄存器编码、条件代码或符号扩展。使用的编码字段 操作码因操作类别而异。

通用指令和 SIMD 指令的双字节操作码格式包含以下内容之一:

一个转义操作码字节 0FH 作为主操作码和第二个操作码字节。 强制前缀(66HF2HF3H)、转义操作码字节和第二个操作码字节(与前面的相同) 子弹)。

例如,CVTDQ2PD 由以下序列组成:F3 0F E6第一个字节是强制前缀(不是 被视为重复前缀)。 通用指令和 SIMD 指令的三字节操作码格式包含以下内容之一:

一个转义操作码字节 0FH 作为主操作码,外加两个额外的操作码字节。 一个强制前缀(66H、F2H 或 F3H),一个转义操作码字节,加上两个额外的操作码字节(与 上一个项目符号)。

例如,用于 XMM 寄存器的 PHADDW 由以下序列组成:66 0F 38 01。第一个字节是强制前缀。

【讨论】:

以上是关于在 SSE 中组合前缀的主要内容,如果未能解决你的问题,请参考以下文章

异或前缀和,组合数学——cf1054D

Luogu P2822 组合数问题(前缀和)

[M前缀和] lc1014. 最佳观光组合(思维+前缀和+算法优化)

基础数学问题 P2822 组合数问题前缀和

基础数学问题 P2822 组合数问题前缀和

[题解](组合数/矩阵的前缀和)luogu_P2822组合数问题