ARMに整数(署名または署名なし)部門をどのように行いますか?
-
27-10-2019 - |
質問
特に皮質A8と皮質A9に取り組んでいます。一部のアーキテクチャは整数部門に付属していないことを知っていますが、フロート、分割、整数への変換に変換する以外に行うための最良の方法は何ですか?それとも、それが確かに最良の解決策ですか?
乾杯! =)
解決
コンパイラには通常、ライブラリに格差が含まれています。たとえば、GCCLIBはGCCからそれらを抽出し、直接使用しました。
https://github.com/dwelch67/stm32vld/ その後、STM32F4D/ADVENTURE/GCCLIB
フロートとバックに行くことは、おそらく最良の解決策ではありません。あなたはそれを試して、それがどれほど速いかを見ることができます...これは増殖ですが、それを簡単に格差にすることができます:
https://github.com/dwelch67/stm32vld/ その後、STM32F4D/FLOAT01/VECTORS.S
どれだけ速く/遅くなるかを見るために時間を過ごしませんでした。私は上記の皮質Mを使用していると理解していますが、あなたは皮質A、スペクトルの異なる端、同様のフロート命令、GCC libのものについて話しています。腕のために簡単に構築します。実際、GCCでは、すべて自動的に動作するはずです。私がやったようにする必要はありません。他のコンパイラも同様に、上記のアドベンチャーゲームで私がやったようにそれをする必要はありません。
他のヒント
一定の値による分割は、64ビットの倍率と右のシフトを実行することで迅速に行われます。たとえば、次のようになります。
LDR R3, =0xA151C331
UMULL R3, R2, R1, R3
MOV R0, R2,LSR#10
ここでR1は1625年に分割されます。計算は次のように行われます。64bitreg(R2:R3)= R1*0xA151C331、結果は上部32ビット右シフト10にシフトされます。
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)
Webで署名されていないバージョンを見つけることができなかったため、署名されていない部門を実行するために自分のルーチンを書きました。 32ビットの結果を得るには、64ビット値を32ビット値で分割する必要がありました。
内側のループは、上記の署名されたソリューションほど効率的ではありませんが、これは署名されていない算術をサポートします。このルーチンは、分子(HI)の高い部分が分母(DEN)よりも小さい場合、32ビット除算を実行します。結果は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
2つの機能があります。 udiv
署名されていない整数部門の場合 sdiv
署名された整数部門用。彼らは両方とも64ビットの配当(署名または署名なし)を期待しています r1
(ハイワード)と r0
(低いワード)、および32ビットの除数 r2
. 。彼らは商をに返します r0
そして残りは r1
, 、したがって、それらをaで定義できます C header
なので extern
64ビットの整数を返し、商と残りをマスクします。エラー(0またはオーバーフローによる除算)は、除数の絶対値に等しい絶対値を持つ残りの部分で示されます。署名された分割アルゴリズムは、配当と除数の両方の兆候によってケースの区別を使用します。すべてのオーバーフロー条件を適切に検出しないため、最初に正の整数に変換されません。