我正在努力优化一段具有此构造的代码:
while (i > 0) do begin
Dec(i);
这看起来效率低下,所以我试着这样做:
while (Dec(i) >= 0) do begin
这不起作用,因为Dec是一个过程,而不是一个函数。
所以我把它重写为:
procedure Withloop;
var
....
function Decr(var a: integer): integer; inline;
begin
Dec(a);
Result:= a;
end;
...
while (Decr(i) >= 0) do begin
但是这会编译成:
SDIMAIN.pas.448: while (Decr(i) >= 0) do begin
00468EE5 8BC4 mov eax,esp
00468EE7 E8D0FEFFFF call Decr <<--- A call??
00468EEC 85C0 test eax,eax
00468EEE 0F8D12FFFFFF jnl $00468e06
00468EF4 EB01 jmp $00468ef7
然而,在该计划的另一部分,它内联函数就好了
我可以使用什么经验法则(或硬规则)来了解Delphi将遵守inline
指令?
答案 0 :(得分:22)
Delphi Documentation
列举了内联发生或不发生的条件:
- 任何形式的后期绑定方法都不会进行内联。这包括 虚拟,动态和消息方法。
- 不会内联包含汇编代码的例程。
- 不会内联构造函数和析构函数。
- 主程序块,单元初始化和单元终结 块无法内联。
- 使用前未定义的例程无法内联。
- 无法内联打开数组参数的例程。
- 代码可以在包中内联,但是,内联永远不会发生 包边界。
- 在循环相关的单元之间不进行内联。这个 包括间接循环 依赖性,例如,单元A使用 单元B,单元B使用单元C 反过来使用单位A.在这个例子中, 编译单元A时,没有代码 单元B或单元C将内联 单位A。
- 编译器可以在单元处于循环依赖关系时内联代码,如 要内联的代码来了 来自通告外的单位 关系。在上面的例子中,如果 单元A也使用单元D,代码来自 单元D可以在A中内联,因为它 没有参与通告 依赖性。
- 如果在接口部分中定义了例程并且它正在访问 实现中定义的符号 部分,那例程不能 内联。
- 如果标有内联的例程使用其他单位的外部符号,则全部 这些单位必须列在 使用语句,否则例程 无法内联。
- while-do中条件表达式中使用的过程和函数 并且重复 - 直到陈述不能 扩展内联。
- 在单元内,应定义内联函数的主体 在调用函数之前。 否则,功能的主体, 这是编译器不知道的 当它到达呼叫站点时,不能 内联扩展。
在你的情况下检查这个条件:
while-do和repeat-until语句中的条件表达式中使用的过程和函数无法内联扩展。
答案 1 :(得分:10)
由于某种原因,编译器没有内联while
循环控制表达式。 Hallvard Vassbotn前一段时间讨论了这个问题(请阅读文章末尾)。