실제로 는 추가 오버 헤드가 발생하지 않습니다 . C ++에서 작은 함수는 일반적으로 컴파일러에 의해 최적화로 인라인되므로 결과 어셈블리는 호출 사이트에서 모든 작업을 수행합니다. 함수는 최종 코드에만 존재하지 않기 때문에 서로 호출하지 않습니다. 수학적 연산.
컴파일러에 따라 이러한 함수 중 하나가 최적화가 없거나 낮은 수준으로 디버그 호출과 같이 다른 함수를 호출하는 것을 볼 수 있습니다. 그래도 더 높은 최적화 수준 (릴리스 빌드)에서는 수학에 맞게 최적화됩니다.
여전히 라이브러리를 만들고자한다면 inline
키워드를 operator*()
(및 유사한 래퍼 함수에) 추가하면 컴파일러가 인라인을 수행하거나 컴파일러 특정 플래그 / 구문을 사용하도록 힌트를 줄 수 있습니다. -finline-small-functions
, -finline-functions
, -findirect-inlining
, __attribute__((always_inline))
(코멘트에 @Stephane Hockenhull의 유용한 정보로 신용) . 개인적으로 필자는 사용중인 프레임 워크 / 라이브러리를 따르는 경향이 있습니다. GLKit의 수학 라이브러리를 사용 GLK_INLINE
하는 경우 제공 하는 매크로도 사용합니다 .
Clang (Xcode 7.2의 Apple LLVM 버전 7.0.2 / clang-700.1.81)을 사용하여 이중 확인 , 다음 main()
기능 (함수 및 순진한 Vector3<T>
구현 과 함께 ) :
int main(int argc, const char * argv[])
{
Vector3<int> a = { 1, 2, 3 };
Vector3<int> b;
scanf("%d", &b.x);
scanf("%d", &b.y);
scanf("%d", &b.z);
Vector3<int> c = a * b;
printf("%d, %d, %d\n", c.x, c.y, c.z);
return 0;
}
최적화 플래그를 사용하여이 어셈블리로 컴파일합니다 -O0
.
.section __TEXT,__text,regular,pure_instructions
.globl _main
.align 4, 0x90
_main: ## @main
Lfunc_begin0:
.loc 6 30 0 ## main.cpp:30:0
.cfi_startproc
## BB#0:
pushq %rbp
Ltmp0:
.cfi_def_cfa_offset 16
Ltmp1:
.cfi_offset %rbp, -16
movq %rsp, %rbp
Ltmp2:
.cfi_def_cfa_register %rbp
subq $128, %rsp
leaq L_.str1(%rip), %rax
##DEBUG_VALUE: main:argc <- undef
##DEBUG_VALUE: main:argv <- undef
movl $0, -4(%rbp)
movl %edi, -8(%rbp)
movq %rsi, -16(%rbp)
.loc 6 31 15 prologue_end ## main.cpp:31:15
Ltmp3:
movl l__ZZ4mainE1a+8(%rip), %edi
movl %edi, -24(%rbp)
movq l__ZZ4mainE1a(%rip), %rsi
movq %rsi, -32(%rbp)
.loc 6 33 2 ## main.cpp:33:2
leaq L_.str(%rip), %rsi
xorl %edi, %edi
movb %dil, %cl
leaq -48(%rbp), %rdx
movq %rsi, %rdi
movq %rsi, -88(%rbp) ## 8-byte Spill
movq %rdx, %rsi
movq %rax, -96(%rbp) ## 8-byte Spill
movb %cl, %al
movb %cl, -97(%rbp) ## 1-byte Spill
movq %rdx, -112(%rbp) ## 8-byte Spill
callq _scanf
.loc 6 34 17 ## main.cpp:34:17
leaq -44(%rbp), %rsi
.loc 6 34 2 is_stmt 0 ## main.cpp:34:2
movq -88(%rbp), %rdi ## 8-byte Reload
movb -97(%rbp), %cl ## 1-byte Reload
movl %eax, -116(%rbp) ## 4-byte Spill
movb %cl, %al
callq _scanf
.loc 6 35 17 is_stmt 1 ## main.cpp:35:17
leaq -40(%rbp), %rsi
.loc 6 35 2 is_stmt 0 ## main.cpp:35:2
movq -88(%rbp), %rdi ## 8-byte Reload
movb -97(%rbp), %cl ## 1-byte Reload
movl %eax, -120(%rbp) ## 4-byte Spill
movb %cl, %al
callq _scanf
leaq -32(%rbp), %rdi
.loc 6 37 21 is_stmt 1 ## main.cpp:37:21
movq -112(%rbp), %rsi ## 8-byte Reload
movl %eax, -124(%rbp) ## 4-byte Spill
callq __ZmlIiiE7Vector3IDTmldtfp_1xdtfp0_1xEERKS0_IT_ERKS0_IT0_E
movl %edx, -72(%rbp)
movq %rax, -80(%rbp)
movq -80(%rbp), %rax
movq %rax, -64(%rbp)
movl -72(%rbp), %edx
movl %edx, -56(%rbp)
.loc 6 39 27 ## main.cpp:39:27
movl -64(%rbp), %esi
.loc 6 39 32 is_stmt 0 ## main.cpp:39:32
movl -60(%rbp), %edx
.loc 6 39 37 ## main.cpp:39:37
movl -56(%rbp), %ecx
.loc 6 39 2 ## main.cpp:39:2
movq -96(%rbp), %rdi ## 8-byte Reload
movb $0, %al
callq _printf
xorl %ecx, %ecx
.loc 6 41 5 is_stmt 1 ## main.cpp:41:5
movl %eax, -128(%rbp) ## 4-byte Spill
movl %ecx, %eax
addq $128, %rsp
popq %rbp
retq
Ltmp4:
Lfunc_end0:
.cfi_endproc
위 __ZmlIiiE7Vector3IDTmldtfp_1xdtfp0_1xEERKS0_IT_ERKS0_IT0_E
의 operator*()
함수 는 callq
다른 __…Vector3…
함수입니다. 꽤 많은 어셈블리에 해당합니다. 로 컴파일하는 -O1
것은 거의 동일하지만 여전히 __…Vector3…
함수를 호출 합니다.
우리가 그것을 범프 그러나, -O2
상기는 callq
s으로 __…Vector3…
사라지게하는 대체 imull
명령어합니다 ( * a.z
≈ * 3
) addl
지시합니다 ( * a.y
≈ * 2
) 바로 사용 b.x
가치 직 업 (인해 * a.x
≈ * 1
).
.section __TEXT,__text,regular,pure_instructions
.globl _main
.align 4, 0x90
_main: ## @main
Lfunc_begin0:
.loc 6 30 0 ## main.cpp:30:0
.cfi_startproc
## BB#0:
pushq %rbp
Ltmp0:
.cfi_def_cfa_offset 16
Ltmp1:
.cfi_offset %rbp, -16
movq %rsp, %rbp
Ltmp2:
.cfi_def_cfa_register %rbp
.loc 6 33 2 prologue_end ## main.cpp:33:2
Ltmp3:
pushq %rbx
subq $24, %rsp
Ltmp4:
.cfi_offset %rbx, -24
##DEBUG_VALUE: main:argc <- EDI
##DEBUG_VALUE: main:argv <- RSI
leaq L_.str(%rip), %rbx
leaq -24(%rbp), %rsi
Ltmp5:
##DEBUG_VALUE: operator*=<int, int>:rhs <- [RSI+0]
##DEBUG_VALUE: operator*<int, int>:rhs <- [RSI+0]
##DEBUG_VALUE: main:b <- [RSI+0]
xorl %eax, %eax
movq %rbx, %rdi
Ltmp6:
callq _scanf
.loc 6 34 17 ## main.cpp:34:17
leaq -20(%rbp), %rsi
Ltmp7:
xorl %eax, %eax
.loc 6 34 2 is_stmt 0 ## main.cpp:34:2
movq %rbx, %rdi
callq _scanf
.loc 6 35 17 is_stmt 1 ## main.cpp:35:17
leaq -16(%rbp), %rsi
xorl %eax, %eax
.loc 6 35 2 is_stmt 0 ## main.cpp:35:2
movq %rbx, %rdi
callq _scanf
.loc 6 22 18 is_stmt 1 ## main.cpp:22:18
Ltmp8:
movl -24(%rbp), %esi
.loc 6 23 18 ## main.cpp:23:18
movl -20(%rbp), %edx
.loc 6 23 11 is_stmt 0 ## main.cpp:23:11
addl %edx, %edx
.loc 6 24 11 is_stmt 1 ## main.cpp:24:11
imull $3, -16(%rbp), %ecx
Ltmp9:
##DEBUG_VALUE: main:c [bit_piece offset=64 size=32] <- ECX
.loc 6 39 2 ## main.cpp:39:2
leaq L_.str1(%rip), %rdi
xorl %eax, %eax
callq _printf
xorl %eax, %eax
.loc 6 41 5 ## main.cpp:41:5
addq $24, %rsp
popq %rbx
popq %rbp
retq
Ltmp10:
Lfunc_end0:
.cfi_endproc
이 코드를 들어, 어셈블리에서 -O2
, -O3
, -Os
, -Ofast
모든 모양과 동일.