c++ - 为什么显式位移运算会产生更大的 .s 文件?

标签 c++ c gcc micro-optimization machine-code

我不是受过训练的计算机科学家,所以我不知道有关编译等的全部或大部分细节,但我一直认为我的 C 程序被编译成机器代码,我可以使用 -S 标志查看使用海湾合作委员会。

我还认为我的代码越接近机器代码,计算机执行它的速度就越快。所以我决定对此进行测试。

我编写了两个测试文件来计算一个简单的算术问题。

// test1.c
int main(int argc, char* argv[]){
    int x = 4243;
    int y = 3235;
    int z = 613*x + 725*y;
    return 0;
}

// test2.c
int main(int argc, char* argv[]){
    int x = 4243;
    int y = 3235;
    int z = ( ( ( ( ( ( ( x << 3 ) + x ) << 1 ) + x ) << 3 ) + x ) << 2 ) + x + 
      ( ( ( ( ( ( ( ( ( y << 2 ) + y ) << 1 ) + y ) << 2 ) + y ) << 2 ) + y ) << 2 ) + y;
    return 0;
}

我知道我使这个示例变得比必要的复杂得多,但是当我尝试使用一个更简单的示例时,差异并不那么明显。

现在,如果我使用 gcc -S 标志进行编译,则 test1.s 的机器代码为 31 行,test2.s 的机器代码为 47 行

可能的解释是什么?机器代码行数越少意味着执行速度越快的假设是否有缺陷?在创建二进制文件之前,.s 文件是否会用于任何用途?我的玩具测试是假的吗?

感谢您的见解

最佳答案

曾经有一段时间,CPU 非常简单且不复杂,像您在上面尝试做的那样的位移技巧实际上可以比 CPU 的内置乘法指令产生更好的性能。 (以程序长度为代价:一系列移位指令可能会也可能不会比单个乘法指令更快,但它肯定会更长。)我相信直到 80286 为止都是如此。

甚至曾经有一段时间(还记得 Z80,有人吗?)CPU 非常简单,甚至没有内置的乘法指令,因此我们必须调用例程来进行数字相乘,而这些例程将当然,其中包含的循环会迭代与被乘数的位数一样多的次数,因此这些位移位技巧会产生更好的性能。 (同样,这将以牺牲程序长度为代价:调用乘法例程比执行两个或更多移位操作需要更少的字节。)

但如今,这种说法不再成立了。您的(大概是现代的)CPU 当然有一个内置的乘法指令,该指令名义上在非常少的时钟周期内执行( small, as in, 3 ),因此使用它肯定比将乘法分解为运行得更快(并且更小)多个移位操作,其中每一个通常在一个时钟周期内执行。

我说“名义上”是因为通过预取、流水线、缓存等,即使您可以提前知道任何给定指令需要多少个时钟周期的概念也不再成立。

所以,长话短说:“学会停止担忧并热爱炸弹”。

关于c++ - 为什么显式位移运算会产生更大的 .s 文件?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29444662/

相关文章:

c++ - 我应该同时调用 WSASend() 吗?

c++ - 我可以将可搜索字符设备 `/dev/mem_8` 映射到内存并使用 x86_64 指令访问它吗?

c - 文件不能在 C 中正确打印?

c++ - 函数没有实现宏?

c++ - GCC 没有从 .h 类自动解析 .cpp 包括

c++ - 在不丢失对齐的情况下优化打包递归模板化结构

c++ - 我需要一个支持高效随机访问和 O(k) 插入和移除的容器

c++ - for 循环上的 EXC_BAD_ACCESS(数组函数指针)

c - “Control may reach end of non-void function”错误消息

c - 有什么方法可以在 msp430 中进行多精度运算(使用大于 64 位的整数)?