2016-02-05 11 views
7

Prima di tutto sto sviluppando per un microcontrollore in modo RAM e ROM utilizzo sono le priorità.GCC non ottimizza una copia struct del const static Non inizializzato

Mi rendo conto che può leggere come un bug report o non abbastanza specifica. Se non ottengo alcuna risposta qui, la archiverò come tale.

Mi piace usare le strutture static const per inizializzare strutture a pila ai valori predefiniti. Nella maggior parte dei casi la struttura predefinita è tutti zero. Io preferisco farlo con le strutture static const piuttosto che un memset (memset or struct assignment, static const assignment)

mio toolchain attuale è arm-none-eabi-gcc-4_7_3, compilazione per un target Cortex M4 con l'ottimizzazione -Os.

ho notato quanto segue; GCC produce codice diverso se inizializzo esplicitamente il mio static const struct a zero che se non lo faccio (static const struct foo; vs static const struct foo = {0};). In particolare, alloca le strutture static const non inizializzate in memoria ed esegue operazioni di copia.

Ecco un esempio di codice:

struct foo {int foo; int bar;}; 
struct bar {int bar[20];}; 

static const struct foo foo1_init, foo2_init = {0}; 
static const struct bar bar1_init, bar2_init = {0}; 

extern struct foo foo1, foo2; 
extern struct bar bar1, bar2; 

void init_foo1(void) 
{ 
    foo1 = foo1_init; 
} 

void init_foo2(void) 
{ 
    foo2 = foo2_init; 
} 

void init_bar1(void) 
{ 
    bar1 = bar1_init; 
} 

void init_bar2(void) 
{ 
    bar2 = bar2_init; 
} 

Compilato, questo produce i seguenti assembler che elenca (riarrangiato e tagliati per brevità):

396     .section .bss.foo1_init,"aw",%nobits 
397     .align 2 
398     .set .LANCHOR0,. + 0 
401    foo1_init: 
402 0000 00000000  .space 8 
402  00000000 

    40    .L2: 
    41 0010 00000000  .word .LANCHOR0 
    42 0014 00000000  .word foo1 

    55:     **** foo1 = foo1_init; 
    32     .loc 1 55 0 
    33 0000 034A   ldr r2, .L2 
    34 0002 044B   ldr r3, .L2+4 
    35 0004 92E80300  ldmia r2, {r0, r1} 
    36 0008 83E80300  stmia r3, {r0, r1} 


    67    .L5: 
    68 000c 00000000  .word foo2 

    60:     **** foo2 = foo2_init; 
    60 0000 024B   ldr r3, .L5 
    61 0002 0022   movs r2, #0 
    62 0004 1A60   str r2, [r3, #0] 
    63 0006 5A60   str r2, [r3, #4] 


389     .section .bss.bar1_init,"aw",%nobits 
390     .align 2 
391     .set .LANCHOR1,. + 0 
394    bar1_init: 
395 0000 00000000  .space 80 
395  00000000 
395  00000000 
395  00000000 
395  00000000 

    98    .L8: 
    99 0010 00000000  .word .LANCHOR1 
100 0014 00000000  .word bar1 

    65:     **** bar1 = bar1_init; 
    89     .loc 1 65 0 
    90 0002 0349   ldr r1, .L8 
    91 0004 0348   ldr r0, .L8+4 
    92 0006 5022   movs r2, #80 
    93 0008 FFF7FEFF  bl memcpy 


130    .L11: 
131 0010 00000000  .word bar2 

70:     **** bar2 = bar2_init; 
121     .loc 1 70 0 
122 0002 0021   movs r1, #0 
123 0004 5022   movs r2, #80 
124 0006 0248   ldr r0, .L11 
125 0008 FFF7FEFF  bl memset 

possiamo vedere che per foo2 = init_foo2 e bar2 = init_bar2 il compilatore ha ottimizzato le copie basso per memorizzare zeri per foo2 direttamente o chiamando memset per bar2.

Possiamo vedere che per foo1 = init_foo1 e bar1 = init_bar1 il compilatore sta eseguendo copie espliciti, il caricamento e il salvataggio di dai registri per foo1 e chiedendo memcpy per foo2.

ho alcune domande:

  1. E` previsto operazione GCC? Mi aspetto che le strutture non inizializzate static const seguano lo stesso percorso all'interno di GCC come le strutture inizializzate di static const e quindi producano lo stesso output.
  2. Accade questo per altre versioni di ARM GCC? Non ho altre versioni a portata di mano, e tutti i compilatori online degli assembly C sono in realtà C++.
  3. Questo succede per altre architetture di destinazione di GCC? Ancora una volta, non ho altre versioni a portata di mano.
+0

Potrebbe modificare il codice per la coerenza? Attualmente si riferisce a 'foo1_init' ecc., Che non sono definiti nel tuo codice (al suo posto definisce' init_foo1'). Immagino sia solo un refuso, dato che hai 'init_foo1' come una variabile e una funzione nello stesso scope. –

+0

Una chiamata a 'memcpy()' è abbastanza economica in termini di spazio, l'hai confrontata con quello che costerebbe inserire le copie in linea? Forse c'è un'euristica che emette la chiamata quando il numero di byte è abbastanza grande. – unwind

+0

@Ian Effettivamente un errore di battitura. Originariamente avevo una singola funzione chiamata qualcos'altro ma che rendeva l'output dell'assembly difficile da comprendere. –

risposta

-1

Ho provato su amd64 e con mia sorpresa sembra un comportamento coerente (ma non so se si tratta di un bug). gcc inserisce foo1_init e bar1_init nel segmento di dati comuni o il segmento di valori inizializzati a zero dal sistema operativo (.bss). foo2_init e bar2_init vengono inseriti nel segmento di sola lettura (.rodata) come se fossero valori inizializzati diversi da zero. È possibile vederlo usando -O0. Poiché non stai utilizzando un sistema operativo, la sezione inizializzata del sistema operativo viene inizializzata manualmente da gcc e/o dal linker e quindi copiata. gcc ottimizza i valori dei rodata creando il memset diretto ed eliminando le variabili dead * 2_init. clang ottimizza entrambi i casi allo stesso modo, però.

di seguito riportata uscita gcc (-O0):

.file "defs.c" 
    .local foo1_init 
    .comm foo1_init,8,8 
    .section .rodata 
    .align 8 
    .type foo2_init, @object 
    .size foo2_init, 8 
foo2_init: 
    .zero 8 
    .local bar1_init 
    .comm bar1_init,80,32 
    .align 32 
    .type bar2_init, @object 
    .size bar2_init, 80 
bar2_init: 
    .zero 80 
    .text 
    .globl init_foo1 
    .type init_foo1, @function 
init_foo1: 
.LFB0: 
    .cfi_startproc 
    pushq %rbp 
    .cfi_def_cfa_offset 16 
    .cfi_offset 6, -16 
    movq %rsp, %rbp 
    .cfi_def_cfa_register 6 
    movq foo1_init(%rip), %rax 
    movq %rax, foo1(%rip) 
    nop 
    popq %rbp 
    .cfi_def_cfa 7, 8 
    ret 
    .cfi_endproc 
.LFE0: 
    .size init_foo1, .-init_foo1 
    .globl init_foo2 
    .type init_foo2, @function 
init_foo2: 
.LFB1: 
    .cfi_startproc 
    pushq %rbp 
    .cfi_def_cfa_offset 16 
    .cfi_offset 6, -16 
    movq %rsp, %rbp 
    .cfi_def_cfa_register 6 
    movq $0, foo2(%rip) 
    nop 
    popq %rbp 
    .cfi_def_cfa 7, 8 
    ret 
    .cfi_endproc 
.LFE1: 
    .size init_foo2, .-init_foo2 
    .globl init_bar1 
    .type init_bar1, @function 
init_bar1: 
.LFB2: 
    .cfi_startproc 
    pushq %rbp 
    .cfi_def_cfa_offset 16 
    .cfi_offset 6, -16 
    movq %rsp, %rbp 
    .cfi_def_cfa_register 6 
    movq bar1_init(%rip), %rax 
    movq %rax, bar1(%rip) 
    movq bar1_init+8(%rip), %rax 
    movq %rax, bar1+8(%rip) 
    movq bar1_init+16(%rip), %rax 
    movq %rax, bar1+16(%rip) 
    movq bar1_init+24(%rip), %rax 
    movq %rax, bar1+24(%rip) 
    movq bar1_init+32(%rip), %rax 
    movq %rax, bar1+32(%rip) 
    movq bar1_init+40(%rip), %rax 
    movq %rax, bar1+40(%rip) 
    movq bar1_init+48(%rip), %rax 
    movq %rax, bar1+48(%rip) 
    movq bar1_init+56(%rip), %rax 
    movq %rax, bar1+56(%rip) 
    movq bar1_init+64(%rip), %rax 
    movq %rax, bar1+64(%rip) 
    movq bar1_init+72(%rip), %rax 
    movq %rax, bar1+72(%rip) 
    nop 
    popq %rbp 
    .cfi_def_cfa 7, 8 
    ret 
    .cfi_endproc 
.LFE2: 
    .size init_bar1, .-init_bar1 
    .globl init_bar2 
    .type init_bar2, @function 
init_bar2: 
.LFB3: 
    .cfi_startproc 
    pushq %rbp 
    .cfi_def_cfa_offset 16 
    .cfi_offset 6, -16 
    movq %rsp, %rbp 
    .cfi_def_cfa_register 6 
    movl $bar2, %eax 
    movl $80, %ecx 
    movl $0, %esi 
    movq %rsi, (%rax) 
    movl %ecx, %edx 
    addq %rax, %rdx 
    addq $8, %rdx 
    movq %rsi, -16(%rdx) 
    leaq 8(%rax), %rdx 
    andq $-8, %rdx 
    subq %rdx, %rax 
    addl %eax, %ecx 
    andl $-8, %ecx 
    movl %ecx, %eax 
    shrl $3, %eax 
    movl %eax, %ecx 
    movq %rdx, %rdi 
    movq %rsi, %rax 
    rep stosq 
    nop 
    popq %rbp 
    .cfi_def_cfa 7, 8 
    ret 
    .cfi_endproc 
.LFE3: 
    .size init_bar2, .-init_bar2 
    .ident "GCC: (GNU) 6.3.1 20170306" 
    .section .note.GNU-stack,"",@progbits 
Problemi correlati