私はプレゼンテーションのために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
。