原文链接:http://blog.pfan.cn/ddtme/7998.html
优化选项(OPTIMIZATION OPTION)
这些选项控制多种优化措施:
-
-O
-O1
-
优化
.
对于大函数
,
优化编译占用稍微多的时间和相当大的内存
.
不使用`-O'选项时,编译器的目标是减少编译的开销,使编译结果能够调试.语句是独立的:如果在 两条语句之间用断点中止程序,你可以对任何变量重新赋值,或者在函数体内把程序计数器指到其他语句,以及从源程序中 精确地获取你期待的结果.
不使用`-O'选项时,只有声明了register的变量才分配使用寄存器.编译结果比不用 `-O'选项的PCC要略逊一筹.
使用了`-O'选项,编译器会试图减少目标码的大小和执行时间.
如果指定了`-O'选项, `-fthread-jumps'和`-fdefer-pop'选项将被 打开.在有delay slot的机器上, `-fdelayed-branch'选项将被打开.在即使没有帧指针 (frame pointer)也支持调试的机器上, `-fomit-frame-pointer'选项将被打开.某些机器上 还可能会打开其他选项.
-O2
-
多优化一些
.
除了涉及空间和速度交换的优化选项
,
执行几乎所有的优化工作
.
例如不进行循环展开
(loop unrolling)和函数内嵌
(inlining).
和
-O
选项比较
,
这个选项既增加了编译时间
,
也提高了生成代码的 运行效果
.
-
优化的更多.除了打开-O2所做的一切,它还打开了-finline-functions选项
.
-
不优化
.
如果指定了多个-O选项,不管带不带数字,最后一个选项才是生效的选项.
诸如`-fflag'此类的选项描述一些机器无关的开关.大多数开关具有肯定和否定两种格式; `-ffoo'开关选项的否定格式应该是`-fno-foo'.下面的列表只展示了一种格式---那个不是 默认选项的格式.你可以通过去掉或添加`no-'构造出另一种格式.
-
-ffloat-store
-
不要在寄存器中存放浮点变量
.
这样可以防止某些机器上不希望的过高精度
,
如
68000
的浮点寄存器
(
来自
68881)
保存的精度超过了
double
应该具有的精度
.
对于大多数程序,过高精度只有好处.但是有些程序严格依赖于IEEE浮点数的定义.对这样的程序可以使用 `-ffloat-store'选项.
-fmemoize-lookups
-fsave-memoized
-
使用探索法
(heuristic)
进行更快的编译
(
仅对
C++).
默认情况下不使用探索法
.
由于探索法只对某些输入文件 有效
,
其他程序的编译速度会变得更慢
.
第一次编译器必须对成员函数(或对成员数据的引用)建立一个调用.它必须(1)判断出这个类是否实现了那个名字的 成员函数; (2)决定调用哪个成员函数(涉及到推测需要做哪种类型转换); (3)检查成员函数对调用者是否可见.所有这些构成 更慢的编译.一般情形,第二次对成员函数(或对成员数据的引用)建立的调用,必须再次经过相同长度的处理.这意味着象 这样的代码
cout << "This " << p << " has " << n << " legs./n";
对整个三步骤要做六次遍历.通过使用软件缓存, ``命中''能够显著地减少这种代价.然而不幸的是,使用这种缓存 必须实现其他机制,带来了它自己的开销. `-fmemoize-lookups'选项打开软件缓存.
因为函数的正文环境不同,函数对成员和成员函数的访问权(可见性)也可能不同, g++可能需要刷新缓存. 使用`-fmemoize-lookups'选项,每编译完一个函数就刷新缓存.而`-fsave-memoized'选项 也启用同样的缓存,但是当编译器发觉最后编译的函数的正文环境产生的访问权和下一个待编译的函数相同,编译器就 保留缓存内容.这对某个类定义许多成员函数时非常有用:除了某些其他类的友函数,每个成员函数拥有和其他成员函数完全一样 的访问权,因而无需刷新缓存.
-fno-default-inline
-
默认为不要把成员函数内嵌
,
因为它们定义在类的作用域内
(
仅
C++).
-
一旦函数返回
,
参数就立即弹出
.
对于那些调用函数后必须弹出参数的机器
,
编译器一般情况下让几次函数调用的参数 堆积在栈上
,
然后一次全部弹出
.
-
做数学运算前把将要使用的内存操作数送入寄存器
.
通过把内存访问转换成潜在的公共子表达式
,
它可能产生较好的目标码
.
如果它们不是公共子表达式
,
指令组合应该消除各自的寄存器载荷
.
我乐意倾听不同意见
.
-
做数学运算前把将要使用的内存地址常数送入寄存器
.
它可能和
`-fforce-mem'
一样产生较好的 目标码
.
我乐意倾听不同意见
.
-
对于不需要帧指针
(frame pointer)
的函数
,
不要在寄存器中保存帧指针
.
这样能够避免保存
,
设置和恢复 帧指针的指令
;
同时对许多函数提供一个额外的寄存器
.
但是在大多数机器上将无法调试
.
某些机器上,如Vax,这个选项无效,因为标准调用序列自动处理帧指针,通过假装不存在而不保存任何东西.机器描述宏 FRAME_POINTER_REQUIRED控制目标机是否支持这个选项.
-finline-functions
-
把所有简单的函数集成进调用者
.
编译器探索式地决定哪些函数足够简单
,
值得这种集成
.
如果集成了所有给定函数的调用,而且函数声明为static,那么一般说来GCC有权不按汇编代码输出函数.
-fcaller-saves
-
允许在寄存器里分配数值
,
但是这个方案通常受到各个函数调用的冲击
,
因此
GCC
生成额外的代码
,
在函数调用的 前后保存和复原寄存器内容
.
仅当生成代码看上去优于反之结果时才实现这样的分配
.
某些机器上该选项默认为允许,通常这些机器没有调用保护寄存器代替使用.
-fkeep-inline-functions
-
即使集成了某个函数的所有调用
,
而且该函数声明为
static,
仍然输出这个函数一个独立的
,
运行时可调用 的版本
.
-
不要把函数地址存入寄存器
;
让调用固定函数的指令显式给出函数地址
.
这个选项产生效率较低的目标码,但是如果不用这个选项,某些不寻常的hack,改变汇编器的输出,可能因优化而带来 困惑.
-fno-peephole
-
禁止任何机器相关的
peephole
优化
.
-
这个选项出于速度优化
,
允许
GCC
违反某些
ANSI
或
IEEE
规则
/
规格
.
例如
,
它允许编译器假设
sqrt
函数的参数是非负数
.
这个选项不被任何`-O'选项打开,因为对于严格依靠IEEE或ANSI规则/规格实现的数学函数,程序可能 会产生错误的结果.
下列选项控制特定的优化. `-O2'选项打开下面的大多数优化项,除了`-funroll-loops'和 `-funroll-all-loops'项.
而`-O'选项通常打开`-fthread-jumps'和`-fdelayed-branch' 优化项,但是特定的机器上的默认优化项有可能改变.
如果特别情况下非常需要``微调''优化,你可以使用下面的选项.
-
-fstrength-reduce
-
执行循环强度缩小
(loop strength reduction)
优化
,
并且消除重复变量
.
-
执行优化的地点是
,
如果某个跳转分支的目的地存在另一个条件比较
,
而且该条件比较包含在前一个比较语句之内
,
那么 执行优化
.
根据条件是
true
或者
false,
前面那条分支重定向到第二条分支的目的地或者紧跟在第二条分支后面
.
-
执行循环展开
(loop unrolling)
优化
.
仅对循环次数能够在编译时或运行时确定的循环实行
.
-
执行循环展开
(loop unrolling)
优化
.
对所有循环实行
.
通常使程序运行的更慢
.
-
在公共子表达式消元
(common subexpression elimination)
的时候
,
如果没有其他路径到达某个跳转的 目的地
,
就扫过这条
jump
指令
.
例如
,
如果
CSE
遇到带有
else
从句的
if
语句
,
当条件测试为
false
时
, CSE
就跟在
jump
后面
.
-
它类似于
`-fcse-follow-jumps'
选项
,
但是
CSE
跟在条件跳转后面
,
条件跳转跳过了 语句块
(block).
如果
CSE
遇到一条简单的
if
语句
,
不带
else
从句
, `-fcse-skip-blocks'
选项将导致
CSE
跟在
if
产生的跳转后面
.
-
执行循环优化后
,
重新进行公共子表达式消元
.
-
如果看上去合理就省略构造子
(
仅
C++).
根据这个选项
,
对于下面的代码
, GNU C++
直接从调用
foo
初始化
y,
而无需通过临时变量
:
A foo (); A y = foo ();
如果没有这个选项, GNU C++首先通过调用类型A 合适的构造子初始化y;然后把 foo的结果赋给临时变量;最后,用临时变量替换`y'的初始值.
ANSI C++标准草案规定了默认行为(`-fno-elide-constructors').如果程序的构造子存在 副效应, `-felide-constructors'选项能够使程序有不同的表现,因为可能忽略一些构造子的调用.
-fexpensive-optimizations
-
执行一些相对开销较大的次要优化
.
-
如果对目标机支持这个功能
,
它试图重新排列指令
,
以便利用延迟分支
(delayed branch)
指令后面的指令空隙
.
-
如果对目标机支持这个功能
,
它试图重新排列指令
,
以便消除因数据未绪造成的执行停顿
.
这可以帮助浮点运算或内存访问 较慢的机器调取指令
,
允许其他指令先执行
,
直到调取指令或浮点运算完成
.
- 类似于 `-fschedule-insns' 选项 , 但是在寄存器分配完成后 , 需要一个额外的指令调度过程 . 对于 寄存器数目相对较少 , 而且取内存指令大于一个周期的机器 , 这个选项特别有用 .