2

私はプレゼンテーションのためにFortran90とC++を比較しているところです。g++私の比較の1つは、とによって単純なプログラム用に生成されたアセンブリに依存していgfortranます。

一例は次のようになります。

#include<cstdio> // quick and dirty number formatting

template<int N>
double dot(double x[], double y[]){
  return x[N-1] * y[N-1] + dot<N-1>(x, y);
}

template<>
double dot<1>(double x[], double y[]){
  return x[0] * y[0];
}
    
int main(){
  double x[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
  double y[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
  printf("x.y = %23.16E\n", dot<10>(x, y));
}

次のアセンブラはg++ -S -O3 myprogram.cpp、OS X10.7.4x86_64-apple-darwin11.4.2でg++4.7.2を使用するコマンドによって生成されます。

    .text
    .align 4,0x90
    .globl __Z3dotILi1EEdPdS0_
__Z3dotILi1EEdPdS0_:
LFB2:
    movsd   (%rdi), %xmm0
    mulsd   (%rsi), %xmm0
    ret
LFE2:
    .cstring
LC1:
    .ascii "x.y = %23.16E\12\0"
    .section __TEXT,__text_startup,regular,pure_instructions
    .align 4
    .globl _main
_main:
LFB3:
    leaq    LC1(%rip), %rdi
    subq    $8, %rsp
LCFI0:
    movl    $1, %eax
    movsd   LC0(%rip), %xmm0
    call    _printf
    xorl    %eax, %eax
    addq    $8, %rsp
LCFI1:
    ret
LFE3:
    .literal8
    .align 3
LC0:
    .long   0
    .long   1081610240
    .section __TEXT,__eh_frame,coalesced,no_toc+strip_static_syms+live_support
EH_frame1:
    .set L$set$0,LECIE1-LSCIE1
    .long L$set$0
LSCIE1:
    .long   0
    .byte   0x1
    .ascii "zR\0"
    .byte   0x1
    .byte   0x78
    .byte   0x10
    .byte   0x1
    .byte   0x10
    .byte   0xc
    .byte   0x7
    .byte   0x8
    .byte   0x90
    .byte   0x1
    .align 3
LECIE1:
LSFDE1:
    .set L$set$1,LEFDE1-LASFDE1
    .long L$set$1
LASFDE1:
    .long   LASFDE1-EH_frame1
    .quad   LFB2-.
    .set L$set$2,LFE2-LFB2
    .quad L$set$2
    .byte   0
    .align 3
LEFDE1:
LSFDE3:
    .set L$set$3,LEFDE3-LASFDE3
    .long L$set$3
LASFDE3:
    .long   LASFDE3-EH_frame1
    .quad   LFB3-.
    .set L$set$4,LFE3-LFB3
    .quad L$set$4
    .byte   0
    .byte   0x4
    .set L$set$5,LCFI0-LFB3
    .long L$set$5
    .byte   0xe
    .byte   0x10
    .byte   0x4
    .set L$set$6,LCFI1-LCFI0
    .long L$set$6
    .byte   0xe
    .byte   0x8
    .align 3
LEFDE3:
    .constructor
    .destructor
    .align 1
    .subsections_via_symbols

内積は385で、コンパイル時に計算されたようですが、正確な場所が見つからないようです。次のアセンブラセグメントのどこかにあると思います。

    movl    $1, %eax
    movsd   LC0(%rip), %xmm0
    call    _printf
    xorl    %eax, %eax
    addq    $8, %rsp
LCFI1:
    ret
LFE3:
    .literal8
    .align 3
LC0:
    .long   0
    .long   1081610240
    .section __TEXT,__eh_frame,coalesced,no_toc+strip_static_syms+live_support

アセンブリについての私の(非常に非常に限られた)理解では、ドット積がコンパイラによって計算され、レジスタ(LC0)に配置されたことがわかります。次に、命令は値を文字列に配置し、結果のフォーマットされmovsd LC0(%rip), %xmm0た文字列を呼び出します。printf

これは本当ですか?実際の数385はこの出力のどこかに含まれていますか、それとも他の方法で計算されていますか?

ありがとうございました!

編集:

gfortranによって作成されたアセンブリがどのように見えるか疑問に思われる方のために、以下に添付します。コンパイル時に既知であり、Fortranの組み込みdot_product演算子を使用している場合でも、生成されるアセンブリは大幅に大きくなり(C ++バージョンでは90行に対して130行)、オプティマイザーでは削減できないようです。手術。

プログラム(組み込みの組み込みdot_product演算子を使用していることに注意してください):

PROGRAM MAIN
  REAL(8), DIMENSION(10):: X = (/1, 2, 3, 4, 5, 6, 7, 8, 9, 10/)
  REAL(8), DIMENSION(10):: Y = (/1, 2, 3, 4, 5, 6, 7, 8, 9, 10/)
  PRINT "(A, E23.16)", "x.y = ", DOT_PRODUCT(X, Y)
ENDPROGRAM MAIN

アセンブリ(OS X10.7.4x86_64-apple-darwin11.4.2でgcc4.7.2を使用するgfortran-S-O3 myprogram.cpp)

    .cstring
LC0:
    .ascii "dotproduct-intrinsic.f90\0"
    .const
LC1:
    .ascii "(A, E23.16)"
LC2:
    .ascii "x.y = "
    .text
    .align 4,0x90
_MAIN__:
LFB0:
    leaq    LC0(%rip), %rax
    subq    $504, %rsp
LCFI0:
    movq    %rax, 24(%rsp)
    leaq    16(%rsp), %rdi
    leaq    LC1(%rip), %rax
    movl    $5, 32(%rsp)
    movq    %rax, 88(%rsp)
    movl    $11, 96(%rsp)
    movl    $4096, 16(%rsp)
    movl    $6, 20(%rsp)
    call    __gfortran_st_write
    leaq    16(%rsp), %rdi
    movl    $6, %edx
    leaq    LC2(%rip), %rsi
    call    __gfortran_transfer_character_write
    leaq    8(%rsp), %rsi
    movl    $8, %edx
    movabsq $4645480607818711040, %rax
    leaq    16(%rsp), %rdi
    movq    %rax, 8(%rsp)
    call    __gfortran_transfer_real_write
    leaq    16(%rsp), %rdi
    call    __gfortran_st_write_done
    addq    $504, %rsp
LCFI1:
    ret
LFE0:
    .section __TEXT,__text_startup,regular,pure_instructions
    .align 4
    .globl _main
_main:
LFB1:
    subq    $8, %rsp
LCFI2:
    call    __gfortran_set_args
    leaq    _options.3.1864(%rip), %rsi
    movl    $8, %edi
    call    __gfortran_set_options
    call    _MAIN__
    xorl    %eax, %eax
    addq    $8, %rsp
LCFI3:
    ret
LFE1:
    .const
    .align 5
_options.3.1864:
    .long   68
    .long   1023
    .long   0
    .long   0
    .long   1
    .long   1
    .long   0
    .long   1
    .section __TEXT,__eh_frame,coalesced,no_toc+strip_static_syms+live_support
EH_frame1:
    .set L$set$0,LECIE1-LSCIE1
    .long L$set$0
LSCIE1:
    .long   0
    .byte   0x1
    .ascii "zR\0"
    .byte   0x1
    .byte   0x78
    .byte   0x10
    .byte   0x1
    .byte   0x10
    .byte   0xc
    .byte   0x7
    .byte   0x8
    .byte   0x90
    .byte   0x1
    .align 3
LECIE1:
LSFDE1:
    .set L$set$1,LEFDE1-LASFDE1
    .long L$set$1
LASFDE1:
    .long   LASFDE1-EH_frame1
    .quad   LFB0-.
    .set L$set$2,LFE0-LFB0
    .quad L$set$2
    .byte   0
    .byte   0x4
    .set L$set$3,LCFI0-LFB0
    .long L$set$3
    .byte   0xe
    .byte   0x80,0x4
    .byte   0x4
    .set L$set$4,LCFI1-LCFI0
    .long L$set$4
    .byte   0xe
    .byte   0x8
    .align 3
LEFDE1:
LSFDE3:
    .set L$set$5,LEFDE3-LASFDE3
    .long L$set$5
LASFDE3:
    .long   LASFDE3-EH_frame1
    .quad   LFB1-.
    .set L$set$6,LFE1-LFB1
    .quad L$set$6
    .byte   0
    .byte   0x4
    .set L$set$7,LCFI2-LFB1
    .long L$set$7
    .byte   0xe
    .byte   0x10
    .byte   0x4
    .set L$set$8,LCFI3-LCFI2
    .long L$set$8
    .byte   0xe
    .byte   0x8
    .align 3
LEFDE3:
    .subsections_via_symbols

編集2

@JerryCoffinの回答のおかげで、確かにビットパターンを確認できます

LC0:
    .long   0
    .long   1081610240

アセンブリ出力にあるのは、番号385に対応します。

@JerryCoffinが提供するのとまったく同じプログラムを使用しました。

#include <stdio.h>


    #pragma pack(1)
    struct x {
        long x, y;
    };    
    
    int main() { 
        x v = {0, 1081610240};
    
        printf("%f\n", *(double *)&v);
        return 0;
    }

32ビットターゲットを使用してコンパイルする必要があるという唯一の注意点がありますg++ verification.cpp -m32

4

1 に答える 1

7

はい、これ:

LC0:
    .long   0
    .long   1081610240

値が 385 1の double のビット パターンです。何が起こっているかというと、次のようになります。

LCFI0:
    movl    $1, %eax
    movsd   LC0(%rip), %xmm0
    call    _printf

...その値を XMM レジスタにロードし、呼び出しprintfて出力します。確かなことは言えませんが、推測する必要があるとすれば、1は、出力される 1 つのパラメーターを渡していることを示していると言えます。


1それを確認したい場合は、これを試してください。

#include <stdio.h>

#pragma pack(1)
struct x {
    long x, y;
};    

int main() { 
    x v = {0, 1081610240};

    printf("%f\n", *(double *)&v);
    return 0;
}

もちろん、公式には、これは移植性がありません。しかし、同じマシンに同じコンパイラを使用すると、99% の確率で、私が行ったのと同じ出力が得られます -- 385.

于 2013-01-26T00:46:57.507 に答える