代码之家  ›  专栏  ›  技术社区  ›  YutakaAoki

对于“MOVMSKPD reg,xmm”中的reg=rbx,MASM中的编码“66|48/0F 50 D8”是否正确?

  •  0
  • YutakaAoki  · 技术社区  · 3 年前

    在里面 MOVMSKPD reg, xmm , VMOVMSKPD reg, xmm2 或 VMOVMSKPD reg, ymm2 我认为reg是r32或r64。

    但在MASM中,我进行了测试,得到了以下结果:

    MOVMSKPD rbx, xmm0  ;OK, 66| 48/ 0F 50 D8
    MOVMSKPD ebx, xmm0  ;OK, 66| 0F 50 D8
    

    我怀疑这个结果是否正确,尤其是因为它有“48前缀”。48小时是具有W位ON的REX前缀。

    相反,以下代码编码在完全相同的机器代码中,每个代码都带有VEX。W位为零。

    000004F9  C5 F9/ 50 D8          VMOVMSKPD rbx, xmm0
    000004FD  C5 F9/ 50 D8          VMOVMSKPD ebx, xmm0
    

    所有这些代码编码正确吗?

    我使用了ml64.exe。目标是x86_64(64-BIT模式)。

    [test2.asm]

    ;MOVMSKPD reg, xmm  ;66 0F 50 /r
    MOVMSKPD rbx, xmm0  ;OK, with a 48 prefix
    MOVMSKPD ebx, xmm0  ;OK, without a 48 prefix
        
    ;VMOVMSKPD reg, xmm2    ;VEX.128.66.0F.WIG 50 /r
    VMOVMSKPD rbx, xmm0 ;OK
    VMOVMSKPD ebx, xmm0 ;OK, but the same machine code as above.
        
    ;VMOVMSKPD reg, ymm2    ;VEX.256.66.0F.WIG 50 /r
    VMOVMSKPD rbx, ymm0 ;OK
    VMOVMSKPD ebx, ymm0 ;OK, but the same machine code as above.
    

    [测试2.lst]

    ;MOVMSKPD reg, xmm  ;66 0F 50 /r
     000004F0  66| 48/ 0F 50 D8     MOVMSKPD rbx, xmm0
     000004F5  66| 0F 50 D8         MOVMSKPD ebx, xmm0
                        
    ;VMOVMSKPD reg, xmm2    ;VEX.128.66.0F.WIG 50 /r
     000004F9  C5 F9/ 50 D8         VMOVMSKPD rbx, xmm0
     000004FD  C5 F9/ 50 D8         VMOVMSKPD ebx, xmm0
                        
    ;VMOVMSKPD reg, ymm2    ;VEX.256.66.0F.WIG 50 /r
     00000501  C5 FD/ 50 D8         VMOVMSKPD rbx, ymm0
     00000505  C5 FD/ 50 D8         VMOVMSKPD ebx, ymm0
    
    • 注: 我想指出一些不直接相关但可能相关的内容。

    关于操作数大小重写前缀(0x66)。
    在“英特尔手册PDF”中,我发现一句话:“此前缀与MMX、SSE和/或SSE2指令一起使用是保留的,可能会导致不可预测的行为。”

    http://gec.di.uminho.pt/Discip/Lesi/AC10203/docs/P4ISAformat.pdf

    第2章指令格式
    2.2.指令前缀
    操作数大小重写前缀允许程序在16位和32位操作数大小之间切换。
    任意一个操作数大小都可以是默认值。此前缀选择非默认大小。
    此前缀与MMX、SSE和/或SSE2指令一起使用是保留的,可能会导致不可预测的行为(请参阅下面的注释)。
    注释
    一些SSE和SSE2指令具有三字节操作码。 对于这三个字节的操作码,第三操作码字节可以是F2H、F3H或66H。
    例如,SSE2指令CVTQ2PD具有三字节操作码F3 0F E6。
    这三个字节操作码中的第三个操作码字节不应被视为前缀,即使它与操作数大小前缀(66H)或重复前缀之一(F2H和F3H)具有相同的编码。
    如上所述,保留将操作数大小和重复前缀与SSE和SSE2指令一起使用。
    还应注意的是,在不支持SSE2的英特尔处理器上执行SSE2指令(CPUID功能标志寄存器EDX位26已清除)将导致不可预测的代码执行。

    我认为REX。REX前缀的W比特类似于66前缀。
    所以我怀疑REX。W位只能在旧式指令中使用,不能在MMX、SSE和/或SSE2指令中自由使用(自行判断)。
    我认为在MMX/SSE/AVX指令中,如果REX,它可以安全地使用。W写在指令表的操作码列中,但如果是REX。W不是写在那里的,它不能用来自我判断。

    我认为如下:

    • 在传统指令中,可以使用REX。W位对于GPR几乎是自由的,尤其是对于目标操作数的大小。
    • 在MMX/SSE/SSE2/AVX/AVX2/AVX512中,不能使用REX。W自由位。

    PS1,2023/07/2401:38,JST

    AMD手册:AMD 64位技术,24108C-2001年1月

    结果的零扩展。
    在64位模式中,当使用GPR目标执行32位操作时,处理器零将32位结果扩展到完整的64位目标。
    对GPR的8位和16位操作保留目的地GPR的所有未写入的高位。
    这与部分宽度结果的传统16位和32位语义一致。

    英特尔手册: MOVMSKPD提取压缩双精度浮点符号掩码

    Operation  
    
    (V)MOVMSKPD (128-bit Versions)  
    DEST[0] := SRC[63]  
    DEST[1] := SRC[127]  
    IF DEST = r32  
        THEN DEST[31:2] := 0;  
        ELSE DEST[63:2] := 0;  
    FI  
      
    VMOVMSKPD (VEX.256 Encoded Version)  
    DEST[0] := SRC[63]  
    DEST[1] := SRC[127]  
    DEST[2] := SRC[191]  
    DEST[3] := SRC[255]  
    IF DEST = r32  
        THEN DEST[31:4] := 0;  
        ELSE DEST[63:4] := 0;  
    FI  
    

    在上文中,请注意以下内容

    IF DEST = r32
        THEN DEST[31:2] := 0;
        ELSE DEST[63:2] := 0;
    FI
    

    但根据AMD手册,在64-BIT模式下,如果目的地是32-BIT通用寄存器(GPR),则底层64-BIT GPR的上部32个BIT被清零。
    但根据英特尔手册,如果reg为32-BIT,则DEST[31:2]:=0;如果reg为64-BIT,那么DEST[63:2]:=0。
    我认为如果它使用REX遵循AMD的一般规则,这是不一致的。W位。
    如果它遵循AMD一般规则,如果目的地是32-BIT,则底层寄存器的高32位被清零,从而DEST[63:2]:=0。如果它是正确的,在手册中,写

    IF DEST = r32
      THEN DEST[31:2] := 0;
      ELSE DEST[63:2] := 0;
    FI
    

    没有意义,因为在这两种情况下,DEST[63:2]:=0。

    我的观点是“假设一切都是正确的”,如果指令 MOVMSKPD ebx, xmm0 存在于64-BIT模式中,则它不服从AMD的一般规则,因此它是不一致的。
    我使用了“矛盾证明”或荒诞还原的方法。

    ps22023/07/24,03:05,JST

    我认为:

    reg is r32 if cpu is in 32-BIT mode (compatible mode).
    reg is r64 if cpu is in 64-BIT mode (long mode).
    

    并且它不能被REX控制。W位或VEX。W位。

    我认为没有指示 MOVMSKPD ebx,xmm0 64-BIT模式或“英特尔手册”中的“操作伪码”在目标寄存器的高32位中不正确。根据AMD的一般规则,当CPU处于64-BIT模式时,如果目标操作数是32-BIT GPR,则底层64-BIT GPR的高32位被清零,但《英特尔手册》规定,如果DEST=r32,则底层64位GPR的高32比特被保留。

    ps32023/07/24,17:24,JST

    figure1

    ps42023/07/25 01:22,JST

    我在《英特尔手册》的附录B中找到了MOVMSKPS的编码,作为使用REX推广的特殊情况指令。W

    第2D卷B-63

    指令格式和编码

    B.13 64位模式的特殊编码

    以下奔腾、P6、MMX、SSE、SSE2、SSE3指令通过使用REX在IA-32e模式下升级为64位操作。W.但是,这些条目属于特殊情况,不符合一般规则(第B.4节中规定)。

    表B-34。使用REX推广的特殊情况说明。W(续)

    figure2

    ps52023/07/25205:49,JST

    3.1.1.1指令汇总表中的操作码列(无VEX前缀的指令)

    雷克斯。W表示影响操作数大小或指令语义的REX前缀的使用。第2章讨论了REX前缀和其他可选/强制指令前缀的排序。 请注意,将旧指令提升为64位行为的REX前缀没有在操作码列中明确列出。

    我认为重要的是,它将省略REX前缀限制为仅将操作码列中的64位行为提升为“遗留指令”。因此,对于非遗留指令,基本上,将其提升为64位行为的REX前缀在操作码列中明确列出。

    3.1.1.3操作码汇总表中的指令列

    reg用于指令的通用寄存器 当寄存器的宽度与指令的操作的语义无关时。 寄存器可以是r16、r32或r64。

    另一方面:

    r/m8字节操作数,它是字节通用寄存器(AL、CL、DL、BL、AH、CH、DH、BH、BPL、SPL、DIL和SIL)的内容,或者是来自内存的字节。字节寄存器R8B-R15B可使用REX。R在64位模式中。

    • 在r/m8的情况下,r表示8位GPR。
    • 在r/m16的情况下,r表示一个16位的GPR。
    • 在r/m32的情况下,r表示32位GPR。
    • 在r/m64的情况下,r表示64位GPR。

    我认为在reg/m8中,reg表示r16/r32/r64 GPR,而在指令中,寄存器的宽度与指令操作的语义无关。

    所以,我认为

    • 在reg/m8的情况下,reg表示r16/r32/r64 GPR。
    • 在reg/m16的情况下,reg表示r16/r32/r64 GPR。
    • 在reg/m32的情况下,reg表示r16/r32/r64 GPR。
    • 在reg/m64的情况下,reg表示r16/r32/r64 GPR。

    ps62023/07/25206:32,JST

    英特尔手册

    3-12第1卷

    3.4.1.1 64位模式下的通用寄存器

    在64位模式下,操作数大小决定目标通用中的有效位数 寄存器:

    • 64位操作数在目标通用寄存器中生成64位结果。
    • 32位操作数生成32位结果,零扩展到目标通用寄存器中的64位结果。
    • 8位和16位操作数产生8位或16位结果。目的通用寄存器的高56位或48位(分别)不通过该操作进行修改。如果8位或16位运算的结果用于64位地址计算,则显式地将寄存器符号扩展到完整的64位。
    0 回复  |  直到 3 年前