2012-07-03 12 views
7

qual è la grande differenza tra un puntatore globale e un riferimento globale per l'ottimizzatore VS2010? perché il riferimento non è risolto?vengono risolti dall'ottimizzatore, ma non i riferimenti, perché?

typedef unsigned char byte_t; 
typedef unsigned short word_t; 

struct byte_reg_t 
{ 
    byte_t low; 
    byte_t high; 
}; 

union word_reg_t 
{ 
    word_t value; 
    byte_reg_t part; 
}; 

word_reg_t r16; 

byte_t& low_ref = r16.part.low; 
byte_t* const low_ptr = &r16.part.low; 

#define SPLIT() _asm nop; 

int main() 
{ 
    low_ref = 4; 
    SPLIT() 

    byte_t a = r16.part.low; 
    SPLIT() 

    byte_t b = low_ref; 
    SPLIT() 

    byte_t c = *low_ptr; 
    SPLIT() 

    return a+b+c; 
} 

compilato in uscita-Mode con uscita Assemblea produrre questo si traduce

;byte_t a = r16.part.low; 
mov cl, BYTE PTR [email protected]@[email protected]@A 

;byte_t b = low_ref; 
mov edx, DWORD PTR [email protected]@3AAEA ; low_ref 
mov dl, BYTE PTR [edx] 

;byte_t c = *low_ptr; 
mov al, BYTE PTR [email protected]@[email protected]@A 

smontaggio non modificato

.text:00401000 _main   proc near    ; CODE XREF: __tmainCRTStartup+11D 
.text:00401000     mov  eax, [email protected]@3AAEA ; uchar & low_ref 
.text:00401005     mov  byte ptr [eax], 4 
.text:00401008     nop 
.text:00401009     mov  cl, [email protected]@[email protected]@A ; word_reg_t r16 
.text:0040100F     nop 
.text:00401010     mov  edx, [email protected]@3AAEA ; uchar & low_ref 
.text:00401016     mov  dl, [edx] 
.text:00401018     nop 
.text:00401019     mov  al, [email protected]@[email protected]@A ; word_reg_t r16 
.text:0040101E     nop 
.text:0040101F     movzx eax, al 
.text:00401022     movzx edx, dl 
.text:00401025     movzx ecx, cl 
.text:00401028     add  eax, edx 
.text:0040102A     add  eax, ecx 
.text:0040102C     retn 
.text:0040102C _main   endp 

.data:00403374 [email protected]@[email protected]@A db ?    ; DATA XREF: _main+9 
.data:00403374           ; _main+19 
.data:00403375     align 4 

.data:00403018 ; unsigned char & low_ref 
.data:00403018 [email protected]@3AAEA dd offset [email protected]@[email protected]@A ; DATA XREF: _main 
.data:00403018           ; _main+10 
.data:00403018           ; word_reg_t r16 

Ho testato diverse varianti (di ritorno dalla funzione, ecc) - non risolvere se il low_ref è in uso

  • è l'ottimizzatore stupido?
  • un caso raro per l'ottimizzazione?
  • alcune restrizioni standard c/C++?

UPDATE

Sembra essere un caso raro per ottimizzazione - thx Michael Burr

funziona se il riferimento è in un ambito funzione - o all'interno di una classe o struttura un'istanza in funzione scope (ma la sua ancora strano che l'ottimizzatore risolve const PTR ma non referenze - identiche al 100%)

UPDATE 2

è ancora più strano - se si passa da byte_t a int entrambi resolvings funziona - const PTR e riferimento

  • PTR const globale alla global byte_t var: risolto
  • PTR const globale per int globale var: risolto
  • riferimento globale al globale byte_t var: non risolto
  • globale riferimento ENCE al globale int var: risolto
  • riferimento globale al locale var byte_t: risolto
  • riferimento globale per int locale var: risolto

quindi c'è una piccola differenza nel ottimizzatore per ptr const e riferimenti, lo scope di riferimento ..... e il tipo di riferimento ... a volte :)

UPDATE 3

testcode più semplice - verificato con VS2010 e clang 3.1

typedef unsigned char byte_t; 
typedef unsigned int dword_t; 

//for msvc 
#define SPLIT() _asm nop _asm nop; 
//for clang 
//#define SPLIT() asm("nop"); asm("nop"); 

byte_t byte; 
dword_t dword; 

byte_t& global_ref_byte = byte; 
dword_t& global_ref_dword = dword; 

byte_t* const global_ptrc_byte = &byte; 
dword_t* const global_ptrc_dword = &dword; 

int main(int argc, char** argv) 
{ 
    byte_t& local_ref_byte = byte; 
    dword_t& local_ref_dword = dword; 

    dword_t random = (dword_t)argv; 

    byte = (byte_t)random; 
    dword = (dword_t)random; 
    SPLIT() 

    byte_t a = global_ref_byte; 
    SPLIT() 

    dword_t b = global_ref_dword; 
    SPLIT() 

    byte_t c = *global_ptrc_byte; 
    SPLIT() 

    dword_t d = *global_ptrc_dword; 
    SPLIT() 

    byte_t e = local_ref_byte; 
    SPLIT() 

    dword_t f = local_ref_dword; 
    SPLIT() 

    dword_t result = a+b+c+d+e+f; 

    return result; 
} 

VS2010 smontaggio

.text:00401000 ; int __cdecl main(int argc, const char **argv, const char **envp) 
.text:00401000 _main   proc near    ; CODE XREF: ___tmainCRTStartup+11D 
.text:00401000 
.text:00401000 argc   = dword ptr 8 
.text:00401000 argv   = dword ptr 0Ch 
.text:00401000 envp   = dword ptr 10h 
.text:00401000 
.text:00401000     push ebp 
.text:00401001     mov  ebp, esp 
.text:00401003     mov  eax, [ebp+argv] 
.text:00401006     push ebx 
.text:00401007     push esi 
.text:00401008     push edi 
.text:00401009     mov  byte_403374, al 
.text:0040100E     mov  dword_403378, eax 
.text:00401013     nop 
.text:00401014     nop 
.text:00401015     mov  eax, off_40301C 
.text:0040101A     mov  al, [eax] 
.text:0040101C     nop 
.text:0040101D     nop 
.text:0040101E     mov  ecx, dword_403378 
.text:00401024     nop 
.text:00401025     nop 
.text:00401026     mov  dl, byte_403374 
.text:0040102C     nop 
.text:0040102D     nop 
.text:0040102E     mov  esi, dword_403378 
.text:00401034     nop 
.text:00401035     nop 
.text:00401036     mov  bl, byte_403374 
.text:0040103C     nop 
.text:0040103D     nop 
.text:0040103E     mov  edi, dword_403378 
.text:00401044     nop 
.text:00401045     nop 
.text:00401046     movzx edx, dl 
.text:00401049     movzx ebx, bl 
.text:0040104C     add  edx, edi 
.text:0040104E     movzx eax, al 
.text:00401051     add  edx, ebx 
.text:00401053     add  eax, edx 
.text:00401055     pop  edi 
.text:00401056     add  eax, esi 
.text:00401058     pop  esi 
.text:00401059     add  eax, ecx 
.text:0040105B     pop  ebx 
.text:0040105C     pop  ebp 
.text:0040105D     retn 
.text:0040105D _main   endp 

clang 3,1 smontaggio

.text:004012E0 sub_4012E0  proc near    ; CODE XREF: sub_401020+91 
.text:004012E0 
.text:004012E0 arg_4   = dword ptr 0Ch 
.text:004012E0 
.text:004012E0     push ebp 
.text:004012E1     mov  ebp, esp 
.text:004012E3     call sub_4014F0 
.text:004012E8     mov  eax, [ebp+arg_4] 
.text:004012EB     mov  byte_402000, al 
.text:004012F0     mov  dword_402004, eax 
.text:004012F5     nop 
.text:004012F6     nop 
.text:004012F7     movzx eax, byte_402000 
.text:004012FE     nop 
.text:004012FF     nop 
.text:00401300     add  eax, dword_402004 
.text:00401306     nop 
.text:00401307     nop 
.text:00401308     movzx ecx, byte_402000 
.text:0040130F     add  ecx, eax 
.text:00401311     nop 
.text:00401312     nop 
.text:00401313     add  ecx, dword_402004 
.text:00401319     nop 
.text:0040131A     nop 
.text:0040131B     movzx eax, byte_402000 
.text:00401322     add  eax, ecx 
.text:00401324     nop 
.text:00401325     nop 
.text:00401326     add  eax, dword_402004 
.text:0040132C     nop 
.text:0040132D     nop 
.text:0040132E     pop  ebp 
.text:0040132F     retn 
.text:0040132F sub_4012E0  endp 

senza PON entrambi ottimizzatori può produce codice migliore - ma clang è ancora meglio

VS2010 (più codice a causa del riferimento byte non risolto)

.text:00401003     mov  eax, [ebp+argv] 
.text:00401006     movzx ecx, al 
.text:00401009     lea  edx, [eax+eax*2] 
.text:0040100C     mov  byte_403374, al 
.text:00401011     mov  dword_403378, eax 
.text:00401016     lea  eax, [edx+ecx*2] 
.text:00401019     mov  ecx, off_40301C 
.text:0040101F     movzx edx, byte ptr [ecx] 
.text:00401022     add  eax, edx 

clang 3.1:

.text:004012E8     mov  eax, [ebp+arg_4] 
.text:004012EB     mov  byte_402000, al 
.text:004012F0     mov  dword_402004, eax 
.text:004012F5     movzx ecx, al 
.text:004012F8     add  ecx, eax 
.text:004012FA     lea  eax, [ecx+ecx*2] 
+0

Come è finito l'indirizzo di low_ptr in PTR? forse potresti mostrarci lo smontaggio completo? Non solo linee selezionate? – RedX

+0

cosa intendi con finire in PTR? la variabile "? r16 @@ 3Tword_reg_t @@ A" è il globale "word_reg_t r16" - niente più da vedere nello smontaggio - questo è l'unico codice tra i nops? – llm

+0

Oh sry, pensavo di aver visto un ';' Là. Ok ha più senso ora. – RedX

risposta

5

Ecco quello che credo stia succedendo. Il riferimento viene trattato come un puntatore globale non costante. È possibile vedere questo se si rimuove il const dalla dichiarazione low_ptr.

Si può anche vedere che se si sposta il riferimento da locale alla funzione il compilatore è in grado di ottimizzare l'accesso attraverso di esso senza problemi.

Immagino che dal momento che i riferimenti globali sono piuttosto rari (una "statistica" ammetto che ho appena inventato) che ci sono stati pochi sforzi per ottimizzarli.

+0

funziona per entrambi se int è il tipo base :) - se si utilizza byte_t viene risolto solo il const ptr – llm

Problemi correlati