【问题标题】:When does Delphi honor `inline` and when not?Delphi 什么时候尊重“内联”,什么时候不尊重?
【发布时间】:2011-06-19 10:05:14
【问题描述】:

我想优化一段具有这种结构的代码:

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.5%)。如果您对机器代码的外观有所了解,您会发现前两个版本可以很容易地编译为相同的代码。优化失败。
  • @delnan,我有点讨厌人们认为你是个白痴。当然循环是hot,否则我不会打扰。测试做得更多,但我将其简化为本质。我也知道你不能内联 asm 函数,所以合乎逻辑的选择:function Decr(var a: integer): integer; inline; begin asm DEC EAX end; end; 已经过时了。
  • 我很难相信你会比第一段代码做得更好。为什么第二个代码块会比第一个代码块编译得更快,即使它是有效的?我不认为德尔南没有假设你是个白痴。很多人都提出了基于严重误解的优化问题。既然你没有说这个特定的循环是你代码中的热点,我们怎么知道。现在,如果你在循环中做了任何事情,那么 while 测试和 dec 将是微不足道的,所以也许 delnan 有一点。
  • @Johan 你错了。 for 循环可以运行 0 次。始终确保您的循环计数器是有符号整数。事实上总是使用Integer

标签: delphi optimization inline delphi-2007


【解决方案1】:

Delphi Documentation 列举了内联发生或不发生的条件:

  • 任何形式的后期绑定方法都不会发生内联。这包括 虚拟、动态和消息方法。
  • 包含汇编代码的例程不会被内联。
  • 构造函数和析构函数不会被内联。
  • 主程序块、单元初始化和单元完成 块不能内联。
  • 使用前未定义的例程无法内联。
  • 无法内联采用开放数组参数的例程。
  • 代码可以在包中内联,但是,内联永远不会发生在包中 包边界。
  • 循环依赖的单元之间不进行内联。这 包括间接循环 依赖关系,例如,单元 A 使用 B 单元,B 单元使用 C 单元 依次使用单元 A。在此示例中, 编译单元A时,没有代码 单元 B 或单元 C 将被内联 A单元。
  • 当单元处于循环依赖中时,编译器可以内联代码,如 只要要内联的代码来了 从圆形外的一个单位 关系。在上面的例子中,如果 单元 A 也使用单元 D,代码来自 单元 D 可以内联在 A 中,因为它 未参与通函 依赖。
  • 如果在接口部分定义了一个例程并且它访问 实现中定义的符号 部分,该例程不能 内联。
  • 如果标有 inline 的例程使用来自其他单元的外部符号,则所有 这些单位必须列在 使用语句,否则例程 不能内联。
  • while-do 条件表达式中使用的过程和函数 并且不能重复直到语句 展开内联。
  • 在一个单元内,应定​​义内联函数的主体 在调用函数之前。 否则,函数体, 编译器不知道 当它到达呼叫站点时,不能 内联展开。

在你的情况下检查这个条件:

while-do 和 repeat-until 语句的条件表达式中使用的过程和函数不能内联扩展。

【讨论】:

    【解决方案2】:

    由于某种原因,编译器没有内联while 循环控制表达式。 Hallvard Vassbotn前段时间讨论过这个问题(阅读文末)。

    【讨论】:

    • 上一部分或文章的快速总结:while True do begin if Decr(i) &lt; 0 then Break;inlines Decr.
    猜你喜欢
    • 2010-12-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-04
    • 2021-06-17
    • 1970-01-01
    相关资源
    最近更新 更多