2011-10-24 25 views
6

最新のインテルCPU(コアi7、サンディーブリッジ)で128ビットシフトを行う最も効率的な方法は何ですか?アセンブリ言語を使用した128ビットシフト?

同様のコードは私の最も内側のループである:

u128 a[N]; 
void xor() { 
    for (int i = 0; i < N; ++i) { 
    a[i] = a[i]^(a[i] >> 1)^(a[i] >> 2); 
    } 
} 

a[N]内のデータは、ほぼランダムです。

+0

64ビットまたは32ビットのx86-64これはに簡素化しているのですか? –

+1

最大限の最適化を有効にして、コンパイラが生成するものを確認することから始めます。 –

+0

'u128'の定義を教えてもらえますか?おそらくSSEを使用して効率的なソリューションを提供することができます。 – Mysticial

答えて

9

使用説明シフトダブル

したがってSHLDまたはSHRD命令です.SSEはこの目的のためのものではないためです。 クラシックな方法があります。ここでは、32ビットと64ビットCPUモードで16ビット左シフトのテストケースがあります。

このようにして、最大32/64ビットの無制限サイズシフトを実行できます。 Yooは即座にビット数を変えたり、clレジスタの数値をシフトすることができます。最初の命令オペラントは、メモリ内の変数に対処することもできます。

128 32ビットx86 CPUモードで16ビットだけ左シフトビット:64ビットx86 CPUモードで16ビットで

mov  eax, $04030201; 
    mov  ebx, $08070605; 
    mov  ecx, $0C0B0A09; 
    mov  edx, $100F0E0D; 

    shld edx, ecx, 16 
    shld ecx, ebx, 16 
    shld ebx, eax, 16 
    shl  eax, 16 

128ビット左シフト:この中

mov rax, $0807060504030201; 
    mov rdx, $100F0D0E0B0C0A09; 

    shld rdx, rax, 16 
    shl rax, 16 
+1

私はこれを使用しました。これはうまく動作しますが、32ビットコードでは最大31、64ビットコードでは63までが可能です。可変量でシフトしたい場合は、 64では、これは使用できません。 – hirschhornsalz

+0

@drhirsch:私は32/64ビットまで言及していますが、32/64ビットワード以上の移動が必要な場合は、もちろん31/63bitsにする必要があります。 –

3

をx86 SHR命令とRCR命令の組み合わせを使用する特別なケース:

; a0 - bits 0-31 of a[i] 
; a1 - bits 32-63 of a[i] 
; a2 - bits 64-95 of a[i] 
; a3 - bits 96-127 of a[i] 
mov eax, a0 
mov ebx, a1 
mov ecx, a2 
mov ecx, a3 

shr eax, 1 
rcr ebx, 1 
rcr ecx, 1 
rcr edx, 1 

; b0 - bits 0-31 of b[i] := a[i] >> 1 
; b1 - bits 32-63 of b[i] := a[i] >> 1 
; b2 - bits 64-95 of b[i] := a[i] >> 1 
; b3 - bits 96-127 of b[i] := a[i] >> 1 
mov b0, eax 
mov b1, ebx 
mov b2, ecx 
mov b3, edx 

shr eax, 1 
rcr ebx, 1 
rcr ecx, 1 
rcr edx, 1 

; c0 - bits 0-31 of c[i] := a[i] >> 2 = b[i] >> 1 
; c1 - bits 32-63 of c[i] := a[i] >> 2 = b[i] >> 1 
; c2 - bits 64-95 of c[i] := a[i] >> 2 = b[i] >> 1 
; c3 - bits 96-127 of c[i] := a[i] >> 2 = b[i] >> 1 
mov c0, eax 
mov c1, ebx 
mov c2, ecx 
mov c3, edx 

; a0 - bits 0-63 of a[i] 
; a1 - bits 64-127 of a[i] 
mov rax, a0 
mov rbx, a1 

shr rax, 1 
rcr rbx, 1 

; b0 - bits 0-63 of b[i] := a[i] >> 1 
; b1 - bits 64-127 of b[i] := a[i] >> 1 
mov b0, rax 
mov b1, rbx 

shr rax, 1 
rcr rbx, 1 

; c0 - bits 0-63 of c[i] := a[i] >> 2 = b[i] >> 1 
; c1 - bits 64-127 of c[i] := a[i] >> 2 = b[i] >> 1 
mov c0, rax 
mov c1, rbx 

更新:64ビット版で修正誤字

+0

残念ながら、RCR/RCL命令は、ほとんどすべての最新のプロセッサで非常に遅いです。SHLD/SHRDはより良い代替品です – hirschhornsalz

+0

そして2番目のケースでは代わりに** shr eax、1; rcr ebx、1 ** ** shr rax、1; rcr rbx、1 ** –

+0

2番目の引数が1の場合、RCR/RCLは高速です。これはまさにこの問題の場合です。 2番目の引数が1の場合RCR/RCLは現代のすべてのCPUでSHLD/SHRDより高速です。 –

関連する問題