/ / GCC vs CLANG wskaźnik do optymalizacji char * - c, gcc, asembler, clang

GCC vs CLANG wskaźnik do char * optymalizacji - c, gcc, assembly, clang

Mam ten kod: mainP.c:

int main(int c, char **v){
char *s = v[0];
while (*s++ != 0) {
if ((*s == "a") && (*s != "b")) {
return 1;
}
}
return 0;
}

które kompiluję z clang i gcc generującymi kod asemblera w celu porównania optymalizacji:

clang-3.9 -S -masm=intel -O3 mainP.c
gcc -S -masm=intel -O3 mainP.c

Wersja kompilatora to:

clang version 3.9.1-9 (tags/RELEASE_391/rc2)
Target: x86_64-pc-linux-gnu
gcc (Debian 6.3.0-18) 6.3.0 20170516

2 wynikowe kody zestawu to:

kod zestawu gcc:

main:
.LFB0:
.cfi_startproc
mov     rax, QWORD PTR [rsi]
jmp     .L2
.p2align 4,,10
.p2align 3
.L4:
cmp     BYTE PTR [rax], 97
je      .L5
.L2:
add     rax, 1
cmp     BYTE PTR -1[rax], 0
jne     .L4
xor     eax, eax
ret
.L5:
mov     eax, 1
ret

kod zestawu clang:

main:                                   # @main
.cfi_startproc
# BB#0:
mov     rcx, qword ptr [rsi]
mov     dl, byte ptr [rcx]
inc     rcx
.p2align        4, 0x90
.LBB0_1:                                # =>This Inner Loop Header: Depth=1
xor     eax, eax
test    dl, dl
je      .LBB0_3
# BB#2:                                 #   in Loop: Header=BB0_1 Depth=1
movzx   edx, byte ptr [rcx]
inc     rcx
mov     eax, 1
cmp     dl, 97
jne     .LBB0_1
.LBB0_3:
ret

Zauważam to: w kodzie zestawu gcc do * s można uzyskać dwa razy w pętli, podczas gdy do * s można uzyskać tylko raz kod zestawu clang.

czy jest wyjaśnienie różnicy?

Następnie po lekkiej zmianie kodu C (dodaniu lokalnej zmiennej char), otrzymuję mniej więcej ten sam kod asemblera z GCC:

int main(int c, char **v){
char *s = v[0];
char ch;
ch = *s;
while (ch != 0) {
if ((ch == "a") && (ch != "b")) {
return 1;
}
ch = *s++;
}
return 0;
}

Wynikowy kod zestawu z GCC:

main:
.LFB0:
.cfi_startproc
mov     rax, QWORD PTR [rsi]
movzx   edx, BYTE PTR [rax]
test    dl, dl
je      .L6
add     rax, 1
cmp     dl, 97
jne     .L5
jmp     .L8
.p2align 4,,10
.p2align 3
.L4:
cmp     dl, 97
je      .L8
.L5:
add     rax, 1
movzx   edx, BYTE PTR -1[rax]
test    dl, dl
jne     .L4
.L6:
xor     eax, eax
ret
.L8:
mov     eax, 1
ret

Odpowiedzi:

0 dla odpowiedzi № 1

Wyjaśnienie różnicy: optymalizacje kompilatora są ciężko zrobić, a różne kompilatory zoptymalizują Twój kod na różne sposoby.

Ponieważ wyrażenie jest stosunkowo proste, możemy to założyć *s ma taką samą wartość w obu miejscach i naprawdę potrzebne jest tylko jedno obciążenie.

Ale odkrycie, że optymalizacja jest trudne, ponieważ kompilator musi absolutnie „wiedzieć”, że „cokolwiek wskazuje na”, nie można zmienić między pierwszym odniesieniem a drugim.

W twoim przykładzie clang lepiej jest rozgryźć to niż gcc.