关于 O2

发布时间 2023-10-10 21:42:42作者: VoahTang

本文是关于 O2 带来的问题、以及本人因为 O2 出过的问题的一个整合。

O2 带来的问题

语义误用

inline 内联

如果开 O2,不手动写 inline 也是内联的;如果不开,手动写 inline 也是没什么卵用的。

register 虚假的寄存器建议

现代编译器会直接忽略你的 register 关键字。

你自己认为的寄存器分配一般没有编译器直接跑寄存器分配算法来的聪明

此关键字于 C++11 被弃用,于 C++17 被删除

代码修正

运算符优化

  • << 代替 *

    但是不能类似的用 >> 代替 /,因为编译器不能判断两个有符号的数的正负性。因为 / 2向零取整>> 1 是向下取整。
    举个例子,-7 / 2 = -3,但是 -7 >> 1 = -4

  • * 代替 /

  • + 代替 *

常量传播

如果一个表达式可以确定为常量,在它的下一个定义前,可以进行常量传播。例如:

int x = 1;
int y = x;  // x = 1, => y = 1
x = 3;
int z = 2 * y;   // z => 2 * y = 2 * 1 = 2
int y2 = x * 2;  // x = 3, => y2 = 6

在编译时可转化为:

int x = 1;
int y = 1;
x = 3;
int z = 2;
int y2 = 6;

无用代码删除

long long T_T() {
    long long a = 114514;
    long long b = a * 1919810;
    long long c = 1145;
    return c;
}

在编译时可转化为:

long long test() {
    return 1145;
}

这个例子不仅有 无用代码删除,还有 常量传播

关于循环

  • 循环替换

    do-while 外套 if 代替 for。(虽然不知道能快多少)

  • 循环不变量外提

  • 循环判断外提

    就是把 if 等分支结构放在 for 等的外面(虽然不知道能快多少)。

剩下的

还不太理解,直接参见原文献吧。

本人出现过的问题

关于函数

对于函数,我们必须要严格规范函数返回类型的使用。否则会 RE。举个例子:

// This is the wrong code(function).

inline int awa() {
    /* ... */
    // You have no returns in non-void functions.
    // In the older compiler, there's no wrong in this code(function).
    // But in the compiler now, this code(function) will tell you RE.
}
// These are the right codes(functions).

inline int qwq() {
    /* ... */
    return 114514;
    // You must have at least a return(except in the void functions), and this is right. 
}

inline void T_T() {
    // In the void functions, you must have no returns.
}

好了,今天是被 O2 坑害的一天。

关于不知道

还有一些厌氧 code,不吸氧就 AC,吸氧就 RE(这不分明是欠揍?),有可能是越界问题。

参考文献

  1. 编译优化 - OI Wiki