特に Cortex-A8 と Cortex-A9 に取り組んでいます。一部のアーキテクチャには整数除算が付属していないことは知っていますが、浮動小数点数への変換、除算、整数への変換以外にそれを行う最良の方法は何ですか? それとも、それが本当に最善の解決策ですか?
乾杯!= )
特に Cortex-A8 と Cortex-A9 に取り組んでいます。一部のアーキテクチャには整数除算が付属していないことは知っていますが、浮動小数点数への変換、除算、整数への変換以外にそれを行う最良の方法は何ですか? それとも、それが本当に最善の解決策ですか?
乾杯!= )
定数値による除算は、たとえば次のように、64 ビットの乗算と右シフトを実行することですばやく実行できます。
LDR R3, =0xA151C331
UMULL R3, R2, R1, R3
MOV R0, R2,LSR#10
ここで、R1 は 1625 で除算されます。計算は次のように行われます。
R1*0xA151C331/2^(32+10) = R1*0.00061538461545751488 = R1/1624.99999980
この式から独自の定数を計算できます。
x / N == (x*A)/2^(32+n) --> A = 2^(32+n)/N
A < 2^32 である最大の n を選択します
整数除算のための他の場所からのコピーパスタ: 基本的に、ビットごとに 3 つの命令。このウェブサイトからですが、他の多くの場所でも見ました。 このサイトには、全体的に高速なナイス バージョンもあります。
@ Entry r0: numerator (lo) must be signed positive
@ r2: deniminator (den) must be non-zero and signed negative
idiv:
lo .req r0; hi .req r1; den .req r2
mov hi, #0 @ hi = 0
adds lo, lo, lo
.rept 32 @ repeat 32 times
adcs hi, den, hi, lsl #1
subcc hi, hi, den
adcs lo, lo, lo
.endr
mov pc, lr @ return
@ Exit r0: quotient (lo)
@ r1: remainder (hi)
コンパイラーは通常、そのライブラリー gcclib に除算を含めます。たとえば、gcc からそれらを抽出して直接使用します。
https://github.com/dwelch67/stm32vld/その後、stm32f4d/adventure/gcclib
浮かんで戻ってくるのは、おそらく最善の解決策ではありません。あなたはそれを試してみて、それがどれほど速いかを見ることができます...これは乗算ですが、除算も簡単に行うことができます:
https://github.com/dwelch67/stm32vld/その後 stm32f4d/float01/vectors.s
私はそれがどれほど速い/遅いかを確認するために時間を計りませんでした. 上記のcortex-mを使用していることを理解しました。あなたはcortex-a、スペクトルのさまざまな端、同様のフロート命令、およびgcc libのものについて話していることを理解しています。腕も同様に簡単に構築できます。実際、gcc を使用すると、すべて自動的に機能するはずです。私が行った方法で行う必要はありません。他のコンパイラーも、上記のアドベンチャー ゲームで行った方法で行う必要はありません。
Webで署名されていないバージョンが見つからなかったため、署名されていない除算を実行するための独自のルーチンを作成しました。32ビットの結果を得るには、64ビットの値を32ビットの値で除算する必要がありました。
内部ループは、上記の符号付きソリューションほど効率的ではありませんが、これは符号なし演算をサポートします。このルーチンは、分子の上位部分(hi)が分母(den)よりも小さい場合は、32ビットの除算を実行します。それ以外の場合は、完全な64ビットの除算(hi:lo / den)を実行します。結果はloにあります。
cmp hi, den // if hi < den do 32 bits, else 64 bits
bpl do64bits
REPT 32
adds lo, lo, lo // shift numerator through carry
adcs hi, hi, hi
subscc work, hi, den // if carry not set, compare
subcs hi, hi, den // if carry set, subtract
addcs lo, lo, #1 // if carry set, and 1 to quotient
ENDR
mov r0, lo // move result into R0
mov pc, lr // return
do64bits:
mov top, #0
REPT 64
adds lo, lo, lo // shift numerator through carry
adcs hi, hi, hi
adcs top, top, top
subscc work, top, den // if carry not set, compare
subcs top, top, den // if carry set, subtract
addcs lo, lo, #1 // if carry set, and 1 to quotient
ENDR
mov r0, lo // move result into R0
mov pc, lr // return
境界条件と2の累乗の追加チェックを追加できます。詳細については、http://www.idwiz.co.za/Tips%20and%20Tricks/Divide.htmをご覧ください。
ARM GNU
アセンブラ用に以下の関数を書きました。マシンをサポートする CPU がない場合はudiv/sdiv
、関数の最初の数行を "0:" ラベルまで切り取ってください。
.arm
.cpu cortex-a7
.syntax unified
.type udiv,%function
.globl udiv
udiv: tst r1,r1
bne 0f
udiv r3,r0,r2
mls r1,r2,r3,r0
mov r0,r3
bx lr
0: cmp r1,r2
movhs r1,r2
bxhs lr
mvn r3,0
1: adds r0,r0
adcs r1,r1
cmpcc r1,r2
subcs r1,r2
orrcs r0,1
lsls r3,1
bne 1b
bx lr
.size udiv,.-udiv
.type sdiv,%function
.globl sdiv
sdiv: teq r1,r0,ASR 31
bne 0f
sdiv r3,r0,r2
mls r1,r2,r3,r0
mov r0,r3
bx lr
0: mov r3,2
adds r0,r0
and r3,r3,r1,LSR 30
adcs r1,r1
orr r3,r3,r2,LSR 31
movvs r1,r2
ldrvc pc,[pc,r3,LSL 2]
bx lr
.int 1f
.int 3f
.int 5f
.int 11f
1: cmp r1,r2
movge r1,r2
bxge lr
mvn r3,1
2: adds r0,r0
adcs r1,r1
cmpvc r1,r2
subge r1,r2
orrge r0,1
lsls r3,1
bne 2b
bx lr
3: cmn r1,r2
movge r1,r2
bxge lr
mvn r3,1
4: adds r0,r0
adcs r1,r1
cmnvc r1,r2
addge r1,r2
orrge r0,1
lsls r3,1
bne 4b
rsb r0,0
bx lr
5: cmn r1,r2
blt 6f
tsteq r0,r0
bne 7f
6: mov r1,r2
bx lr
7: mvn r3,1
8: adds r0,r0
adcs r1,r1
cmnvc r1,r2
blt 9f
tsteq r0,r3
bne 10f
9: add r1,r2
orr r0,1
10: lsls r3,1
bne 8b
rsb r0,0
bx lr
11: cmp r1,r2
blt 12f
tsteq r0,r0
bne 13f
12: mov r1,r2
bx lr
13: mvn r3,1
14: adds r0,r0
adcs r1,r1
cmpvc r1,r2
blt 15f
tsteq r0,r3
bne 16f
15: sub r1,r2
orr r0,1
16: lsls r3,1
bne 14b
bx lr
udiv
符号なし整数除算用と符号付き整数除算用の2 つの関数がありますsdiv
。r1
どちらも(上位ワード) と(下位ワード) で64 ビットの被除数 (符号付きまたは符号なし) を想定し、r0
で 32 ビットの除数を想定していr2
ます。これらは で商を返し、r0
で余りを返します。したがって、 でそれらを64 ビット整数を返すように定義し、後で商と余りをマスクすることr1
ができます。エラー (0 による除算またはオーバーフロー) は、除数の絶対値以上の絶対値を持つ剰余によって示されます。符号付き除算アルゴリズムは、被除数と除数の両方の符号による大文字と小文字の区別を使用します。すべてのオーバーフロー条件を適切に検出できないため、最初に正の整数に変換しません。C header
extern