Неэффективная процедура встроенной сборки в Delphi с использованием SSE2 - PullRequest
2 голосов
/ 27 октября 2011

У меня есть простая операция с плавающей точкой, которая всегда выполняется дважды.Поэтому я попытался перевести его на SSE, но он просто не удался.Язык высокого уровня - Delphi, так как он не поддерживает функции Intrinsics, я должен написать все это.В основном у меня просто есть параметр load / unload и некоторые умножения и дополнения .:

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;

, но эта процедура не работает, если я не могу выполнить все операции загрузки / сохранения Sample1 / Sample2, все в порядке, но в противном случае мойфильтр молчит.Что является основным, что я не получаю с SSE в этом?

Addenum:

старый класс class:

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;

Новый класс:

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;

Ответы [ 2 ]

6 голосов
/ 27 октября 2011

При написании ассемблера для Delphi, особенно в 64-битном режиме, вы всегда должны знать, как передаются параметры. Я никогда не использую имена первых 4 параметров, так как они в любом случае есть в регистрах. Я использую эти регистры напрямую.

Обратите внимание, что _a1, _b1, _oldIn1 и _oldIn2 передаются в XMM0 - XMM3 соответственно, поэтому первая часть вашего кода перезаписывает некоторые из эти регистры. Например, загрузка XMM3 с _b1 перезапишет _oldIn2. То же самое происходит с XMM2 , который содержит _oldIn1.

Было бы разумно изменить порядок использования регистра, чтобы вам не приходилось использовать память в качестве промежуточного элемента.

IOW, попробуйте что-то вроде (не проверено):

asm
        MOVDDUP XMM0,XMM0
        MOVDDUP XMM1,XMM1

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

        // etc...
2 голосов
/ 27 октября 2011

В Delphi есть панель отладчика («FPU»), которая показывает регистры SSE. Так что, если вы подадите в фильтр несколько ненулевых значений, вы сможете найти источник тихого вывода.

...