2011-10-26 11 views
2

私は、常に2回実行される単純な浮動小数点ベースの演算を持っています。だから私はそれをSSEに変換しようとしましたが、ただ失敗します。高水準言語はDelphiです。そのため、Intrinsics関数をサポートしていないため、すべてを記述する必要があります。 基本的に私はちょうど:パラメータのロード/アンロードし、いくつかの乗算とaddditionsを持ってSSE2を使用したDelphiでのインラインアセンブル非効率プロシージャ

Procedure TLP1Poly2.Process(Const _a1, _b1, _OldIn1, _OldIn2, _OldOut1, _OldOut2:  Double; Var Sample1, Sample2: Double); 
Asm 
    MOVLPD XMM4, _a1 
    MOVHPD XMM4, _a1 
    MOVLPD XMM3, _b1 
    MOVHPD XMM3, _b1 
    // 
    MOVLPD XMM0, [Sample1] 
    MOVHPD XMM0, [Sample2] 
    MULPD XMM0, XMM4 
    // 
    MOVLPD XMM1, _OldIn1 
    MOVHPD XMM1, _OldIn2 
    MULPD XMM1, XMM4 
    // 
    MOVLPD XMM2, _OldOut1 
    MOVHPD XMM2, _OldOut2 
    MULPD XMM2, XMM3 
    // 
    ADDPD XMM0, XMM1 
    ADDPD XMM0, XMM2 
    // 
    MOVLPD [Sample1], XMM0 
    MOVHPD [Sample2], XMM0 
    // 
    // which stands for twice this: 
    // Sample:= Sample*a1 + oldinp*a1 + oldout*b1; 
    // 
End; 

が、この手順は動作しません、私はそれは大丈夫だ省エネ/サンプル1 /サンプル2の負荷の間のすべてを「NOP」の場合、それ以外の私のフィルタ黙っている。 SSEでこれで得られない基本的なことは何ですか?

Addenum:

古いクラスのクラス:

constructor TLP1.create; 
begin 
    oldfreq := -1 ; 
end; 
procedure TLp1.process(inp,Frq,SR :single); 
begin 
    if Frq<>oldfreq then 
    begin 
     a := 2* SR; 
     t := Frq * _ppi; 
     n := 1/ (a+t) ; 
     b1:= (a - t) * n; 
    a1:= t * n; 
    oldfreq := frq; 
    end; 
    outlp := (inp+_kd)*a1 + oldinp*a1 + oldout*b1; 
    oldout := outlp ; 
    oldinp := inp; 
end; 

新クラス:Delphiで

Procedure TLP2Poly2.SetSamplerate(Const Value: Single); 
Begin 
    If Value = FSamplerate Then Exit; 
    FSamplerate := Value; 
    UpdateCoefficients; 
End; 

Procedure TLP2Poly2.SetFrequency(Const Value: Single); 
Begin 
If Value = FFrequency Then Exit; 
    FFrequency := Value; 
    UpdateCoefficients; 
End; 

Procedure TLP2Poly2.UpdateCoefficients; 
Var 
    a,t,n: Single; 
Begin 
    a := 2 * FSamplerate ; 
    t := FFrequency * 2 * pi; 
    n := 1/ (a+t) ; 
    b1:= (a - t) * n; 
    a1:= t * n; 
End; 

Procedure TLP2Poly2.Process(Var Sample1, Sample2: Double); 
Var 
    o1, o2: Double; 
Begin 
    o1 := Sample1; 
    o2 := Sample2; 
    IntProcess(a1, b1, OldIn1, OldIn2, OldOut1, OldOut2, Sample1, Sample2); 
    OldOut1 := Sample1; 
    OldOut2 := Sample2; 
    OldIn1 := o1; 
    OldIn2 := o2; 
End; 

Procedure TLP2Poly2.IntProcess(Const _a1, _b1, _OldIn1, _OldIn2, _OldOut1, _OldOut2: Double; Var Sample1, Sample2: Double); 
Asm 
    MOVLPD XMM4, _a1 
    MOVHPD XMM4, _a1 
    MOVLPD XMM3, _b1 
    MOVHPD XMM3, _b1 
    // 
    MOVLPD XMM0, [Sample1] 
    MOVHPD XMM0, [Sample2] 
    MULPD XMM0, XMM4 
    // 
    MOVLPD XMM1, _OldIn1 
    MOVHPD XMM1, _OldIn2 
    MULPD XMM1, XMM4 
    // 
    MOVLPD XMM2, _OldOut1 
    MOVHPD XMM2, _OldOut2 
    MULPD XMM2, XMM3 
    // 
    ADDPD XMM0, XMM1 
    ADDPD XMM0, XMM2 
    // 
    MOVLPD [Sample1], XMM0 
    MOVHPD [Sample2], XMM0 
End; 
+1

をあまり意味がありません "それは動作しません"。このコードは何ですか?それは何をすべきか、代わりに何をしていますか?もう少し細かいことが非常に役に立つでしょう。 –

+0

低域フィルタ、1極です。強調表示されたコードの最後に元のコードがコメントとして挿入されます。 a1とb1は係数で、元のバージョンのフィルタとまったく同じです。 – az01

+1

正確に何を翻訳したいのですか?あなたのコードの発言は不十分です。 –

答えて

2

SSEレジスタを示しデバッガペイン( "FPU")があります。したがって、フィルタにゼロ以外の値を入力すると、サイレント出力がどこから来るのかを見つけることができます。

6

特に64ビットモードで、デルファイのアセンブラを書くときには、パラメータの受け渡し方法に常に注意する必要があります。とにかく最初の4つのパラメータの名前は決して使用されません。私はこれらのレジスタを直接使用します。それぞれXMM3ので、あなたのコードの最初の部分は、これらのレジスタの一部を上書きする - 。_a1_b1_oldIn1_oldIn2XMM0に渡されていることを

注意たとえば、XMM3_b1にロードすると、_oldIn2を上書きします。同じことがXMM2で起こります。これは_oldIn1です。

レジスタの使用方法を並べ替えることで、メモリの記憶域をinbetweenとして使用する必要がなくなります。

IOW、(未テスト)のような何かしてみてください:

asm 
     MOVDDUP XMM0,XMM0 
     MOVDDUP XMM1,XMM1 

     MOVLPD XMM4,[Sample1] 
     MOVHPD XMM4,[Sample2] 
     MULPD XMM4,XMM0 

     // etc... 
+0

アドバイスありがとう。 MOVDUPが問題ないかどうかはわかりませんでした。大きな問題は、SSE(http://softpixel.com/~cwright/programming/simd/)を学ぶために古いオフライン文書を使用していることです。 – az01

+0

AMDまたはIntelの公式ドキュメントをお試しください。それらは無料で多数の.pdfsとしてダウンロードできます。 –

+0

2つの半分に読み込むには、 'movlpd'の代わりに' movsd'を使い始めます。あなたが*古い値にマージしてそれに依存することを望む場合にのみ、 'movlpd'を使用してください。また、上半分は1バイトのコードサイズを節約するために 'movlps 'となるかもしれません。 –

関連する問題