문제

strong> 이것은 4.4 이전의 GCC 버전의 문제 일뿐입니다. 이것은 GCC 4.5에서 수정되었습니다.

는 컴파일러에 스위치에서 사용 된 변수가 제공된 경우에 제공된 경우가 있으십니까? 특히 그것이 작은 범위이고 점프 테이블이 생성 된 경우.

extern int a;
main()
{
        switch (a & 0x7) {   // 0x7  == 111  values are 0-7
        case 0: f0(); break;
        case 1: f1(); break;
        case 2: f2(); break;
        case 3: f3(); break;
        case 4: f4(); break;
        case 5: f5(); break;
        case 6: f6(); break;
        case 7: f7(); break;
        }
}
.

gcc_unreachable ()을 사용하여 gcc_unreachable ()을 사용하여 열거 형을 사용하여 낮은 비트 (예 참조)로 XOR'ing을 시도했습니다. 생성 된 코드는 변수가 범위 내에 있는지 항상 점검하고 무의미한 지점 조건부를 추가하고 점프 테이블 계산 코드를 멀리 이동합니다.

참고 : 이것은 디코더의 가장 안쪽 루프, 성능 문제가 크게 중요합니다.

.

기본 분기가 결코 취하지 않는다고 GCC에 알릴 방법이 없습니다. 그것이 그 증명할 수있는 경우 기본 분기를 생략하지만 가치는 초기 조건 검사를 기반으로 범위를 벗어나지 않습니다.

그래서 GCC가 변수를 증명할 수 있고 위의 예에서는 기본 분기가 없습니까? (조건부 분기를 추가하지 않고) 물론.)

업데이트

  1. 이것은 GCC 4.2가있는 Snow Leopard에있었습니다 (Xcode에서 기본값.) Linux에서 GCC 4.4 / 4.3 (Nathon 및 Jens Gustedt 가보고)

    리>

  2. 예제의 기능은 가독성이 있거나 인라인 또는 단지 진술을하는 것으로 생각합니다. x86에서 함수 호출을 만드는 것은 비싸다.

    또한 메모에서 언급 한 것처럼 예제는 데이터 (BIG DATA) 루프 내부에 속합니다.

    GCC 4.2 / OS X가있는 생성 된 코드는 다음과 같습니다.

    [...]
    andl    $7, %eax
    cmpl    $7, %eax
    ja  L11
    mov %eax, %eax
    leaq    L20(%rip), %rdx
    movslq  (%rdx,%rax,4),%rax
    addq    %rdx, %rax
    jmp *%rax
    .align 2,0x90
    L20:
    .long   L12-L20
    .long   L13-L20
    .long   L14-L20
    .long   L15-L20
    .long   L16-L20
    .long   L17-L20
    .long   L18-L20
    .long   L19-L20
    L19:
    [...]
    
    .

    문제점은 cmp $7, %eax; ja L11;

  3. 에 있습니다.

  4. OK, 추악한 솔루션을 사용하고 스위치없이 다른 버전을 사용하여 4.4 미만의 GCC 버전을 추가하고 GOTO 및 GCC의 && Label Extensions를 사용합니다.

    static void *jtb[] = { &&c_1, &&c_2, &&c_3, &&c_4, &&c_5, &&c_6, &&c_7, &&c_8 };
    [...]
    goto *jtb[a & 0x7];
    [...]
    while(0) {
    c_1:
    // something
    break;
    c_2:
    // something
    break;
    [...]
    }
    
    .

    레이블 배열은 정적이므로 모든 통화마다 계산되지 않습니다.

도움이 되었습니까?

해결책

나는 -O5와 -FNO 인라인 (내 F0-F7 기능이 사소한)과 비교할 수있는 것을 편성하려고 시도했다.


 8048420:   55                      push   %ebp ;; function preamble
 8048421:   89 e5                   mov    %esp,%ebp ;; Yeah, yeah, it's a function.
 8048423:   83 ec 04                sub    $0x4,%esp ;; do stuff with the stack
 8048426:   8b 45 08                mov    0x8(%ebp),%eax ;; x86 sucks, we get it
 8048429:   83 e0 07                and    $0x7,%eax ;; Do the (a & 0x7)
 804842c:   ff 24 85 a0 85 04 08    jmp    *0x80485a0(,%eax,4) ;; Jump table!
 8048433:   90                      nop
 8048434:   8d 74 26 00             lea    0x0(%esi,%eiz,1),%esi
 8048438:   8d 45 08                lea    0x8(%ebp),%eax
 804843b:   89 04 24                mov    %eax,(%esp)
 804843e:   e8 bd ff ff ff          call   8048400 
 8048443:   8b 45 08                mov    0x8(%ebp),%eax
 8048446:   c9                      leave  
.

최적화 수준을 가지고 노는 것을 시도 했습니까?

다른 팁

스위치 대신 함수 포인터 배열을 사용할 수 있습니까?

#include <stdio.h>

typedef void (*func)(void);

static void f0(void) { printf("%s\n", __FUNCTION__); }
static void f1(void) { printf("%s\n", __FUNCTION__); }
static void f2(void) { printf("%s\n", __FUNCTION__); }
static void f3(void) { printf("%s\n", __FUNCTION__); }
static void f4(void) { printf("%s\n", __FUNCTION__); }
static void f5(void) { printf("%s\n", __FUNCTION__); }
static void f6(void) { printf("%s\n", __FUNCTION__); }
static void f7(void) { printf("%s\n", __FUNCTION__); }

int main(void)
{
    const func f[8] = { f0, f1, f2, f3, f4, f5, f6, f7 };
    int i;

    for (i = 0; i < 8; ++i)
    {
        f[i]();
    }
    return 0;
}
.

switch 변수를 비트 필드로 선언 시도 했습니까?

struct Container {
  uint16_t a:3;
  uint16_t unused:13;
};

struct Container cont;

cont.a = 5;  /* assign some value */
switch( cont.a ) {
...
}
.

이 작품을 희망합니다!

나는 시도하지 않았지만, gcc_unreachable__builtin_unreachable와 동일한 것을 잘 모르겠습니다.Googling in gcc_unreachable는 GCC 자체의 개발을위한 어설 션 도구로 설계된 것으로 보입니다. 아마도 분기 예측 힌트가 포함되어있는 반면, __builtin_unreachable는 기본 블록을 삭제하는 것과 같은 것처럼 보이는 프로그램을 즉시 정의하지 않습니다..

http://gcc.gnu.org/onlinedocs / gcc / 기타 - builtins.html # index-g_t_005f_005fbuiltin_005funreachable-3075

아마도 첫 번째 또는 마지막 경우에 default 레이블을 사용하는 것입니다.

이 질문은 확실히 우리에게 겉보기에 겉보기에 겉보기에 분명한 확실한 컴파일러 최적화의 관점에서 흥미롭게 흥미 롭습니다. 그리고 나는 똑바로 솔루션을 일으키기 위해 상당한 시간을 보냈습니다.

, 나는 를 인정해야한다. 나는이 추가적인 지시가 실제로, 특히 새로운 MAC에서 측정 가능한 성능 차이를 초래할 것이라는 점을 매우 회의적으로 인정해야한다.상당한 양의 데이터가있는 경우 I / O 바인딩이되며 단일 명령은 결코 병목 현상이 아닙니다.작은 양의 데이터가있는 경우, 단일 지시가 병목 현상이되기 전에 반복적으로 계산의 로트 로트 을 수행해야합니다.

실제로 성능 차이가 있음을 보여주기 위해 몇 가지 코드를 게시 하시겠습니까?또는 귀하의 작업 코드와 데이터를 설명하십시오.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top