Чтение (простой) сборки, чтобы найти вычисление времени компиляции в результате использования шаблонов C ++

Я нахожусь в процессе сравнения Fortran 90 с C ++ для презентации. Одно из моих сравнений основано на сборке, сгенерированной для простых программ g++ а также 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 используя g ++ 4.7.2 на OS X 10.7.4 x86_64-apple-darwin11.4.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, я прилагаю ее ниже. Обратите внимание, что хотя это известно во время компиляции, и я использую встроенный Фортран dot_product оператор, сгенерированная сборка существенно больше (130 строк против 90 строк в версии C ++), и кажется, что оптимизатор не может сократить операцию.

Программа (обратите внимание, что я использую встроенную, встроенную 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

Сборка (gfortran -S -O3 myprogram.cpp с использованием gcc 4.7.2 на OS X 10.7.4 x86_64-apple-darwin11.4.2)

    .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

Благодаря @ JerryCoffin’s answer, Я могу убедиться, что действительно, битовая структура

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,

2

Решение

Да — это:

LC0:
.long   0
.long   1081610240

Является ли битовый шаблон для двойника значением 3851. Так что происходит, что это:

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

…загружает это значение в регистр XMM, затем вызывает printf распечатать его. Я не могу сказать наверняка, но если бы мне пришлось угадывать, я бы сказал, 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,

7

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]