GCC:Optimization
gcc는 기본적으로 아무런 옵션을 지정하지 않으면, 만들어지는 코드를 최적화(optimization)시키지 않는다. 최적화를 위해, 여러가지 옵션을 제공하는데, 이들 옵션을 일일히 선택하기 보다는 이들 옵션을 세트로 묶어 제공하는 -O
, -O1
, -O2
, -O3
등을 일반적으로 사용한다.
(gcc version 3.2.2, 3.4.6 기준.)
(참고로 -O0
는 전혀 최적화하지 말라는, default 옵션이다.)
Optimization set
-
-O
,-O1
- 만들어지는 오브젝트, 또는 실행 파일을 가능한 작게 하면서, 컴파일 시간이 오래걸리지 않는 범위에서 최적화를 수행한다.
-
-O2
- 만들어지는 코드가 가능한 빠르게 수행되도록 하지만, 코드의 크기가 너무 커지지 않도록 하는 범위에서 최적화를 수행한다.
-
-Os
- -O2에서 제공하는 모든 최적화 기능을 다 쓰지만, 코드의 크기를 증가시키는 최적화 기능은 빼고 나서 최적화를 수행한다.
-
-O3
- 코드의 크기는 전혀 신경 쓰지 않고, 오직 빠른 코드를 만들어 내기 위해 최적화를 수행한다. 그러나, 꼭 생각해 두어야 할 점은,
-O3
로 만들어낸 코드가 반드시-O2
를 써서 만들어낸 코드보다 빠르다는 보장은 없다. 그 이유는, 보통 CPU가 기계어를 수행할 때, 일정한 분량만큼 먼저 CPU 내부의 cache(캐시)에 불러와서 수행하는데,-O3
를 써서 만든 코드는 대개 크기가 커서, 이 cache에 들어갈 수 있는 명령의 양이 상대적으로 적어지기 때문에, 오히려 느려질 가능성도 있다.
-On
(n=1, 2, 3) 꼴의 옵션과 더불어 다른 옵션을 섞어 쓸 수도 있다. 예를 들어, -O2
를 쓸 경우, inline-function 최적화는 적용되지 않는다. 따라서 아래와 같이 -O2
에 해당하는 모든 최적화 기법들과 -inline-functions
을 함께 쓸 수 있다.
물론, 특정 옵션 기능을 빼는 것도 가능하다. 아래는 -O3
가 제공하는 모든 최적화 기법을 적용하지만 inline-functions 최적화만 빼고 컴파일하는 것을 보여준다.
즉, 추가 옵션을 적용시키려면(on) -f<OPTION_NAME>
을 쓰고, 끄려면(off), -fno-<OPTION_NAME>
꼴을 사용하면 된다.
GCC Optimization Option List
최적화옵션리스트는 아래와 같다. 최적화셋트옵션에 대한 사용여부도 함께 정리했다.
Optimization | -O1 | -O2 | -Os | -O3 | Remarks |
defer-pop | O | O | O | O | |
thread-jumps | O | O | O | O | |
branch-probabilities | O | O | O | O | |
cprop-registers | O | O | O | O | |
guess-branch-probability | O | O | O | O | |
omit-frame-pointer | O | O | O | O | |
merge-constants | O | O | O | O | |
loop-optimize | O | O | O | O | |
if-conversion | O | O | O | O | |
if-conversion2 | O | O | O | O | |
align-loops | X | O | X | O | |
align-jumps | X | O | X | O | |
align-labels | X | O | X | O | |
align-functions | X | O | X | O | |
crossjumping | X | O | O | O | |
prefetch-loop-array | ? | ? | X | ? | |
optimize-sibling-calls | X | O | O | O | |
cse-follow-jumps | X | O | O | O | |
cse-skip-blocks | X | O | O | O | |
gcse | X | O | O | O | |
gcse-lm | X | O | O | O | |
gcse-sm | X | O | O | O | |
gcse-las | X | O | O | O | |
expensive-optimizations | X | O | O | O | |
strength-reduce | X | O | O | O | |
rerun-cse-after-loop | X | O | O | O | |
rerun-loop-opt | X | O | O | O | |
caller-saves | X | O | O | O | |
force-mem | X | O | O | O | |
peephole2 | X | O | O | O | |
regmove | X | O | O | O | |
strict-aliasing | X | O | O | O | 컴파일러는 서로 다른 타입의 변수는 동일한 메모리를 가리키지 않는다. (상세 정보) |
delete-null-pointer-checks | X | O | O | O | |
reorder-blocks | X | O | O | O | |
reorder-functions | X | O | O | O | |
unit-at-a-time | X | O | ? | O | |
schedule-insns | X | O | O | O | |
schedule-insns2 | X | X | X | O | |
schedule-interblock | X | O | ? | O | |
sched-spec | X | O | ? | O | |
inline-functions | X | X | X | O | |
rename-registers | X | X | X | O | |
web | X | X | X | O | |
unswitch-loops | X | X | ? | O |
FORTIFY SOURCE
FORTIFY_SOURCE가 적용되면 일반 메모리/문자열 및 버퍼 관련 함수들은 GCC builtin 함수로 바뀌는데 이들은 연산을 수행할 대상 (Destination, 즉 결과가 저장될 영역)의 크기를 알아야만 Overflow 검사를 할 수 있다. 이러한 메모리 영역의 크기를 알아내기 위해 __builtin_object_size()
내장 함수가 사용된다.
사용방법은 아래와 같다.
-
-O1
이상의 최적화 옵션. -
-D_FORTIFY_SOURCE=N
으로 Define 추가.
See also
Favorite site
References
-
GCC_optimization_-_Gentoo_Wiki.pdf ↩