[c] 얼마나 많은 GCC 최적화 수준이 있습니까?

얼마나 많은 GCC 최적화 수준이 있습니까?

gcc -O1, gcc -O2, gcc -O3 및 gcc -O4를 시도했습니다.

정말 많은 수를 사용하면 작동하지 않습니다.

그러나 나는 시도했다

gcc -O100

그리고 그것은 컴파일되었습니다.

얼마나 많은 최적화 수준이 있습니까?



답변

현명하게 말하자면, gcc에 줄 수있는 유효한 -O 옵션이 8 가지 있지만 같은 의미를 갖는 옵션도 있습니다.

이 답변의 원래 버전에는 7 가지 옵션이 있다고 명시되어 있습니다. GCC는 이후 -Og총 8 개를 추가 했습니다.

로부터 매뉴얼 페이지

  • -O (과 동일 -O1)
  • -O0 (최적화 안 함, 최적화 수준이 지정되지 않은 경우 기본값)
  • -O1 (최소한 최적화)
  • -O2 (더 최적화)
  • -O3 (더욱 최적화)
  • -Ofast (표준 준수를 위반하는 지점까지 매우 적극적으로 최적화)
  • -Og (디버깅 경험을 최적화하십시오. -Og는 디버깅을 방해하지 않는 최적화를 가능하게합니다. 표준 편집-컴파일-디버그주기를위한 최적화 수준이어야하며, 빠른 컴파일과 좋은 디버깅 경험을 유지하면서 합리적인 수준의 최적화를 제공해야합니다. )
  • -Os(크기 최적화. 일반적으로 코드 크기를 늘리지 않는 -Os모든 -O2최적화를 활성화합니다 . 또한 코드 크기를 줄이기 위해 설계된 추가 최적화를 수행
    -Os합니다. 다음 최적화 플래그를 비활성화합니다. -falign-functions -falign-jumps -falign-loops -falign-labels -freorder-blocks -freorder-blocks-and-partition -fprefetch-loop-arrays -ftree-vect-loop-version)

@pauldoo가 언급했듯이 OS X에는 플랫폼 별 최적화가있을 수도 있습니다. -Oz


답변

GCC 5.1의 소스 코드를 해석-O100 하여 man 페이지에 명확하지 않기 때문에 어떤 일이 발생하는지 살펴 보겠습니다 .

우리는 다음과 같이 결론을 내릴 것입니다.

  • 위의 아무것도 -O3까지이 INT_MAX과 동일 -O3하지만 쉽게, 향후 변경 될 수 있으므로에 의존하지 않습니다.
  • GCC 5.1은보다 큰 정수를 입력하면 정의되지 않은 동작을 실행 INT_MAX합니다.
  • 인수는 숫자 만 가질 수 있거나 정상적으로 실패합니다. 특히 다음과 같은 음의 정수는 제외됩니다.-O-1

하위 프로그램에 집중

먼저 GCC는 단지 프런트 엔드 있다는 사실을 cpp, as, cc1, collect2. 빠른는 ./XXX --help만 말한다 collect2cc1포획-O 그래서 그들에 중점을하자.

과:

gcc -v -O100 main.c |& grep 100

제공합니다 :

COLLECT_GCC_OPTIONS='-O100' '-v' '-mtune=generic' '-march=x86-64'
/usr/local/libexec/gcc/x86_64-unknown-linux-gnu/5.1.0/cc1 [[noise]] hello_world.c -O100 -o /tmp/ccetECB5.

그래서 -O모두에 전달 된 cc1collect2 .

O common.opt

common.opt내부 문서에 설명되어 있으며 opth-gen.awkoptc-gen.awk에 의해 C로 번역 된 GCC 특정 CLI 옵션 설명 형식 입니다.

다음과 같은 흥미로운 라인이 포함되어 있습니다.

O
Common JoinedOrMissing Optimization
-O<number>  Set optimization level to <number>

Os
Common Optimization
Optimize for space rather than speed

Ofast
Common Optimization
Optimize for speed disregarding exact standards compliance

Og
Common Optimization
Optimize for debugging experience rather than speed or size

모든 O옵션 을 지정합니다 . 어떻게 참고 -O<n>다른과는 별도의 가족이다 Os, Ofast하고 Og.

빌드 할 때 다음 options.h을 포함 하는 파일 이 생성 됩니다.

OPT_O = 139,                               /* -O */
OPT_Ofast = 140,                           /* -Ofast */
OPT_Og = 141,                              /* -Og */
OPT_Os = 142,                              /* -Os */

보너스로, 우리가 \bO\n내부를 탐색하는 동안 우리는 common.opt다음과 같은 라인을 발견했습니다.

-optimize
Common Alias(O)

어떤 것을 우리에게 가르쳐 --optimize(이중 대시가 대시로 시작하기 때문에 -optimize.opt파일)에 대한 문서화되지 않은 별칭 -O으로 사용할 수 있습니다 --optimize=3!

OPT_O가 사용되는 곳

이제 우리는 grep :

git grep -E '\bOPT_O\b'

두 개의 파일을 가리 킵니다.

먼저 추적 해보자 opts.c

opts.c : default_options_optimization

모든 opts.c사용은 내부에서 발생합니다 : default_options_optimization.

우리는이 함수를 호출하는 사람을 확인하기 위해 역 추적을했고, 유일한 코드 경로는 다음과 같습니다.

  • main.c:main
  • toplev.c:toplev::main
  • opts-global.c:decode_opts
  • opts.c:default_options_optimization

main.c의 진입 점입니다 cc1. 좋은!

이 기능의 첫 번째 부분 :

  • 합니까 integral_argument호출 atoi에 해당하는 문자열을 OPT_O입력 인수를 구문 분석
  • 값 안에 저장 이다 .opts->x_optimizeoptsstruct gcc_opts

구조체 gcc_opts

헛되이 움켜 쥐고 나면 다음 위치 struct에서도 생성됩니다 options.h.

struct gcc_options {
    int x_optimize;
    [...]
}

x_optimize라인 에서 오는 곳 :

Variable
int optimize

에 존재 common.opt하며 그 options.c:

struct gcc_options global_options;

그래서 우리는 이것이 전체 구성 전역 상태를 포함하고 있다고 추측합니다. int x_optimize 하고 최적화 값 .

255는 내부 최대 값입니다.

에서 opts.c:integral_argument, atoi따라서, 입력 인수에인가 INT_MAX상한이다. 그리고 더 큰 것을 넣으면 GCC가 C 정의되지 않은 동작을 실행하는 것처럼 보입니다. 아야?

integral_argument또한 atoi숫자가 아닌 문자가 있으면 인수를 얇게 감싸고 거부합니다. 따라서 음수 값은 정상적으로 실패합니다.

로 돌아 가면 opts.c:default_options_optimization다음 줄이 표시됩니다.

if ((unsigned int) opts->x_optimize > 255)
  opts->x_optimize = 255;

최적화 수준이 255. 읽는 동안 opth-gen.awk나는 우연히 발견했다 :

# All of the optimization switches gathered together so they can be saved and restored.
# This will allow attribute((cold)) to turn on space optimization.

그리고 생성 options.h:

struct GTY(()) cl_optimization
{
  unsigned char x_optimize;

잘림 이유를 설명합니다. 옵션도로 전달되어야 cl_optimization합니다.char .이 경우 공간을 절약하기 위해 를 사용합니다. 따라서 255는 실제로 내부 최대 값입니다.

opts.c : maybe_default_options

위로 opts.c:default_options_optimization, 우리는 건너 maybe_default_options있는 흥미로운 소리. 우리는 그것을 입력 maybe_default_option하고 큰 스위치에 도달합니다.

switch (default_opt->levels)
  {

  [...]

  case OPT_LEVELS_1_PLUS:
    enabled = (level >= 1);
    break;

  [...]

  case OPT_LEVELS_3_PLUS:
    enabled = (level >= 3);
    break;

가능한 가장 큰 >= 4수표 가 없음 을 나타냅니다 3.

그런 다음 OPT_LEVELS_3_PLUSin 의 정의를 검색합니다 common-target.h.

enum opt_levels
{
  OPT_LEVELS_NONE, /* No levels (mark end of array).  */
  OPT_LEVELS_ALL, /* All levels (used by targets to disable options
                     enabled in target-independent code).  */
  OPT_LEVELS_0_ONLY, /* -O0 only.  */
  OPT_LEVELS_1_PLUS, /* -O1 and above, including -Os and -Og.  */
  OPT_LEVELS_1_PLUS_SPEED_ONLY, /* -O1 and above, but not -Os or -Og.  */
  OPT_LEVELS_1_PLUS_NOT_DEBUG, /* -O1 and above, but not -Og.  */
  OPT_LEVELS_2_PLUS, /* -O2 and above, including -Os.  */
  OPT_LEVELS_2_PLUS_SPEED_ONLY, /* -O2 and above, but not -Os or -Og.  */
  OPT_LEVELS_3_PLUS, /* -O3 and above.  */
  OPT_LEVELS_3_PLUS_AND_SIZE, /* -O3 and above and -Os.  */
  OPT_LEVELS_SIZE, /* -Os only.  */
  OPT_LEVELS_FAST /* -Ofast only.  */
};

하아! 이것은 3 개의 레벨 만 있다는 강력한 지표입니다.

opts.c : default_options_table

opt_levels너무 흥미로워 서 우리는 grep OPT_LEVELS_3_PLUS을하고 다음 을 보게됩니다 opts.c:default_options_table.

static const struct default_options default_options_table[] = {
    /* -O1 optimizations.  */
    { OPT_LEVELS_1_PLUS, OPT_fdefer_pop, NULL, 1 },
    [...]

    /* -O3 optimizations.  */
    { OPT_LEVELS_3_PLUS, OPT_ftree_loop_distribute_patterns, NULL, 1 },
    [...]
}

그래서 이것은 -On문서에 언급 된 특정 최적화 매핑이 인코딩되는 곳입니다. 좋은!

x_optimize를 더 이상 사용하지 않도록하십시오.

의 주요 용도 는 man 페이지에 설명 된 x_optimize것과 같은 다른 특정 최적화 옵션을 설정 하는 것이 었습니다 -fdefer_pop. 더 있나요?

우리 grep는 몇 가지를 더 찾습니다. 그 수가 적고 수동 검사를 통해 모든 사용이 최대 a 만 수행하는 것을 알 수 x_optimize >= 3있으므로 결론은 유효합니다.

lto-wrapper.c

이제 우리의 두 번째 발생에 대한 이동 OPT_O에 있었다 lto-wrapper.c.

LTO는 Link Time Optimization을 의미하며 이름에서 알 수 있듯이 -O옵션 이 필요하며 collec2기본적으로 링커에 연결됩니다 .

실제로 첫 번째 줄 lto-wrapper.c은 다음 과 같이 말합니다.

/* Wrapper to call lto.  Used by collect2 and the linker plugin.

이 파일에서 OPT_O발생은 값을 ​​정규화하여 O전달하는 것처럼 보이므로 괜찮습니다.


답변

7 가지 수준 :

  • -O0 (기본값) : 최적화 없음.

  • -O또는 -O1(동일) : 최적화하되 너무 많은 시간을 소비하지 마십시오.

  • -O2:보다 적극적으로 최적화

  • -O3: 가장 적극적으로 최적화

  • -Ofast: -O3 -ffast-math. -ffast-math비표준 호환 부동 소수점 최적화를 트리거합니다. 이를 통해 컴파일러는 부동 소수점 숫자가 무한히 정확하고 그에 대한 대수가 실수 대수의 표준 규칙을 따르는 것처럼 가장 할 수 있습니다. 또한 적어도 x86 및 x86-64를 포함한 일부 프로세서에서 비정규를 0으로 플러시하고 비정규를 0으로 처리하도록 하드웨어에 지시하도록 컴파일러에 지시합니다. 비정규 화는 많은 FPU에서 느린 경로를 트리거하므로이를 0 (느린 경로를 트리거하지 않음)으로 처리하면 성능이 크게 향상 될 수 있습니다.

  • -Os: 코드 크기를 최적화합니다. 이것은 더 나은 I- 캐시 동작으로 인해 어떤 경우에는 실제로 속도를 향상시킬 수 있습니다.

  • -Og: 최적화하지만 디버깅을 방해하지 않습니다. 이것은 디버그 빌드에 대해 당황스럽지 않은 성능을 가능하게하며 디버그 빌드를 대체하기 -O0위한 것 입니다.

이들 중 어느 것도 활성화하지 않고 별도로 활성화해야하는 다른 옵션도 있습니다. 최적화 옵션을 사용할 수도 있지만이 최적화로 활성화 된 특정 플래그를 비활성화합니다.

자세한 내용은 GCC 웹 사이트를 참조하십시오.


답변

4 개 (0-3) : GCC 4.4.2 설명서를 참조하십시오 . 더 높은 값은 -O3에 불과하지만 어느 시점에서 가변 크기 제한을 초과하게됩니다.


답변