3

uni 割り当ての場合、アセンブリ内の文字列 (ポインターとインデックスによって定義される) 内のスペースの数をカウントする関数を作成する必要があります。これを使用するための要件pcmpeqb(つまり、SSE レジスターを操作すること) と、 および を使用するためのヒントがpopcntありpmovmskbます。私の基本的なアプローチは、文字列を 16 バイトのチャンクで処理し、各チャンクをロードして、16 個のスペースを含むように初期化されたチャンク%xmm8と比較することです。%xmm9ただし、最後のチャンクを何らかの方法で特別に処理する必要があります。

最初に考えたのは、回転命令を使用して、文字列の末尾を過ぎたゴミを削除することでした。(セグメンテーション違反を防ぐために、文字列の末尾に追加のスペースが割り当てられることが保証されていますが、そこにあるデータはおそらく比較に使用されるべきではありません。)偶然見つけましPSRLDQたが、即時ではない引数を受け入れないようです。(または、少なくとも私が投げたものを拒否しました。) それで、私の質問は、SSE レジスタの最後の X バイトを、その半分をゼロにすることなく、または単語ごとに削除することなく削除するにはどうすればよいですか? (私が理解しているように、それらに対して利用可能な操作のほとんどはそうです。)

私のコード(モジュロボイラープレート)は現在次のようになっています-問題のあるビットはラベルの後、最後に向かっています_last:

    # === Arguments ===
    # %rdi - char *input
    # %rsi - size_t count
    # === Temporaries ===
    # %rdx - how many chars to process in final run
    # %rcx - how many characters were "read" already
    # %r8 - pop count of last iteration
    # %r9
    # %r11
    # === SSE Temporaries ===
    # %xmm8 - the chunk of the string being processed
    # %xmm9 - 16 spaces

    xor %rcx, %rcx
    xor %rax, %rax
    movdqu _spaces(%rip), %xmm9

_loop:
    # set %rdx to number of characters left to process
    mov %rsi, %rdx
    sub %rcx, %rdx

    # we've reached the end of the string
    cmp %rdx, %rsi
    jge _end

    movdqu (%rdi, %rcx), %xmm8 # load chunk of string to process
    add $16, %rcx

    # less than 16 characters to process
    cmp $16, %rdx
    jg _last

_compare: #compare %xmm8 with spaces and add count of spaces to %eax
    pcmpeqb %xmm9, %xmm8
    pmovmskb %xmm8, %r8d
    popcntl %r8d, %r8d
    add %r8d, %eax
    jmp _loop

_last: # last part of string, less than 16 chars
    sub $16, %rdx
    neg %rdx
    # I need to delete possible garbage after the last chars
    psrldq %edx, %xmm8 
    jmp _compare

_end:
    ret

(制御フローにはまだバグがあるかもしれませんが、後で対処します。)

4

2 に答える 2