8

私は、2 つの場所で 64 ビット x 32 ビットの固定小数点除算があり、結果が 32 ビットで取得されるコードに取り組んでいます。これらの 2 つの場所を合わせて、合計時間の 20% 以上を費やしています。ですので、64ビットの割り算をなくせば、コードをうまく最適化できる気がします。NEON では、いくつかの 64 ビット命令を使用できます。より高速な実装を使用してボトルネックを解決するためのルーチンを提案できますか。

または、C の 32 ビット/32 ビット分割に関して、64 ビット/32 ビット分割を行うことができれば、それも問題ありませんか?

誰かが何か考えがあれば、私を助けてくれませんか?

4

1 に答える 1

5

私は過去に多くの固定小数点演算を行い、自分で高速な 64/32 ビット除算を探して多くの調査を行いました。「ARM部門」をグーグルで検索すると、この問題に関する素晴らしいリンクと議論がたくさん見つかります。

ハードウェアで 32 ビット除算さえ利用できない可能性がある ARM アーキテクチャの最適なソリューションは次のとおりです。

http://www.peter-teichmann.de/adiv2e.html

このアセンブリ コードは非常に古いため、アセンブラはその構文を理解できない可能性があります。ただし、コードをツールチェーンに移植する価値はあります。これは、私がこれまでに見た特別なケースの最速の除算コードであり、私を信頼してください:私はそれらすべてをベンチマークしました:-)

前回実行したとき (約 5 年前、CortexA8 の場合)、このコードはコンパイラが生成したコードよりも約 10 倍高速でした。

このコードは NEON を使用しません。NEONポートは面白いでしょう。ただし、パフォーマンスが大幅に向上するかどうかはわかりません。

編集:

GAS (GNU Toolchain) にアセンブラを移植したコードを見つけました。このコードは動作し、テストされています:

割るS

.section ".text"

.global udiv64

udiv64:
    adds      r0,r0,r0
    adc       r1,r1,r1

    .rept 31
        cmp     r1,r2   
        subcs   r1,r1,r2  
        adcs    r0,r0,r0
        adc     r1,r1,r1
    .endr

    cmp     r1,r2
    subcs   r1,r1,r2
    adcs    r0,r0,r0

    bx      lr

C コード:

extern "C" uint32_t udiv64 (uint32_t a, uint32_t b, uint32_t c);

int32_t fixdiv24 (int32_t a, int32_t b)
/* calculate (a<<24)/b with 64 bit immediate result */
{
  int q;
  int sign = (a^b) < 0; /* different signs */
  uint32_t l,h;
  a = a<0 ? -a:a;
  b = b<0 ? -b:b;
  l = (a << 24);
  h = (a >> 8);
  q = udiv64 (l,h,b);
  if (sign) q = -q;
  return q;
}
于 2013-03-05T03:35:16.467 に答える