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
(制御フローにはまだバグがあるかもしれませんが、後で対処します。)