2026-08-18

東大版Palo Alto Tiny BASICのGETIルーチンをamd64に移植するとLEA命令を使う

SDK-80のシリアルポートにASR-33が接続された環境を想定している東大版Palo Alto Tiny BASICをWSL2Ubuntu環境に移植しています。Geminiと相談しながら作業しています。BASICというものは、編集環境と実行環境が統合されているところに真髄があるのですが、まず編集環境の方から移植を進めています。数字文字列を2進数に変換するために「GETI」というルーチンがあります。これをamd64にしてみます。

 

オリジナルは次のようになっています。

GINT:  LXI   H,0000H        ;GET INTEGER
       MOV   B,H
       CALL  SKPBL
GETI1: CPI   '0'
       RC                    ;RETURN INTEGER IN HL
       CPI   '9'+1
       RNC
       MVI   A,0F0H
       ANA   H                ;IF INTEGER>#0FFF ERHOW
       JNZ   ERHOW
       INR   B
       PUSH  B
       MOV   B,H            ;HL HL+10
       MOV   C,L
       DAD   H
       DAD   H
       DAD   B
       DAD   H
       LDAX  D                ;HL HL+(DE)&#0F
       INX   D
       ANI   0FH
       ADD   L
       MOV   L,A
       MVI   A,00H
       ADC   H
       MOV   H,A
       POP   B
       LDAX  D
       JM    ERHOW
       JMP   GETI1

 

Geminiの指導を受けながらamd64に移植したら、次のようになりました。

.equ    GINT_DIGIT_MAX,        (NINE-ZERO)
.equ    GINT_MAX_BEFORE_X10,    0x0FFF
gint:    xor    eax,eax
    xor    ecx,ecx
    call    skpbl
geti1:    movzx    edx,byte ptr [rdi]
    sub    edx,ZERO
    cmp    edx,GINT_DIGIT_MAX
    ja    geti9
    cmp    ax,GINT_MAX_BEFORE_X10
    ja    erhow
    inc    cx
    # amd64の真骨頂: LEA命令による AX = (AX * 10) + DX
    lea    eax,[rax + rax*4]
    lea    eax,[rdx + rax*2]
    inc    rdi
    test    ax,ax
    js    erhow
    jmp    geti1
geti9:    ret

amd64と比べるのは卑怯かもしれませんが、i8080は命令が貧弱です。レジスタの内容を10倍するのも、簡単にはできません。一方amd64は、IMUL命令で簡単に10倍できるはずですが、Geminiが提示してきたのはLEA命令を使う方法でした。なぜIMUL命令を使わないでLEA命令なのかとGeminiに問うと、内部処理の都合上この方が速いのだそうです。ここがボトルネックという訳ではないので、微妙に速くなっても全体としては速さを意識できないと思います。しかし、いかにもamd64チューニングされているという感じにはなりました。 

0 件のコメント:

コメントを投稿