Fortran90(多次元配列その2)

配列代入が中で何をしているか気になって仕方がありません。GDBを使って見ていきます。
まずは、配列要素が1つで、次元数1つのプログラムで確認してみます。

a(1)

という整数を定義し、配列代入a=100を実行するプログラムです。

takk@deb9:~$ cat arr1x1.f90
      program main
        integer a(1)
        a = 100
        stop
      end
takk@deb9:~$ gfortran -g arr1x1.f90
takk@deb9:~$

GDBを起動します。

takk@deb9:~$ gfortran -g arr1x1.f90
takk@deb9:~$ gdb a.out

          ~

(gdb) l
1             program main
2               integer a(1)
3               a=100
4               stop
5             end
(gdb)

a=100の行にブレイクポイントを設定し実行します。

(gdb) b 3
Breakpoint 1 at 0x7d8: file arr1x1.f90, line 3.
(gdb) r
Starting program: /home/takk/a.out

Breakpoint 1, MAIN__ () at arr1x1.f90:3
3               a=100
(gdb) 

アセンブラを見てみましょう。

(gdb) disas
Dump of assembler code for function MAIN__:
   0x00005555555547d0 <+0>:     push   %rbp
   0x00005555555547d1 <+1>:     mov    %rsp,%rbp
   0x00005555555547d4 <+4>:     sub    $0x10,%rsp
=> 0x00005555555547d8 <+8>:     mov    $0x1,%eax
   0x00005555555547dd <+13>:    cmp    $0x1,%rax
   0x00005555555547e1 <+17>:    jg     0x5555555547f5 <MAIN__+37>
   0x00005555555547e3 <+19>:    lea    -0x1(%rax),%rdx
   0x00005555555547e7 <+23>:    movl   $0x64,-0x4(%rbp,%rdx,4)
   0x00005555555547ef <+31>:    add    $0x1,%rax
   0x00005555555547f3 <+35>:    jmp    0x5555555547dd <MAIN__+13>
   0x00005555555547f5 <+37>:    mov    $0x0,%esi
   0x00005555555547fa <+42>:    mov    $0x0,%edi
   0x00005555555547ff <+47>:    callq  0x555555554660 <_gfortran_stop_string@plt>
End of assembler dump.
(gdb)

100は、16進で0x64ですので、<+23>の行あたりで、a(1)へ配列代入しているものと思われます。<+35>の行のjmpは、アドレス0x5555555547ddに戻っているので配列のループを作っていますね。同アドレスでチェックしてます。
この作りを覚えておいて、次は二次元配列にした場合、どう変わるのか見てみます。

takk@deb9:~$ cat arr1x2.f90
      program main
        integer a(1,1)
        a=100
        stop
      end
takk@deb9:~$

アセンブラを見てみます。

(gdb) disas
Dump of assembler code for function MAIN__:
   0x00005555555547d0 <+0>:     push   %rbp
   0x00005555555547d1 <+1>:     mov    %rsp,%rbp
   0x00005555555547d4 <+4>:     sub    $0x10,%rsp
=> 0x00005555555547d8 <+8>:     mov    $0x1,%eax
   0x00005555555547dd <+13>:    cmp    $0x1,%rax
   0x00005555555547e1 <+17>:    jg     0x55555555480a <MAIN__+58>
   0x00005555555547e3 <+19>:    lea    -0x2(%rax),%rsi
   0x00005555555547e7 <+23>:    mov    $0x1,%edx
   0x00005555555547ec <+28>:    cmp    $0x1,%rdx
   0x00005555555547f0 <+32>:    jg     0x555555554804 <MAIN__+52>
   0x00005555555547f2 <+34>:    lea    (%rdx,%rsi,1),%rcx
   0x00005555555547f6 <+38>:    movl   $0x64,-0x4(%rbp,%rcx,4)
   0x00005555555547fe <+46>:    add    $0x1,%rdx
   0x0000555555554802 <+50>:    jmp    0x5555555547ec <MAIN__+28>
   0x0000555555554804 <+52>:    add    $0x1,%rax
   0x0000555555554808 <+56>:    jmp    0x5555555547dd <MAIN__+13>
   0x000055555555480a <+58>:    mov    $0x0,%esi
   0x000055555555480f <+63>:    mov    $0x0,%edi
   0x0000555555554814 <+68>:    callq  0x555555554660 <_gfortran_stop_string@plt>
End of assembler dump.
(gdb)

前に戻るjmpが2つになったので、次元数と一致します。要素数が1でもそれ以外でも関係なくこの作りになってそうです。
ではビルドの限界である七次元配列で確認してみます。要素数はそれぞれ2にしておきます。
確認に使ったプログラムはこれです。

takk@deb9:~$ cat arr2x7.f90
      program main
        integer a(2,2,2,2,2,2,2)
        a=100
        stop
      end
takk@deb9:~$

アセンブラです。

 (gdb) disas
Dump of assembler code for function MAIN__:
   0x00005555555547d0 <+0>:     push   %rbp
   0x00005555555547d1 <+1>:     mov    %rsp,%rbp
   0x00005555555547d4 <+4>:     push   %r15
   0x00005555555547d6 <+6>:     push   %r14
   0x00005555555547d8 <+8>:     push   %r13
   0x00005555555547da <+10>:    push   %r12
   0x00005555555547dc <+12>:    push   %rbx
   0x00005555555547dd <+13>:    sub    $0x208,%rsp
=> 0x00005555555547e4 <+20>:    mov    $0x1,%edi
   0x00005555555547e9 <+25>:    cmp    $0x2,%rdi
   0x00005555555547ed <+29>:    jg     0x5555555548c3 <MAIN__+243>
   0x00005555555547f3 <+35>:    mov    %rdi,%rax
   0x00005555555547f6 <+38>:    shl    $0x6,%rax
   0x00005555555547fa <+42>:    lea    -0x7f(%rax),%rbx
   0x00005555555547fe <+46>:    mov    $0x1,%r8d
   0x0000555555554804 <+52>:    cmp    $0x2,%r8
   0x0000555555554808 <+56>:    jg     0x5555555548ba <MAIN__+234>
   0x000055555555480e <+62>:    mov    %r8,%rax
   0x0000555555554811 <+65>:    shl    $0x5,%rax
   0x0000555555554815 <+69>:    lea    (%rax,%rbx,1),%r12
   0x0000555555554819 <+73>:    mov    $0x1,%r9d
   0x000055555555481f <+79>:    cmp    $0x2,%r9
   0x0000555555554823 <+83>:    jg     0x5555555548b1 <MAIN__+225>
   0x0000555555554829 <+89>:    mov    %r9,%rax
   0x000055555555482c <+92>:    shl    $0x4,%rax
   0x0000555555554830 <+96>:    lea    (%rax,%r12,1),%r13
   0x0000555555554834 <+100>:   mov    $0x1,%eax
   0x0000555555554839 <+105>:   cmp    $0x2,%rax
   0x000055555555483d <+109>:   jg     0x5555555548a8 <MAIN__+216>
   0x000055555555483f <+111>:   lea    0x0(,%rax,8),%rdx
   0x0000555555554847 <+119>:   lea    (%rdx,%r13,1),%r14
   0x000055555555484b <+123>:   mov    $0x1,%edx
   0x0000555555554850 <+128>:   cmp    $0x2,%rdx
   0x0000555555554854 <+132>:   jg     0x5555555548a2 <MAIN__+210>
   0x0000555555554856 <+134>:   lea    0x0(,%rdx,4),%rcx
   0x000055555555485e <+142>:   lea    (%rcx,%r14,1),%r15
   0x0000555555554862 <+146>:   mov    $0x1,%ecx
   0x0000555555554867 <+151>:   cmp    $0x2,%rcx
   0x000055555555486b <+155>:   jg     0x55555555489c <MAIN__+204>
   0x000055555555486d <+157>:   lea    (%rcx,%rcx,1),%rsi
   0x0000555555554871 <+161>:   lea    (%rsi,%r15,1),%r11
   0x0000555555554875 <+165>:   mov    $0x1,%esi
   0x000055555555487a <+170>:   cmp    $0x2,%rsi
   0x000055555555487e <+174>:   jg     0x555555554896 <MAIN__+198>
   0x0000555555554880 <+176>:   lea    (%rsi,%r11,1),%r10
   0x0000555555554884 <+180>:   movl   $0x64,-0x230(%rbp,%r10,4)
   0x0000555555554890 <+192>:   add    $0x1,%rsi
   0x0000555555554894 <+196>:   jmp    0x55555555487a <MAIN__+170>
   0x0000555555554896 <+198>:   add    $0x1,%rcx
   0x000055555555489a <+202>:   jmp    0x555555554867 <MAIN__+151>
   0x000055555555489c <+204>:   add    $0x1,%rdx
   0x00005555555548a0 <+208>:   jmp    0x555555554850 <MAIN__+128>
   0x00005555555548a2 <+210>:   add    $0x1,%rax
   0x00005555555548a6 <+214>:   jmp    0x555555554839 <MAIN__+105>
   0x00005555555548a8 <+216>:   add    $0x1,%r9
   0x00005555555548ac <+220>:   jmpq   0x55555555481f <MAIN__+79>
   0x00005555555548b1 <+225>:   add    $0x1,%r8
   0x00005555555548b5 <+229>:   jmpq   0x555555554804 <MAIN__+52>
   0x00005555555548ba <+234>:   add    $0x1,%rdi
   0x00005555555548be <+238>:   jmpq   0x5555555547e9 <MAIN__+25>
   0x00005555555548c3 <+243>:   mov    $0x0,%esi
   0x00005555555548c8 <+248>:   mov    $0x0,%edi
   0x00005555555548cd <+253>:   callq  0x555555554660 <_gfortran_stop_string@plt>
End of assembler dump.
(gdb)

予想通り配列処理のループを作っているjmpが7つあります。(jmpqが混ざってますが)
配列代入といえども、一つずつ代入していることには変わりありませんね。

Leave a Reply

Your email address will not be published. Required fields are marked *

CAPTCHA