3

问题陈述:需要从ymm0寄存器中提取位于寄存器中某个位置的字节AL

我的方法:(相当丑陋):

        ; 将 XMM1 设置为“右移一个字节”掩码
        ; XMM1:000F0E0D0C0B0A090807060504030201

        cmp al,15 ; 检查是否在 ymm0 或更高的较低 xmmword 中
        ja is_in_higher
        异或 CX,CX
        移动 CL,AL
    loop_for_next :
       vpextrb edx,ymm0,ymm0,0
       vpshufb xmm0,xm​​m0,xm​​m1 ; 右移 xmm0 作为掩码
       循环 loop_for_next
    ..
    is_in_higher :
        vperm2i128 ymm0,ymm0,ymm0,01 ; 将上 128 交换为下 128
    jmp loop_for_next

有没有更优雅的方式来做到这一点?任何建议表示赞赏。挑战的症结在于VPEXTRB它只采用立即索引值,而不是CL(或AL)寄存器作为索引值

谢谢...

4

2 回答 2

0

您的代码需要 AVX2 ( vperm2i128),我无法对其进行测试,因为我只有 AVX。无论如何,您的代码对不需要循环的任务使用循环。我的解决方案使用简单的查找表和vpshufb(需要 SSSE3)指令来重新排序字节。在 YASM 中测试。

这是代码:

[位 64]

部分 .text
全局_start

_开始:

设置示例值:
        移动,0x1e ; 字节索引:0...31, 0x00...0x1f
        vmovaps ymm0,[example_data] ; 定义数据

code_starts_here:
        cmp al,15
        jna no_need_to_reorder_octalwords

        vperm2f128 ymm0,ymm0,ymm0,0x81 ; 重新排序 ymm0。前 16 个字节为零。

no_need_to_reorder_octalwords:
        和 eax,15
        shl eax,4
        vmovaps xmm1,[rax+shuffle_table] ; 每个字节是一个索引,f0 = 设置为 0。
        vpshufb xmm0,xm​​m1 ; 将右字节复制到 xmm0 的字节 0。
                                         ; 将 xmm0 的其余字节归零。

        movq rdx,xmm0 ; 复制到rdx。

        ...

。数据
对齐 32
; 联邦银行 9 8 7 6 5 4 3 2 1 0
example_data 做 0xafaeadacabaaa9a8a7a6a5a4a3a2a1a0
; 1f1e1d1c1b1a19181716151413121110
             做 0xbfbebdbcbbbab9b8b7b6b5b4b3b2b1b0

shuffle_table dd 0xf0f0f000, 0xf0f0f0f0, 0xf0f0f0f0, 0xf0f0f0f0
                dd 0xf0f0f001, 0xf0f0f0f0, 0xf0f0f0f0, 0xf0f0f0f0
                dd 0xf0f0f002, 0xf0f0f0f0, 0xf0f0f0f0, 0xf0f0f0f0
                dd 0xf0f0f003, 0xf0f0f0f0, 0xf0f0f0f0, 0xf0f0f0f0
                dd 0xf0f0f004, 0xf0f0f0f0, 0xf0f0f0f0, 0xf0f0f0f0
                dd 0xf0f0f005, 0xf0f0f0f0, 0xf0f0f0f0, 0xf0f0f0f0
                dd 0xf0f0f006, 0xf0f0f0f0, 0xf0f0f0f0, 0xf0f0f0f0
                dd 0xf0f0f007, 0xf0f0f0f0, 0xf0f0f0f0, 0xf0f0f0f0
                dd 0xf0f0f008, 0xf0f0f0f0, 0xf0f0f0f0, 0xf0f0f0f0
                dd 0xf0f0f009, 0xf0f0f0f0, 0xf0f0f0f0, 0xf0f0f0f0
                dd 0xf0f0f00a, 0xf0f0f0f0, 0xf0f0f0f0, 0xf0f0f0f0
                dd 0xf0f0f00b, 0xf0f0f0f0, 0xf0f0f0f0, 0xf0f0f0f0
                dd 0xf0f0f00c, 0xf0f0f0f0, 0xf0f0f0f0, 0xf0f0f0f0
                dd 0xf0f0f00d, 0xf0f0f0f0, 0xf0f0f0f0, 0xf0f0f0f0
                dd 0xf0f0f00e, 0xf0f0f0f0, 0xf0f0f0f0, 0xf0f0f0f0
                dd 0xf0f0f00f, 0xf0f0f0f0, 0xf0f0f0f0, 0xf0f0f0f0
于 2013-11-20T22:45:57.200 回答
0

虽然我不确定,但可能是这样的:

and         eax,  0x0000001F    // eax  = [al & 31, 0, 0, 0] 
or          eax,  0x80808000    // eax  = [al & 31, 0x80, 0x80, 0x80]
vmovd       xmm1, eax           // ymm1 = [eax, 0, 0, 0, 0, 0, 0, 0]
vpshufb     ymm0, ymm0, ymm1    // ... 
vmovd       eax,  xmm0          // eax  = [ymm0.byte[al & 31], 0, 0, 0]

从位置 al 的 ymm0 提取的字节存储在 eax 中。

于 2014-05-30T11:49:50.660 回答