2009年09月02日

AndroidのDalvikVMのインタープリタをFPU命令で少し高速化する(その2)

前回はDalvik VMのインタープリタのfloatの四則演算だけFPU命令を使うように修正してみました。今回はdoubleの四則演算でもFPU命令を使うように修正します。今回の修正で私が即席で作った速度測定プログラムをエミュレータで実行したところ、約260msecかかっていたものが約85msecにまで短縮できました。これは結構効果がありそうです。



2009年11月のEclairのソースリリースでだいぶ状況が変わっています。こちらも参照してください。

まず、floatのときと同じ変更をしてみたが...失敗

floatのときには一命令のライブラリ呼び出しを合計4命令のFPU命令に置き換えました。単純ですが、これだと差し引き3命令分サイズが増えてしまいます。アセンブラのインタープリタでは高速化のためにひとつのDXコードに対する処理を64バイトで書かなければならないようになっています。ARMモードだと16命令分です。

floatのときには命令数に余裕があったのですが、doubleでは3命令増えると合計が17命令になってはみだしてしまいました。

変更する範囲を広げる

命令数を増やさないようにしつつFPU命令を使うためには、ライブラリ呼び出しだけを置き換えるのでなく、メモリの読み書きの部分も変更して、メモリから直接FPUレジスタに読み書きするようにします。

以下のようなCのプログラムからメモリからFPUレジスタへの読み書きの方法を調べます。

void dadd(double *x, double *y) { *x += *y; }
void dsub(double *x, double *y) { *x -= *y; }
void dmul(double *x, double *y) { *x *= *y; }
void ddiv(double *x, double *y) { *x /= *y; }

void fadd(float *x, float *y) { *x += *y; }
void fsub(float *x, float *y) { *x -= *y; }
void fmul(float *x, float *y) { *x *= *y; }
void fdiv(float *x, float *y) { *x /= *y; }

FPUを使わない場合

dmul:
	@ args = 0, pretend = 0, frame = 0
	@ frame_needed = 0, uses_anonymous_args = 0
	ldmia	r1, {r2-r3}
	stmfd	sp!, {r4, lr}
	mov	r4, r0
	ldmia	r0, {r0-r1}
	bl	__aeabi_dmul
	stmia	r4, {r0-r1}
	ldmfd	sp!, {r4, pc}

FPUを使う場合

dmul:
	@ args = 0, pretend = 0, frame = 0
	@ frame_needed = 0, uses_anonymous_args = 0
	@ link register save eliminated.
	fldd	d5, [r1, #0]
	fldd	d7, [r0, #0]
	@ lr needed for prologue
	fmuld	d6, d7, d5
	fstd	d6, [r0, #0]
	bx	lr

これを参考にして、試しにインタープリタの一ヶ所だけを以下のように変更してみます。

diff --git a/vm/mterp/out/InterpAsm-armv5te.S b/vm/mterp/out/InterpAsm-armv5te.S
index fa2ad9a..eb6f8a8 100644
--- a/vm/mterp/out/InterpAsm-armv5te.S
+++ b/vm/mterp/out/InterpAsm-armv5te.S
@@ -5267,8 +5267,10 @@ d2i_doconv:
     add     r9, rFP, r9, lsl #2         @ r9<- &fp[AA]
     add     r2, rFP, r2, lsl #2         @ r2<- &fp[BB]
     add     r3, rFP, r3, lsl #2         @ r3<- &fp[CC]
-    ldmia   r2, {r0-r1}                 @ r0/r1<- vBB/vBB+1
-    ldmia   r3, {r2-r3}                 @ r2/r3<- vCC/vCC+1
+@    ldmia   r2, {r0-r1}                 @ r0/r1<- vBB/vBB+1
+@    ldmia   r3, {r2-r3}                 @ r2/r3<- vCC/vCC+1
+    fldd	d6, [r2, #0]
+    fldd	d7, [r3, #0]
     .if 0
     orrs    ip, r2, r3                  @ second arg (r2-r3) is zero?
     beq     common_errDivideByZero
@@ -5276,9 +5278,13 @@ d2i_doconv:
     FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
 
                                @ optional op; may set condition codes
-    bl      __aeabi_dmul                              @ result<- op, r0-r3 changed
+@    bl      __aeabi_dmul                              @ result<- op, r0-r3 changed
+    fmuld	d6, d7, d6
+	
     GET_INST_OPCODE(ip)                 @ extract opcode from rINST
-    stmia   r9, {r0,r1}     @ vAA/vAA+1<- r0/r1
+@    stmia   r9, {r0,r1}     @ vAA/vAA+1<- r0/r1
+    fstd	d6, [r9, #0]
+	
     GOTO_OPCODE(ip)                     @ jump to next instruction
     /* 14-17 instructions */
 

この変更を入れると以下のようになります。

InterpAsm-armv5te.S


/* ------------------------------ */
    .balign 64
.L_OP_MUL_DOUBLE: /* 0xad */
/* File: armv5te/OP_MUL_DOUBLE.S */
/* File: armv5te/binopWide.S */
    /*
     * Generic 64-bit binary operation.  Provide an "instr" line that
     * specifies an instruction that performs "result = r0-r1 op r2-r3".
     * This could be an ARM instruction or a function call.  (If the result
     * comes back in a register other than r0, you can override "result".)
     *
     * If "chkzero" is set to 1, we perform a divide-by-zero check on
     * vCC (r1).  Useful for integer division and modulus.
     *
     * for: add-long, sub-long, div-long, rem-long, and-long, or-long,
     *      xor-long, add-double, sub-double, mul-double, div-double,
     *      rem-double
     *
     * IMPORTANT: you may specify "chkzero" or "preinstr" but not both.
     */
    /* binop vAA, vBB, vCC */
    FETCH(r0, 1)                        @ r0<- CCBB
    mov     r9, rINST, lsr #8           @ r9<- AA
    and     r2, r0, #255                @ r2<- BB
    mov     r3, r0, lsr #8              @ r3<- CC
    add     r9, rFP, r9, lsl #2         @ r9<- &fp[AA]
    add     r2, rFP, r2, lsl #2         @ r2<- &fp[BB]
    add     r3, rFP, r3, lsl #2         @ r3<- &fp[CC]
@    ldmia   r2, {r0-r1}                 @ r0/r1<- vBB/vBB+1
@    ldmia   r3, {r2-r3}                 @ r2/r3<- vCC/vCC+1
    fldd	d6, [r2, #0]
    fldd	d7, [r3, #0]
    .if 0
    orrs    ip, r2, r3                  @ second arg (r2-r3) is zero?
    beq     common_errDivideByZero
    .endif
    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST

                               @ optional op; may set condition codes
@    bl      __aeabi_dmul                              @ result<- op, r0-r3 changed
    fmuld	d6, d7, d6
	
    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
@    stmia   r9, {r0,r1}     @ vAA/vAA+1<- r0/r1
    fstd	d6, [r9, #0]
	
    GOTO_OPCODE(ip)                     @ jump to next instruction
    /* 14-17 instructions */



/* ------------------------------ */
    .balign 64

バスエラー発生。なんで?!

このように一ヶ所だけ変更したインタープリタでエミュレータを起動するとエラーが発生して起動に失敗してしまいました。

logcatによると zygoteのプロセスでバスエラーが発生したようです。

I/DEBUG   (  543): *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
I/DEBUG   (  543): Build fingerprint: 'generic/generic/generic/:Donut/Donut/eng.koba.20090827.140821:eng/test-keys'
I/DEBUG   (  543): pid: 590, tid: 590  >>> zygote <<<
I/DEBUG   (  543): signal 7 (SIGBUS), fault addr 00000000
I/DEBUG   (  543):  r0 00001412  r1 4104bbe4  r2 4104bbdc  r3 4104bbe4
I/DEBUG   (  543):  r4 41748086  r5 4104bb94  r6 bef614e8  r7 ad00e640
I/DEBUG   (  543):  r8 000012ad  r9 4104bbdc  10 4104bb84  fp 00000000
I/DEBUG   (  543):  ip 000000ad  sp bef614a8  lr ad01071c  pc ad01119c  cpsr 20000010
I/DEBUG   (  543):          #00  pc 0001119c  /system/lib/libdvm.so
I/DEBUG   (  543):          #01  pc 00017d90  /system/lib/libdvm.so
I/DEBUG   (  543):          #02  pc 000177d4  /system/lib/libdvm.so
I/DEBUG   (  543):          #03  pc 00052974  /system/lib/libdvm.so
I/DEBUG   (  543):          #04  pc 00052992  /system/lib/libdvm.so

バスエラーを起こしたpcは0xad01119c

Androidではシステムの共有ライブラリは固定番地にprelinkされます。

以下のファイルを調べると0xad01119cはlibdvm.so の中だとわかります。

$TOP/build/core/prelink-linux-arm.map

# 0xC0000000 - 0xFFFFFFFF Kernel
# 0xB0100000 - 0xBFFFFFFF Thread 0 Stack
# 0xB0000000 - 0xB00FFFFF Linker
# 0xA0000000 - 0xBFFFFFFF Prelinked System Libraries
# 0x90000000 - 0x9FFFFFFF Prelinked App Libraries
# 0x80000000 - 0x8FFFFFFF Non-prelinked Libraries
# 0x40000000 - 0x7FFFFFFF mmap'd stuff
# 0x10000000 - 0x3FFFFFFF Thread Stacks
# 0x00000000 - 0x0FFFFFFF .text / .data / heap

 ...

# core dalvik runtime support
libandroid_servers.so   0xAD900000
#libicudata.so           0xAD600000
libicuuc.so             0xAD500000
libicui18n.so           0xAD400000
libandroid_runtime.so   0xAD300000
libnativehelper.so      0xAD200000
libdvm-ARM.so           0xAD100000
libdvm.so               0xAD000000

libdvm.soを逆アセンブルして先頭から 0x1119cのところを見てみると

$ arm-eabi-objdump -d out/target/product/generic/symbols/system/lib/libdvm.so |less

   ...

   11178:       e1a00000        nop                     (mov r0,r0)
   1117c:       e1a00000        nop                     (mov r0,r0)
   11180:       e1d400b2        ldrh    r0, [r4, #2]
   11184:       e1a09428        mov     r9, r8, lsr #8
   11188:       e20020ff        and     r2, r0, #255    ; 0xff
   1118c:       e1a03420        mov     r3, r0, lsr #8
   11190:       e0859109        add     r9, r5, r9, lsl #2
   11194:       e0852102        add     r2, r5, r2, lsl #2
   11198:       e0853103        add     r3, r5, r3, lsl #2
>> 1119c:       ed926b00        fldd    d6, [r2]
   111a0:       ed937b00        fldd    d7, [r3]
   111a4:       e1f480b4        ldrh    r8, [r4, #4]!
   111a8:       ee276b06        fmuld   d6, d7, d6
   111ac:       e208c0ff        and     ip, r8, #255    ; 0xff
   111b0:       ed896b00        fstd    d6, [r9]
   111b4:       e087f30c        add     pc, r7, ip, lsl #6
   111b8:       e1a00000        nop                     (mov r0,r0)
   111bc:       e1a00000        nop                     (mov r0,r0)
   111c0:       e1d400b2        ldrh    r0, [r4, #2]
   ...

1119cのfldd d6, [r2]はまさしく今追加した部分です。

でもなぜバスエラーになるのでしょう?

r2の値は0x4104bbdcです。8バイトのデータの読み出しが8バイト境界になっていないのがまずいのでしょうか?

そんなはずはないと思って、ARMのドキュメントを調べ、またARM1136の実ボードでコードの断片を動かしてみてこのflddが4バイト境界のアドレスで問題なく動作することを確認しました。

このデバッグのダンプしているところのバグかもしれないと思って、その部分を追ってみたり。

最後にはqemuを疑うところまでいきましたが、どうやらそれが当たりだったようです。

 

qemuを変更する

64bitのデータの読み書きでアライメントのチェックをしている箇所をqemuのソースで探しました。マクロが多用された読みにくいソースでしたが該当箇所をなんとか見つけることができました。

試行錯誤で修正してなんとか動くようになりました。やはりqemuの問題でした。

最終的には最新版のqemuとソースを比較し、以下の1箇所の修正でうまくいくことがわかりました。

cd external/qemu

diff --git a/target-arm/op_helper.c b/target-arm/op_helper.c
index 36de55b..41219f6 100644
--- a/target-arm/op_helper.c
+++ b/target-arm/op_helper.c
@@ -70,7 +70,7 @@ uint32_t HELPER(neon_tbl)(uint32_t ireg, uint32_t def,
 static void do_unaligned_access (target_ulong addr, int is_write, int is_user, void *retaddr);
 
 #define MMUSUFFIX _mmu
-#define ALIGNED_ONLY  1
+/*#define ALIGNED_ONLY  1*/
 
 #define SHIFT 0
 #include "softmmu_template.h"

まとめ

  • androidのソースツリーにあるqemuは64bitのデータの読み書きの時のアライメントチェックが間違っていました。
  • 前回と今回の変更でfloatとdoubleの四則演算がFPUで高速化されました。まだ比較や型変換などFPUで高速化できる余地があります。

実機での効果は未測定です。どなたかAndroidをFPUつきの実機に移植した方はぜひ試してみてください。また、アプリでの浮動小数点演算の速度のちょうどいいベンチマークテストがあったら紹介してください。

次回はユーザーランドをまるごとFPUを有効にしてビルドするための変更点を紹介します。

以下に今回のソースの変更点と速度測定に使った即席プログラムを張り付けておきます。

インタープリタのソース変更

前回のfloatの変更に追加して以下を変更します。

diff --git a/vm/mterp/out/InterpAsm-armv5te.S b/vm/mterp/out/InterpAsm-armv5te.S
index fa2ad9a..bbc9d21 100644
--- a/vm/mterp/out/InterpAsm-armv5te.S
+++ b/vm/mterp/out/InterpAsm-armv5te.S
@@ -5177,8 +5177,10 @@ d2i_doconv:
     add     r9, rFP, r9, lsl #2         @ r9<- &fp[AA]
     add     r2, rFP, r2, lsl #2         @ r2<- &fp[BB]
     add     r3, rFP, r3, lsl #2         @ r3<- &fp[CC]
-    ldmia   r2, {r0-r1}                 @ r0/r1<- vBB/vBB+1
-    ldmia   r3, {r2-r3}                 @ r2/r3<- vCC/vCC+1
+@    ldmia   r2, {r0-r1}                 @ r0/r1<- vBB/vBB+1
+@    ldmia   r3, {r2-r3}                 @ r2/r3<- vCC/vCC+1
+    fldd	d6, [r2, #0]
+    fldd	d7, [r3, #0]
     .if 0
     orrs    ip, r2, r3                  @ second arg (r2-r3) is zero?
     beq     common_errDivideByZero
@@ -5186,9 +5188,13 @@ d2i_doconv:
     FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
 
                                @ optional op; may set condition codes
-    bl      __aeabi_dadd                              @ result<- op, r0-r3 changed
+@    bl      __aeabi_dadd                              @ result<- op, r0-r3 changed
+    faddd	d6, d6, d7
+
     GET_INST_OPCODE(ip)                 @ extract opcode from rINST
-    stmia   r9, {r0,r1}     @ vAA/vAA+1<- r0/r1
+@    stmia   r9, {r0,r1}     @ vAA/vAA+1<- r0/r1
+    fstd	d6, [r9, #0]
+
     GOTO_OPCODE(ip)                     @ jump to next instruction
     /* 14-17 instructions */
 
@@ -5222,8 +5228,10 @@ d2i_doconv:
     add     r9, rFP, r9, lsl #2         @ r9<- &fp[AA]
     add     r2, rFP, r2, lsl #2         @ r2<- &fp[BB]
     add     r3, rFP, r3, lsl #2         @ r3<- &fp[CC]
-    ldmia   r2, {r0-r1}                 @ r0/r1<- vBB/vBB+1
-    ldmia   r3, {r2-r3}                 @ r2/r3<- vCC/vCC+1
+@    ldmia   r2, {r0-r1}                 @ r0/r1<- vBB/vBB+1
+@    ldmia   r3, {r2-r3}                 @ r2/r3<- vCC/vCC+1
+    fldd	d6, [r2, #0]
+    fldd	d7, [r3, #0]
     .if 0
     orrs    ip, r2, r3                  @ second arg (r2-r3) is zero?
     beq     common_errDivideByZero
@@ -5231,9 +5239,13 @@ d2i_doconv:
     FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
 
                                @ optional op; may set condition codes
-    bl      __aeabi_dsub                              @ result<- op, r0-r3 changed
+@    bl      __aeabi_dsub                              @ result<- op, r0-r3 changed
+    fsubd	d6, d6, d7
+
     GET_INST_OPCODE(ip)                 @ extract opcode from rINST
-    stmia   r9, {r0,r1}     @ vAA/vAA+1<- r0/r1
+@   stmia   r9, {r0,r1}     @ vAA/vAA+1<- r0/r1
+    fstd	d6, [r9, #0]
+
     GOTO_OPCODE(ip)                     @ jump to next instruction
     /* 14-17 instructions */
 
@@ -5267,8 +5279,10 @@ d2i_doconv:
     add     r9, rFP, r9, lsl #2         @ r9<- &fp[AA]
     add     r2, rFP, r2, lsl #2         @ r2<- &fp[BB]
     add     r3, rFP, r3, lsl #2         @ r3<- &fp[CC]
-    ldmia   r2, {r0-r1}                 @ r0/r1<- vBB/vBB+1
-    ldmia   r3, {r2-r3}                 @ r2/r3<- vCC/vCC+1
+@    ldmia   r2, {r0-r1}                 @ r0/r1<- vBB/vBB+1
+@    ldmia   r3, {r2-r3}                 @ r2/r3<- vCC/vCC+1
+    fldd	d6, [r2, #0]
+    fldd	d7, [r3, #0]
     .if 0
     orrs    ip, r2, r3                  @ second arg (r2-r3) is zero?
     beq     common_errDivideByZero
@@ -5276,9 +5290,13 @@ d2i_doconv:
     FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
 
                                @ optional op; may set condition codes
-    bl      __aeabi_dmul                              @ result<- op, r0-r3 changed
+@    bl      __aeabi_dmul                              @ result<- op, r0-r3 changed
+    fmuld	d6, d6, d7
+
     GET_INST_OPCODE(ip)                 @ extract opcode from rINST
-    stmia   r9, {r0,r1}     @ vAA/vAA+1<- r0/r1
+@    stmia   r9, {r0,r1}     @ vAA/vAA+1<- r0/r1
+    fstd	d6, [r9, #0]
+
     GOTO_OPCODE(ip)                     @ jump to next instruction
     /* 14-17 instructions */
 
@@ -5312,8 +5330,10 @@ d2i_doconv:
     add     r9, rFP, r9, lsl #2         @ r9<- &fp[AA]
     add     r2, rFP, r2, lsl #2         @ r2<- &fp[BB]
     add     r3, rFP, r3, lsl #2         @ r3<- &fp[CC]
-    ldmia   r2, {r0-r1}                 @ r0/r1<- vBB/vBB+1
-    ldmia   r3, {r2-r3}                 @ r2/r3<- vCC/vCC+1
+@    ldmia   r2, {r0-r1}                 @ r0/r1<- vBB/vBB+1
+@    ldmia   r3, {r2-r3}                 @ r2/r3<- vCC/vCC+1
+    fldd	d6, [r2, #0]
+    fldd	d7, [r3, #0]
     .if 0
     orrs    ip, r2, r3                  @ second arg (r2-r3) is zero?
     beq     common_errDivideByZero
@@ -5321,9 +5341,13 @@ d2i_doconv:
     FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
 
                                @ optional op; may set condition codes
-    bl      __aeabi_ddiv                              @ result<- op, r0-r3 changed
+@    bl      __aeabi_ddiv                              @ result<- op, r0-r3 changed
+    fdivd	d6, d6, d7
+
     GET_INST_OPCODE(ip)                 @ extract opcode from rINST
-    stmia   r9, {r0,r1}     @ vAA/vAA+1<- r0/r1
+@    stmia   r9, {r0,r1}     @ vAA/vAA+1<- r0/r1
+    fstd	d6, [r9, #0]
+
     GOTO_OPCODE(ip)                     @ jump to next instruction
     /* 14-17 instructions */
 
@@ -6467,8 +6491,10 @@ d2i_doconv:
     and     r9, r9, #15
     add     r1, rFP, r1, lsl #2         @ r1<- &fp[B]
     add     r9, rFP, r9, lsl #2         @ r9<- &fp[A]
-    ldmia   r1, {r2-r3}                 @ r2/r3<- vBB/vBB+1
-    ldmia   r9, {r0-r1}                 @ r0/r1<- vAA/vAA+1
+@    ldmia   r1, {r2-r3}                 @ r2/r3<- vBB/vBB+1
+@    ldmia   r9, {r0-r1}                 @ r0/r1<- vAA/vAA+1
+    fldd	d7, [r1, #0]
+    fldd	d6, [r9, #0]
     .if 0
     orrs    ip, r2, r3                  @ second arg (r2-r3) is zero?
     beq     common_errDivideByZero
@@ -6476,9 +6502,13 @@ d2i_doconv:
     FETCH_ADVANCE_INST(1)               @ advance rPC, load rINST
 
                                @ optional op; may set condition codes
-    bl      __aeabi_dadd                              @ result<- op, r0-r3 changed
+@    bl      __aeabi_dadd                              @ result<- op, r0-r3 changed
+    faddd	d6, d6, d7
+
     GET_INST_OPCODE(ip)                 @ extract opcode from rINST
-    stmia   r9, {r0,r1}     @ vAA/vAA+1<- r0/r1
+@    stmia   r9, {r0,r1}     @ vAA/vAA+1<- r0/r1
+    fstd	d6, [r9, #0]
+
     GOTO_OPCODE(ip)                     @ jump to next instruction
     /* 12-15 instructions */
 
@@ -6509,8 +6539,10 @@ d2i_doconv:
     and     r9, r9, #15
     add     r1, rFP, r1, lsl #2         @ r1<- &fp[B]
     add     r9, rFP, r9, lsl #2         @ r9<- &fp[A]
-    ldmia   r1, {r2-r3}                 @ r2/r3<- vBB/vBB+1
-    ldmia   r9, {r0-r1}                 @ r0/r1<- vAA/vAA+1
+@    ldmia   r1, {r2-r3}                 @ r2/r3<- vBB/vBB+1
+@    ldmia   r9, {r0-r1}                 @ r0/r1<- vAA/vAA+1
+    fldd	d7, [r1, #0]
+    fldd	d6, [r9, #0]
     .if 0
     orrs    ip, r2, r3                  @ second arg (r2-r3) is zero?
     beq     common_errDivideByZero
@@ -6518,9 +6550,13 @@ d2i_doconv:
     FETCH_ADVANCE_INST(1)               @ advance rPC, load rINST
 
                                @ optional op; may set condition codes
-    bl      __aeabi_dsub                              @ result<- op, r0-r3 changed
+@    bl      __aeabi_dsub                              @ result<- op, r0-r3 changed
+    fsubd	d6, d6, d7
+
     GET_INST_OPCODE(ip)                 @ extract opcode from rINST
-    stmia   r9, {r0,r1}     @ vAA/vAA+1<- r0/r1
+@    stmia   r9, {r0,r1}     @ vAA/vAA+1<- r0/r1
+    fstd	d6, [r9, #0]
+
     GOTO_OPCODE(ip)                     @ jump to next instruction
     /* 12-15 instructions */
 
@@ -6551,8 +6587,10 @@ d2i_doconv:
     and     r9, r9, #15
     add     r1, rFP, r1, lsl #2         @ r1<- &fp[B]
     add     r9, rFP, r9, lsl #2         @ r9<- &fp[A]
-    ldmia   r1, {r2-r3}                 @ r2/r3<- vBB/vBB+1
-    ldmia   r9, {r0-r1}                 @ r0/r1<- vAA/vAA+1
+@    ldmia   r1, {r2-r3}                 @ r2/r3<- vBB/vBB+1
+@    ldmia   r9, {r0-r1}                 @ r0/r1<- vAA/vAA+1
+    fldd	d7, [r1, #0]
+    fldd	d6, [r9, #0]
     .if 0
     orrs    ip, r2, r3                  @ second arg (r2-r3) is zero?
     beq     common_errDivideByZero
@@ -6560,9 +6598,13 @@ d2i_doconv:
     FETCH_ADVANCE_INST(1)               @ advance rPC, load rINST
 
                                @ optional op; may set condition codes
-    bl      __aeabi_dmul                              @ result<- op, r0-r3 changed
+@    bl      __aeabi_dmul                              @ result<- op, r0-r3 changed
+    fmuld	d6, d6, d7
+
     GET_INST_OPCODE(ip)                 @ extract opcode from rINST
-    stmia   r9, {r0,r1}     @ vAA/vAA+1<- r0/r1
+@    stmia   r9, {r0,r1}     @ vAA/vAA+1<- r0/r1
+    fstd	d6, [r9, #0]
+
     GOTO_OPCODE(ip)                     @ jump to next instruction
     /* 12-15 instructions */
 
@@ -6593,8 +6635,10 @@ d2i_doconv:
     and     r9, r9, #15
     add     r1, rFP, r1, lsl #2         @ r1<- &fp[B]
     add     r9, rFP, r9, lsl #2         @ r9<- &fp[A]
-    ldmia   r1, {r2-r3}                 @ r2/r3<- vBB/vBB+1
-    ldmia   r9, {r0-r1}                 @ r0/r1<- vAA/vAA+1
+@    ldmia   r1, {r2-r3}                 @ r2/r3<- vBB/vBB+1
+@    ldmia   r9, {r0-r1}                 @ r0/r1<- vAA/vAA+1
+    fldd	d7, [r1, #0]
+    fldd	d6, [r9, #0]
     .if 0
     orrs    ip, r2, r3                  @ second arg (r2-r3) is zero?
     beq     common_errDivideByZero
@@ -6602,9 +6646,13 @@ d2i_doconv:
     FETCH_ADVANCE_INST(1)               @ advance rPC, load rINST
 
                                @ optional op; may set condition codes
-    bl      __aeabi_ddiv                              @ result<- op, r0-r3 changed
+@    bl      __aeabi_ddiv                              @ result<- op, r0-r3 changed
+    fdivd	d6, d6, d7
+
     GET_INST_OPCODE(ip)                 @ extract opcode from rINST
-    stmia   r9, {r0,r1}     @ vAA/vAA+1<- r0/r1
+@    stmia   r9, {r0,r1}     @ vAA/vAA+1<- r0/r1
+    fstd	d6, [r9, #0]
+
     GOTO_OPCODE(ip)                     @ jump to next instruction
     /* 12-15 instructions */
 

速度測定に使用したプログラム

package com.example.helloandroid;

import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;

public class FPUtestDouble extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        TextView tv = new TextView(this);
        tv.setText("FPUtestDouble: \n"
        		+ testTime() + " : " + testResult() + "\n"
        		+ testTime() + " : " + testResult() + "\n"
        		+ testTime() + " : " + testResult() + "\n"
        		+ testTime() + " : " + testResult() + "\n"
        		+ testTime() + " : " + testResult() + "\n"
        		+ testTime() + " : " + testResult() + "\n"
        		+ testTime() + " : " + testResult() + "\n"
        		+ testTime() + " : " + testResult() + "\n"
        		+ testTime() + " : " + testResult() + "\n"
        		+ testTime() + " : " + testResult() + "\n");
        setContentView(tv);
    }
    
    double result;    
    
    String testResult() {
    	return Double.toString(result);
    }
    

    String testTime() {
    	long start, stop;
    	
    	start = System.currentTimeMillis();
    	result = test();
    	stop = System.currentTimeMillis();
    	return Long.toString(stop - start);
    }
    
    
    static final int COUNT = 100000;
    
    double test() {
    	double x, y, z, w;
    	x = y = z = w = 1.0f;
    	for (int i = 0; i < COUNT; i++) {
    		x += 0.0001d;
    		y -= 0.0001d;
    		z *= 1.0001d;
    		w /= 0.9999d;
    	}
    	return x + y + z + w;
    }
}


トラックバックURL

コメントする

名前
URL
 
  絵文字
 
 
記事検索
最新コメント
アクセスカウンター
  • 今日:
  • 昨日:
  • 累計:

QRコード
QRコード