按照古老的汇编知识,编译器应该是把 #define 做直接的替换,然后汇编指令里使用立即数,避免了一次mov操作,进而得到更高的性能。而定义变量的方式,则一方面会占用内存,计算时还需要将数据从内存mov到寄存器,所以会慢一些。
可惜我使用了gcc在x86_64、arm、avr上的三个版本以及各种优化选项。得到的结果都没有找到将 #define作为汇编立即数的玩法。而是都是定义一个区域后,当作全局变量/静态变量的方式,再mov到寄存器使用的。
开始还怀疑只是浮点数会有这个问题,后来换了整数发现还是这样。gcc还是让我很失望的。
立即数是指做计算时的一个操作数是直接写在指令里的,而非在寄存器里,这样会节省内存和寄存器资源,避免了缓慢的内存倒腾寄存器过程。在高性能计算过程会有很大的性能提升。只是可惜我在gcc里没能复现出这个本该出现的优化。
如下是我写的测试用的C程序 definef.c:
#include <stdio.h>
#define PI_D 3.1416
#define TEN 10
float calc1(float factor) {
return (TEN * factor);
}
float calc2(float factor) {
//float PI_V=3.1416;
int ten=10;
return (ten * factor);
}
int main() {
//printf("%f, %f ", calc1(), calc2());
calc1(2030);
calc2(2030);
return 0;
}
编译到汇编的命令:
gcc -S definef.c
随后可以打开文件 definef.s 来查看生成的汇编代码:
.file "definef.c"
.text
.globl calc1
.type calc1, @function
calc1:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
movss %xmm0, -4(%rbp)
movss -4(%rbp), %xmm1
movss .LC0(%rip), %xmm0
mulss %xmm1, %xmm0
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size calc1, .-calc1
.globl calc2
.type calc2, @function
calc2:
.LFB1:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
movss %xmm0, -20(%rbp)
movl $10, -4(%rbp)
pxor %xmm0, %xmm0
cvtsi2ss -4(%rbp), %xmm0
mulss -20(%rbp), %xmm0
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE1:
.size calc2, .-calc2
.globl main
.type main, @function
main:
.LFB2:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
movss .LC1(%rip), %xmm0
call calc1
movss .LC1(%rip), %xmm0
call calc2
movl $0, %eax
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE2:
.size main, .-main
.section .rodata
.align 4
.LC0:
.long 1092616192
.align 4
.LC1:
.long 1157480448
.ident "GCC: (Ubuntu 5.4.0-6ubuntu1~16.04.12) 5.4.0 20160609"
.section .note.GNU-stack,"",@progbits
从如上calc1标签可见。#define常量放在了标签 .LC0 里,随后被载入到了寄存器%xmm0。
真可惜,不过也越发激励了我的一个业余项目。给Python里内嵌汇编JIT的功能。使得可以直接写一段汇编代码并在运行时编译成可执行代码供优化性能。只要利用Python的格式化字符串来传入那些必要的变量到汇编立即数,就能获得比C/C++更高的性能了。
优势就是前者可以兼容double跟float,甚至字符串,而且是编译期转换。
后者用float损失了精度。而且用到不同类型比如字符串时需要运行期转换。
浮点如果直接定义为const有类型常量通常需要定义两份,一份float一份double。而使用define这样的无类型常量定义就只需要定义一份。
之所以这样是因为浮点跟整数不同,整数类型之间转换是直接截断,没有开销。浮点类型之间转换是有开销的,不同浮点的存储格式不同。
本站所有内容均为互联网搜索引擎提供的公开搜索信息,本站不存储任何数据与内容,任何内容与数据均与本站无关,如有需要请联系相关搜索引擎包括但不限于百度,google,bing,sogou 等
© 2025 tinynews.org All Rights Reserved. 百科问答小站 版权所有