ในทางปฏิบัติ ไม่มีค่าใช้จ่ายเพิ่มเติมจะเกิดขึ้น ใน C ++, ฟังก์ชั่นขนาดเล็กมักจะถูกคอมไพเลอร์เป็นตัวเพิ่มประสิทธิภาพดังนั้นแอสเซมบลีที่เกิดขึ้นจะมีการดำเนินการทั้งหมดที่ callsite - ฟังก์ชั่นจะไม่โทรหากันเนื่องจากฟังก์ชั่นจะไม่มีอยู่ในรหัสสุดท้ายเท่านั้น การดำเนินการทางคณิตศาสตร์
ขึ้นอยู่กับคอมไพเลอร์คุณอาจเห็นหนึ่งในฟังก์ชั่นเหล่านี้เรียกอีกฟังก์ชั่นที่ไม่มีการเพิ่มประสิทธิภาพต่ำ (เช่นเดียวกับ debug builds) ที่ระดับการปรับให้เหมาะสมที่สูงขึ้น (การสร้างรุ่น) พวกเขาจะได้รับการปรับให้เหมาะสมกับคณิตศาสตร์
หากคุณยังคงอยากรู้เกี่ยวกับมัน (พูดว่าคุณกำลังสร้างห้องสมุด) การเพิ่มinline
คำหลักลงในoperator*()
(และฟังก์ชั่น wrapper ที่คล้ายกัน) อาจทำให้คอมไพเลอร์ของคุณทำงานแบบอินไลน์หรือใช้แฟล็ก / ไวยากรณ์เฉพาะคอมไพเลอร์เช่น: -finline-small-functions
, -finline-functions
, -findirect-inlining
, __attribute__((always_inline))
(เครดิตให้ข้อมูลที่เป็นประโยชน์ @Stephane Hockenhull ในการแสดงความคิดเห็น) โดยส่วนตัวแล้วฉันมักจะทำตามสิ่งที่เฟรมเวิร์ก / libs ที่ฉันใช้อยู่ - ถ้าฉันใช้ไลบรารีคณิตศาสตร์ของ GLKit ฉันจะใช้GLK_INLINE
แมโครที่มันให้มาด้วย
การตรวจสอบซ้ำโดยใช้ Clang (แอปเปิ้ล LLVM เวอร์ชัน 7.0.2 / clang-700.1.81 ของ Xcode 7.2)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
รูปลักษณ์ที่เหมือนกันทั้งหมด