免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
123下一页
最近访问板块 发新帖
查看: 7221 | 回复: 23
打印 上一主题 下一主题

[C] 循环优化 -- 不变量外提 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2008-08-15 10:30 |只看该作者 |倒序浏览
strlen_chk.c计算sum1与sum2的目标相同,但是效率是不一样;参考汇编代码strlen_chk.s ,计算sum2时,strlen函数每次循环都被调用。
编译器对于循环优化--不变量外提; 一般的表达式都能够进行归纳优化, 但对函数一般无法进行优化;写程序时最好进行人工优化。

strlen_chk.c:


  1. #include <stdio.h>
  2. #include <string.h>

  3. int main(int argc, char **argv)
  4. {
  5.     char    buf[1024];
  6.     int    len = 0;
  7.     int    sum1 = 0, sum2 = 0;
  8.     int    i = 0;

  9.     len = strlen( buf );
  10.     for( i = 0; i < len; i++ )
  11.         sum1 += i;

  12.     for( i = 0; i < strlen(buf); i++ )
  13.         sum2 += i;

  14.     return sum1 + sum2;
  15. }

复制代码



编译 cc -S -O3  strlen_chk.c
strlen_chk.s


  1.     .file    "strlen_chk.c"
  2.     .text
  3.     .p2align 4,,15
  4. .globl main
  5.     .type    main, @function
  6. main:
  7. .LFB24:
  8.     subq    $912, %rsp
  9. .LCFI0:
  10.     xorl    %r11d, %r11d
  11.     xorl    %r10d, %r10d
  12.     leaq    -120(%rsp), %r9
  13.     movq    %r9, %rsi

  14. ---------------------------------------
  15. *** .L2  计算 len = strlen( buf ); store in eax;
  16. *** .L25 .L23 计算    for( i = 0; i < len; i++ )  sum1 += i;

  17. .L2:
  18.     movl    (%rsi), %eax
  19.     addq    $4, %rsi
  20.     leal    -16843009(%rax), %edx
  21.     notl    %eax
  22.     andl    %eax, %edx
  23.     movl    %edx, %ecx
  24.     andl    $-2139062144, %ecx
  25.     je    .L2
  26.     movl    %ecx, %r8d
  27.     leaq    2(%rsi), %rdi
  28.     shrl    $16, %r8d
  29.     andl    $32896, %edx
  30.     cmove    %r8d, %ecx
  31.     cmove    %rdi, %rsi
  32.     movl    %ecx, %edx
  33.     addb    %cl, %dl
  34.     sbbq    $3, %rsi
  35.     xorl    %edx, %edx
  36.     movl    %esi, %eax
  37.     subl    %r9d, %eax
  38.     jmp    .L23
  39. .L25:
  40.     addl    %edx, %r11d
  41.     incl    %edx
  42. .L23:
  43.     cmpl    %eax, %edx
  44.     jl    .L25
  45.     xorl    %edi, %edi
  46.     .p2align 4,,7
  47. -------------------------------------------

  48. -------------------------------------------
  49. *** .L8 .L11 计算    for( i = 0; i < strlen(buf); i++ )  sum2 += i;
  50. *** 在.L11中,每次循环 strlen(buf)都被调用;
  51. *** 对于循环优化--不变量外提,gcc -O3无法归纳strlen函数为不变量。

  52. .L8:
  53.     movslq    %edi,%r8
  54.     movq    %r9, %rsi
  55.     .p2align 4,,7
  56. .L11:
  57.     movl    (%rsi), %ecx
  58.     addq    $4, %rsi
  59.     leal    -16843009(%rcx), %edx
  60.     notl    %ecx
  61.     andl    %ecx, %edx
  62.     movl    %edx, %ecx
  63.     andl    $-2139062144, %ecx
  64.     je    .L11
  65.     movl    %ecx, %eax
  66.     shrl    $16, %eax
  67.     andl    $32896, %edx
  68.     leaq    2(%rsi), %rdx
  69.     cmove    %eax, %ecx
  70.     movl    %ecx, %eax
  71.     cmove    %rdx, %rsi
  72.     addb    %cl, %al
  73.     sbbq    $3, %rsi
  74.     subq    %r9, %rsi
  75.     cmpq    %rsi, %r8
  76.     jae    .L26
  77.     addl    %edi, %r10d
  78.     incl    %edi
  79.     jmp    .L8
  80. ---------------------------------------
  81. .L26:
  82.     leal    (%r11,%r10), %eax
  83.     addq    $912, %rsp
  84.     ret
  85. .LFE24:
  86.     .size    main, .-main
  87.     .section    .eh_frame,"a",@progbits
  88. .Lframe1:
  89.     .long    .LECIE1-.LSCIE1
  90. .LSCIE1:
  91.     .long    0x0
  92.     .byte    0x1
  93.     .string    ""
  94.     .uleb128 0x1
  95.     .sleb128 -8
  96.     .byte    0x10
  97.     .byte    0xc
  98.     .uleb128 0x7
  99.     .uleb128 0x8
  100.     .byte    0x90
  101.     .uleb128 0x1
  102.     .align 8
  103. .LECIE1:
  104. .LSFDE1:
  105.     .long    .LEFDE1-.LASFDE1
  106. .LASFDE1:
  107.     .long    .LASFDE1-.Lframe1
  108.     .quad    .LFB24
  109.     .quad    .LFE24-.LFB24
  110.     .byte    0x4
  111.     .long    .LCFI0-.LFB24
  112.     .byte    0xe
  113.     .uleb128 0x398
  114.     .align 8
  115. .LEFDE1:
  116.     .section    .note.GNU-stack,"",@progbits
  117.     .ident    "GCC: (GNU) 3.4.6 20060404 (Red Hat 3.4.6-3)"

复制代码

论坛徽章:
0
2 [报告]
发表于 2008-08-15 10:48 |只看该作者
这个标题很容易让人产生误解啊

论坛徽章:
0
3 [报告]
发表于 2008-08-15 11:37 |只看该作者
好的编译器会帮你做这个优化的.LZ试试用O2级别去编译程序再看看汇编码.

论坛徽章:
0
4 [报告]
发表于 2008-08-15 16:53 |只看该作者
绝大多数编译器都不能做这个优化。
如果想要做这个不变量外提,必须让编译器判断出每次调用函数strlen(buf)都会返回相同的值。如果没有strlen函数的内部信息(一般情况下,系统只有strlen的二进制版本,没有源码),编译器不能判断。所以,为了正确性,绝对不能做这个优化。
即便有strlen的内部信息,也需要非常好的别名分析和过程间分析,保证两点:
1、对于strlen,参数不变,返回值不变;
2、sum2和buf没有关系;

在一般意义上,这两个问题都是不可判定的。


原帖由 converse 于 2008-8-15 11:37 发表
好的编译器会帮你做这个优化的.LZ试试用O2级别去编译程序再看看汇编码.

论坛徽章:
0
5 [报告]
发表于 2008-08-15 18:04 |只看该作者
空间换时间
使用len = strlen(buf);多用了一个变量

论坛徽章:
0
6 [报告]
发表于 2008-08-15 21:49 |只看该作者
编译器会自动进行这种优化的

论坛徽章:
0
7 [报告]
发表于 2008-08-15 21:50 |只看该作者
原帖由 freearth 于 2008-8-15 16:53 发表
绝大多数编译器都不能做这个优化。
如果想要做这个不变量外提,必须让编译器判断出每次调用函数strlen(buf)都会返回相同的值。如果没有strlen函数的内部信息(一般情况下,系统只有strlen的二进制版本,没有源 ...

绝大多数编译器都不能做这个优化,最好是自己优化

论坛徽章:
0
8 [报告]
发表于 2008-08-15 21:55 |只看该作者
原帖由 yunlong9981 于 2008-8-15 10:30 发表
strlen_chk.c计算sum1与sum2的目标相同,但是效率是不一样;参考汇编代码strlen_chk.s ,计算sum2时,strlen函数每次循环都被调用。
编译器对于循环优化--不变量外提; 一般的表达式都能够进行归纳优化, 但对 ...

优化和编程风格有时候有些矛盾
需要取舍

论坛徽章:
0
9 [报告]
发表于 2008-08-15 23:45 |只看该作者

回复 #4 freearth 的帖子

就算是自己写的函数,有代码,也未必可以优化。有人把编译器想的太智能了。

5楼考虑一下临时变量。

论坛徽章:
0
10 [报告]
发表于 2008-08-15 23:51 |只看该作者
原帖由 xi2008wang 于 2008-8-15 18:04 发表
空间换时间
使用len = strlen(buf);多用了一个变量

4个字节能对性能造成影响?
讨论至此已经没有任何意义
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP