nul*_*ull 6 delphi optimization performance for-loop compiler-optimization
我刚刚在一个正在编写的程序中注意到了一些非常有趣的东西.我有一个简单的过程,用一个x类型的对象填充TStringlist.
我在跟踪一个问题时添加了一个断点,偶然发现这个问题,希望有人能够解释它为什么会发生这种情况,或者链接到相关文档,因为我找不到任何东西.
我的循环从0到11开始.我正在使用的指针在循环中初始化为nPtr:= 0但是当程序运行时,nPtr var从12变为1.然后我将var初始化为循环如代码片段所示,但同样的事情发生了.该变量在单元中没有其他地方使用.
我问过一位与我合作的人,他们说这是由于Delphi的优化,但我想知道为什么以及如何决定应该影响哪个循环.
谢谢你的帮助.
码:
procedure TUnit.ProcedureName;
var
nPtr : Integer;
obj : TObject;
begin
nPtr:=0;//added later
for nPtr := 0 to 11 do
begin
obj := TObject.Create(Self);
slPeriodList.AddObject('X', obj);
end;
end;
Run Code Online (Sandbox Code Playgroud)
只有在循环体不引用循环变量时才可以进行优化.在这种情况下,如果循环的下限为零,则编译器将反转循环.
如果循环变量从未被循环体引用,那么编译器在实现循环时是合理的,但它很高兴.所需要做的就是按照循环边界的要求多次执行循环体.实际上,编译器在优化循环变量方面是完全合理的.
考虑这个程序:
{$APPTYPE CONSOLE}
procedure Test1;
var
i: Integer;
begin
for i := 0 to 11 do
Writeln(0);
end;
procedure Test2;
var
i: Integer;
begin
for i := 0 to 11 do
Writeln(i);
end;
begin
Test1;
Test2;
end.
Run Code Online (Sandbox Code Playgroud)
该主体Test1由XE7编译为此代码,32位Windows编译器,具有发布选项:
Project1.dpr.9: for i := 0 to 11 do 00405249 BB0C000000 mov ebx,$0000000c Project1.dpr.10: Writeln(0); 0040524E A114784000 mov eax,[$00407814] 00405253 33D2 xor edx,edx 00405255 E8FAE4FFFF call @Write0Long 0040525A E8D5E7FFFF call @WriteLn 0040525F E800DBFFFF call @_IOTest Project1.dpr.9: for i := 0 to 11 do 00405264 4B dec ebx 00405265 75E7 jnz $0040524e
编译器正在向下运行循环,可以通过使用来看到dec.请注意,循环终止测试是在jnz不需要a的情况下执行的cmp.那是因为dec执行与零的隐式比较.
文档dec说明如下:
受影响的旗帜
CF标志不受影响.根据结果设置OF,SF,ZF,AF和PF标志.
ZF当且仅当dec指令的结果为零时,才设置该标志.而ZF决定是否jnz分支的是什么.
发出的代码Test2是:
Project1.dpr.17: for i := 0 to 11 do 0040526D 33DB xor ebx,ebx Project1.dpr.18: Writeln(i); 0040526F A114784000 mov eax,[$00407814] 00405274 8BD3 mov edx,ebx 00405276 E8D9E4FFFF call @Write0Long 0040527B E8B4E7FFFF call @WriteLn 00405280 E8DFDAFFFF call @_IOTest 00405285 43 inc ebx Project1.dpr.17: for i := 0 to 11 do 00405286 83FB0C cmp ebx,$0c 00405289 75E4 jnz $0040526f
请注意,循环变量正在增加,我们现在有一个额外的cmp指令,在每次循环迭代时执行.
值得注意的是,64位Windows编译器不包括此优化.因为Test1它产生了这个:
Project1.dpr.9: for i := 0 to 11 do 00000000004083A5 4833DB xor rbx,rbx Project1.dpr.10: Writeln(0); 00000000004083A8 488B0D01220000 mov rcx,[rel $00002201] 00000000004083AF 4833D2 xor rdx,rdx 00000000004083B2 E839C3FFFF call @Write0Long 00000000004083B7 4889C1 mov rcx,rax 00000000004083BA E851C7FFFF call @WriteLn 00000000004083BF E86CB4FFFF call @_IOTest 00000000004083C4 83C301 add ebx,$01 Project1.dpr.9: for i := 0 to 11 do 00000000004083C7 83FB0C cmp ebx,$0c 00000000004083CA 75DC jnz Test1 + $8
我不确定为什么在64位编译器中没有实现这种优化.我的猜测是,优化在现实世界中的情况可以忽略不计,设计人员选择不花费精力为64位编译器实现它.