在装配中查找最大值和最小值

时间:2013-09-23 00:48:23

标签: loops assembly

尝试在装配中执行以下操作:

#include <stdio.h>
main(){
        int a,b,c=0,d=0;
        for(a = -3; a >= 3; a++){
                b = a*a*a*a*a*a*a - a*a*a*a*4 - a*a*a + a*a*7 + 30*a;
                if(b>=c){
                        c=b;
                }
                if(b<=d){
                        d=b;
                }
        }
    printf("The max value is" + c + "\n");
    printf("The min value is" + d + "\n");
}

我没有在汇编中编写代码,并且我希望能够在查看汇编语言时理解我的代码,所以简单地将其转换为使用gcc的汇编是不可能的。

我的目标是在制作此代码时尽可能少地使用nop。所以我想我的问题是:

  1. 在没有大规模的情况下,在装配中执行权力的最佳方式是什么? 重新进入登记册的数量?那是偶数 可能的?
  2. 当我循环汇编时,我是否需要设置a的值?或者可以 我在这里编程就像这样循环? (我可以避免循环以节省空间)

1 个答案:

答案 0 :(得分:0)

这段代码是编译器优化可以做的一个很好的例子。假设您的意思是for (a = -3; a <= 3; a++) ...,那么您可以将其重新编码为:

#include <stdio.h>

#define val(a)  (a*a*a*a*a*a*a - a*a*a*a*4 - a*a*a + a*a*7 + 30*a)

#define MIN(X, Y)       ((X) > (Y) ? (Y) : (X))
#define MAX(X, Y)       ((X) > (Y) ? (X) : (Y))

int main(int argc, char **argv)
{
    int c = 0, d = 0, a;

    for (a = -3; a <= 3; a++)
            c = MAX(val(a), c), d = MIN(val(a), d);
    printf("max value is %d,\nmin value is %d\n", c, d);
    return 0;
}

英特尔的ICC将其直接转变为:

  4006f9:       [ ... meaningless "ICC glue" instruction ... ]
  4006fd:       bf 7c 0b 40 00          mov    $0x400b7c,%edi
  400702:       be c5 07 00 00          mov    $0x7c5,%esi
  400707:       [ ... meaningless "ICC glue" instruction ... ]
  40070e:       ba 31 f6 ff ff          mov    $0xfffff631,%edx
  400713:       33 c0                   xor    %eax,%eax
  400715:       [ ... meaningless "ICC glue" instruction ... ]
  400719:       e8 2a fe ff ff          callq  400548 <printf@plt>
  40071e:       33 c0                   xor    %eax,%eax
  400720:       48 89 ec                mov    %rbp,%rsp
  400723:       5d                      pop    %rbp
  400724:       c3                      retq

CLang(3.3)也可以,它创造:

0000000000400b60 <main>:
  400b60:       50                      push   %rax
  400b61:       bf 6c 0c 40 00          mov    $0x400c6c,%edi
  400b66:       be c5 07 00 00          mov    $0x7c5,%esi
  400b6b:       ba 31 f6 ff ff          mov    $0xfffff631,%edx
  400b70:       30 c0                   xor    %al,%al
  400b72:       e8 39 fd ff ff          callq  4008b0 <printf@plt>
  400b77:       31 c0                   xor    %eax,%eax
  400b79:       5a                      pop    %rdx
  400b7a:       c3                      retq
在这种情况下,GCC(直到并包括4.8.1)似乎无法进行编译时计算,而在展开循环时,它会插入一系列乘法,条件移动/ SSE最小/最大指令。

但是如果你在代码中明确地展开循环,那么你得到:

c = MAX(val(-3), 0); d = MIN(val(-3), 0);
c = MAX(val(-2), c); d = MIN(val(-2), d);
c = MAX(val(-1), c); d = MIN(val(-1), d);
c = MAX(val(0), c); d = MIN(val(0), d);
c = MAX(val(1), c); d = MIN(val(1), d);
c = MAX(val(2), c); d = MIN(val(2), d);
c = MAX(val(3), c); d = MIN(val(3), d);

并且GCC能够在编译时计算它:

0000000000400630 <main>:
  400630:       48 83 ec 08             sub    $0x8,%rsp
  400634:       ba 31 f6 ff ff          mov    $0xfffff631,%edx
  400639:       be c5 07 00 00          mov    $0x7c5,%esi
  40063e:       bf 50 07 40 00          mov    $0x400750,%edi
  400643:       31 c0                   xor    %eax,%eax
  400645:       e8 79 fe ff ff          callq  4004c0 <printf@plt>
  40064a:       31 c0                   xor    %eax,%eax
  40064c:       48 83 c4 08             add    $0x8,%rsp
  400650:       c3                      retq

士气:在这种情况下你得到的最好结果而不是试图优化汇编程序输出:)