设为首页 加入收藏

TOP

5.8 编译器对循环结构的优化(2)
2013-10-07 14:29:53 来源: 作者: 【 】 浏览:59
Tags:5.8 编译器 循环 结构 优化

5.8 编译器对循环结构的优化(2)

分析代码清单5-25发现,它与图5-13的思路竟然完全一致。编译器通过检查,将for循环结构最终转换成了do循环结构。使用if单分支结构进行第一次执行循环体的判断,再将转换后的do循环嵌套在if语句中,就形成了“先执行,后判断”的do循环结构。由于在O2选项下,while循环及for循环都可以使用do循环进行优化,所以在分析经过O2选项优化的反汇编代码时,很难转换回相同源码,只能尽量还原等价源码。读者可根据个人习惯转换对应的循环结构。

从结构上优化循环后,还需从细节上再次优化,以进一步提高循环的效率。4.4节介绍了编译器的各种优化技巧,循环结构的优化也使用这些技巧,其中常见的优化方式是“代码外提”。例如,循环结构中经常有重复的操作,在对循环结构中语句块的执行结果没有任何影响的情况下,可选择相同代码外提,以减少循环语句块中的执行代码,提升循环执行效率,如代码清单5-26所示。

代码清单5-26 循环结构优化—代码外提

  1. // C++(www.cppentry.com)源码说明:for循环完成整数累加和  
  2. int CodePick(int nCount){  
  3.     int nSum = 0;  
  4.     int nIndex = 0;  
  5.     do {  
  6.         nSum += nIndex;  
  7.         nIndex++;  
  8.     // 此处代码每次都要判断nCount – 1,nCount并没有自减,仍然为一个固定值  
  9. // 可在循环体外先对nCount进行减等于1操作,再进入循环体  
  10.     } while(nIndex < nCount - 1);  
  11.     return nSum;  
  12. }  
  13.  
  14. // 经过优化后的反汇编代码  
  15. .text:00401000 sub_401000      proc near; CODE XREF: _main+21-p  
  16. .text:00401000 arg_0           = dword ptr  4  
  17. ; 获取参数到edx中  
  18. .text:00401000                 mov     edx, [esp+arg_0]  
  19. .text:00401004                 xor     eax, eax  
  20. .text:00401006                 xor     ecx, ecx  
  21. ; 代码外提,对edx执行自减1操作  
  22. .text:00401008                 dec     edx  
  23. ; 进入循环体,在循环体内直接对保存参数的edx进行比较,没有任何减1操作  
  24. .text:00401009 loc_401009:       ; CODE XREF: sub_401000+Ej  
  25. .text:00401009                 add     eax, ecx  
  26. .text:0040100B                 inc     ecx  
  27. .text:0040100C                 cmp     ecx, edx  
  28. .text:0040100E                 jl      short loc_401009  
  29. .text:00401010                 retn  
  30. .text:00401010 sub_401000      endp 

分析代码清单5-26可知,编译器将循环比较“nIndex < nCount - 1”中的“nCount – 1”进行了外提。由于“nCount – 1”中nCount在循环体中没有被修改,因此对它的操作是可以被拿到循环体外。被外提后的代码如下:

  1. int CodePick(int nCount){  
  2.     int nSum = 0;  
  3.     int nIndex = 0;  
  4.     nCount -1;                    // 外提代码  
  5.     do {  
  6.         nSum += nIndex;  
  7.         nIndex++;  
  8.     } while(nIndex < nCount);       // 原来的nCount-1被外提了  
  9.     return nSum;  

这种外提是有选择性的—只有在不影响循环结果的情况下,才可以外提。

除了代码外提,还可以通过一些方法进一步提升循环结构的执行效率—强度削弱,即用等价的低强度运算替换原来代码中的高强度运算,例如,用加法代替乘法,如代码清单5-27所示。

代码清单5-27 循环强度降低优化—Release版

  1. // C++(www.cppentry.com)源码说明:强度削弱  
  2. int main(int argc){  
  3.   int t = 0;  
  4.   int i = 0;  
  5.   while (t < argc){  
  6.     t = i * 99;     // 强度削弱后,这里将不会使用乘法运算  
  7.     i++;            // 此处转换后将为  t = i; i += 99;  
  8.   }             // 利用加法运算替换掉了指令周期长的乘法运算  
  9.   printf("%d", t);  
  10. return 0;  
  11. }  
  12.  
  13. ; 优化后的反汇编代码  
  14. .text:00401020 arg_0           = dword ptr  4  
  15. ; 将参数信息保存到edx中  
  16. .text:00401020  mov     edx, [esp+arg_0]  
  17. .text:00401024  xor     eax, eax        ; 清空eax  
  18. .text:00401026  test    edx, edx  
  19. .text:00401028  jle     short loc_401035  
  20. .text:0040102A  xor     ecx, ecx            ; 清空ecx  
  21. .text:0040102C  
  22. ; 循环语句块首地址  
  23. .text:0040102C loc_40102C:         ; CODE XREF: sub_401020+13j  
  24. .text:0040102C  mov     eax, ecx            ; 将ecx传入eax中  
  25. ; ecx自加63h,即十进制99,等价于ecx每次加1乘以99  
  26. .text:0040102E  add     ecx, 63h  
  27. .text:00401031  cmp     eax, edx  
  28. .text:00401033  jl      short loc_40102C    ; eax小于edx则执行跳转  
  29. .text:00401035  
  30. .text:00401035 loc_401035:          ; CODE XREF: sub_401020+8j  
  31. ;printf函数调用处略  
  32. .text:00401043                  retn  
  33. .text:00401043 sub_401020       endp 

】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇5.6 降低判定树的高度(1) 下一篇5.8 编译器对循环结构的优化(1)

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容: