2

trying to do the following in asembly:

#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");
}

I've don't code in assembly much and I want to be able to understand my code when I look at the assembly languages, so simply converting this into assembly with gcc is kinda out of the question.

My goal here is to use as little nop as possible when I make this code. So I suppose my questions would be:

  1. What is the best way to do powers in assembly without a massive amount of re-entering things into the register? Is that even possible?
  2. When I loop in assembly, will I want a's value set already? or can I program it kind of like this for loop here? (can I avoid while-looping to save space)
davidkonrad
  • 83,997
  • 17
  • 205
  • 265
Ryan Tibbetts
  • 412
  • 1
  • 8
  • 22
  • @Christian: You're correct, but read the prose. The question is asking how something equivalent would be done in assembly, using C as an model of what they want to happen. – icktoofay Sep 23 '13 at 00:57
  • @Christian: Even if it is homework, they are asking a valid question and are not asking for the work to be done for them. – icktoofay Sep 23 '13 at 01:00
  • Ok. Given. But I can see nothing he tried so far. – Mark Sep 23 '13 at 01:00
  • 1
    Two suggestions: 1) Excellent link on GCC/x86 assembly: [Programming from the Ground Up, Jonathan Bartlett](http://savannah.nongnu.org/projects/pgubook/), 2) "gcc -S" your C snippets and analyze the results. "converting this into assembly with gcc" is emphatically *NOT* "kinda outy of the question". It's *RECOMMENDED*. IMHO... – paulsm4 Sep 23 '13 at 01:01
  • Not sure what you're exactly asking, for 1) Are you looking for avoid transfer data by using registers? – Jack Sep 23 '13 at 01:04
  • 1
    @Ryan, I found this interesting [link](http://stackoverflow.com/questions/1969809/x86-max-min-asm-instructions/1969860#1969860) you might wanna check. – Mark Sep 23 '13 at 01:05
  • @ChristianMark I was given parameters to write a program and I knew how to write it in C, but not in assembly. The code you see is my own and not verbatim from an assignment, merely my understanding of how I am to do the assignment with proper computer logic in another language I understand. Also thank you for the link, but I fear it's a bit too confusing for my current understanding of assembly. – Ryan Tibbetts Sep 23 '13 at 01:19
  • @Jack I think what I was asking was if I could simply do something along the lines of: do simply just multiply over and over again or is there a function/method for using exponents? – Ryan Tibbetts Sep 23 '13 at 01:20
  • I got now. Well, usually assemblies doesn't have such features(as far I know) and then you need to write yourself. But the only way to know it is by reading the documentation. – Jack Sep 23 '13 at 01:29
  • @Jack I think I may very well just use a loop to do it, kind of like having a loop that has an input value that lets you run the loop the same many times as the given value. – Ryan Tibbetts Sep 23 '13 at 01:37
  • 1
    `for (a = -3; a >= 3; a++)` -- how often do you think this loop will execute? – Kerrek SB Sep 23 '13 at 07:07
  • @KerrekSB I imagine it should execute about 7 times. – Ryan Tibbetts Sep 23 '13 at 16:26
  • Instead of using "a*a*a*a*a*a*a - a*a*a*a*..." you should use "a*a*a*a*(a*a*a-...)" to save time and space. Unfortunately there is no possibility to do powers in assembly language more efficiently. However some CPUs (x86 not - as far as I know) already provide a "min" and a "max" instruction or conditional "mov" instructions ("isel" on some PowerPCs) that may be used to optimize the "min" and "max" operations. – Martin Rosenau Sep 26 '13 at 07:05

1 Answers1

0

This code is a tremendous example of what compiler optimization can do. Assuming you meant for (a = -3; a <= 3; a++) ... then you can re-code this into:

#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;
}

Intel's ICC turns this directly into:

  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) also can to it, it creates:

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 (up to and including 4.8.1) doesn't seem able to compile-time calculate in this case, while it unrolls the loop it inserts a sequence of multiplies, conditional moves / SSE min/max instructions.

But if you explicitly unroll the loop in code, manually, then you get:

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);

and GCC is able to calculate it at compile-time:

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

Morale: The best result in this case you get by not trying to optimize the assembler output :)

FrankH.
  • 17,675
  • 3
  • 44
  • 63
  • I should've added, just to make it clear, that this specific sourcecode has an _analytically computable_ result, i.e. you can figure out the values for `c` / `d` at the end using "pencil & paper". That's what the compilers do here. Whether this misses the point of the assignment or not, it's the _best result_ for this case. If you wish to see how the compiler expresses the min/max (on x86, three options: "classical" `cmp` and `j...`, `cmp` and conditional moves, and SSE min/max instructions), crank the range boundaries up. – FrankH. Sep 26 '13 at 10:15