GCC 6.1.1 (unstable?) versus clang 3.8

Um leitor me fez a gentileza de compilar o código do artigo anterior (este aqui) usando o GCC 6.1.1 e o clang 3.8. O argumento, é claro, é um velho conhecido de todo mundo: “Ahhh, mas você está usando versões velhas!”. Isso porque usei o GCC 4.9.2 e o clang 3.5. Bem, comparem o código gerado por esses novíssimos e, supostamente, melhores compiladores, na mesma ordem do artigo anterior, primeiro o gerado pelo GCC 6.1.1 (que ainda está em fase de regressões e acertos) e o clang 3.8 (supostamente stable):

;------ GCC 6.1.1 -----------
  align 4
strlcpy:
  movzx ecx,byte [rsi]
  mov   rax,rdi
  test  cl,cl
  jz    .strlcpy_exit
  test  rdx,rdx
  jz    .strlcpy_exit

  add   rdx,rsi
  mov   r8,rdi
  jmp   .L1

  align 4
.loop:
  cmp   rdx,rsi
  je    .strlcpy_exit2
.L1:
  add   r8,1
  add   rsi,1
  mov   byte [r8-1],cl
  movzx ecx,byte [rsi]
  test  cl,cl
  jne   .loop

.strlcpy_exit2:
  mov   byte [r8],0
  ; --- O GCC 4.9 coloca o .strlcpy_exit aqui!
  ret

.strlcpy_exit:  
  mov   r8,rax
  jmp   .strlcpy_exit2

O GCC 6.1.1 conseguiu piorar, no finalzinho, uma rotina que parecia quase ideal. Note que a partir do label .strlcpy_exit o código é inútil, já que RDI já está em RAX!

O clang 3.8 faz um trabalho ainda pior que o seu irmão mais velho. Vejam:

;------ clang 3.8 -----------
  align 16
strlcpy:
  test  rdx,rdx
  mov   rax,rdi       ; Copia RDI para RAX
  jz    .strlcpy_exit ; Se size == 0, sai.

  mov   r8b,[rsi]     ; R8B = *src;
  test  r8b,r8b       
  mov   rax,rdi       ; Copia RDI para RAX (2ª vez).
  jz    .strlcpy_exit ; Se *src == '\0', sai.

  mov   ecx,1
  sub   rcx,rdx       ; RCX = 1 - RDX
  inc   rsi           ; src++;
  mov   rax,rdi       ; Copia RDI para RAX (3ª vez).
  
  align 16  
.loop:
  mov   [rax],r8b     ; *dest = *src;
  inc   rax           ; src++ (src temporário em RAX);
  test  rcx,rcx       
  jz    .strlcpy_exit ; RCX == 0? sai.

  mov   r8b,[rsi]     ; R8B = *src;
  inc   rcx           
  inc   rsi           ; src++;
  test  r8b,r8b
  jne   .loop         ; Se R8B != 0, loop.

.strlcpy_exit:
  mov   [rax],0       ; *dest = '\0';
  mov   rax,rdi       ; Copia RDI para RAX (4ª vez!).
  ret

O código não mudou muito desde a versão 3.5, exceto pelo fato de que, agora, a nova versão faz mais duas cópias desnecessárias de RDI para RAX!!!

Sinto muito, mas essas versões mais novas não me impressionaram nem um pouco… Bem… talvez o GCC tenha impressionado um pouquinho: Afinal, para uma versão não finalizada ele fez até um bom trabalho (como o GCC 4.9 faria)…

Anúncios