1

I'm trying to multiply in assembler by shifting and adding and I get the weirdest output from the following code. If the last two function calls in the int main are commented out I get a normal result but otherwise I get a normal result for the first call and two garbage results for the second and third?

#include <iostream>

using namespace std;

int times_ten(int multiply_by_ten)
{
    int multiplied_by_ten = 0;
    //this multiplies by 10
    __asm__("shld   %%eax,%1;"
                  "movl %%eax,%%ebx;"
                  "shld  %%eax,%1;"
                  "shld  %%eax,%1;"
                  "addl  %%ebx,%%eax;"
                  : "=r" (multiplied_by_ten)
                  : "a" (multiply_by_ten)
    );

    return multiplied_by_ten;
}
int times_hundred(int multiply_by_hundred)
{
    int multiplied_by_hundred = 0;
    //this multiplies by 100
    __asm__("shld   %%eax,%1;"
                  "shld   %%eax,%1;"
                  "movl %%eax,%%ebx;"
                  "shld  %%eax,%1;"
                  "shld  %%eax,%1;"
                  "shld  %%eax,%1;"
                  "movl %%eax,%%edx;"
                  "shld  %%eax,%1;"
                  "addl  %%ebx,%%eax;"
                  "addl  %%edx,%%eax;"
                  : "=r" (multiplied_by_hundred)
                  : "a" (multiply_by_hundred)

    );

    return multiplied_by_hundred;
}
int main()
{
    cout<<times_hundred(1)<<endl;
    cout<<times_ten(1)<<endl;
    cout<<times_hundred(1)<<endl;

    return 0;
}

The following has the clobber list but it wont compile. the errors are below it.

#include <iostream>

using namespace std;

int times_ten(int multiply_by_ten)
{
    int multiplied_by_ten = 0;
    //this multiplies by 10
    __asm__("shld   %%eax,%1;"
                  "movl %%eax,%%ebx;"
                  "shld  %%eax,%1;"
                  "shld  %%eax,%1;"
                  "addl  %%ebx,%%eax;"
                  : "=r" (multiplied_by_ten)
                  : "a" (multiply_by_ten)
                  : "%%eax", "%%ebx"
    );

    return multiplied_by_ten;
}
int times_hundred(int multiply_by_hundred)
{
    int multiplied_by_hundred = 0;
    //this multiplies by 100
    __asm__("shld   %%eax,%1;"
                  "shld   %%eax,%1;"
                  "movl %%eax,%%ebx;"
                  "shld  %%eax,%1;"
                  "shld  %%eax,%1;"
                  "shld  %%eax,%1;"
                  "movl %%eax,%%edx;"
                  "shld  %%eax,%1;"
                  "addl  %%ebx,%%eax;"
                  "addl  %%edx,%%eax;"
                  : "=r" (multiplied_by_hundred)
                  : "a" (multiply_by_hundred)
                  : "%%eax", "%%ebx", "%%edx"
    );

    return multiplied_by_hundred;
}
int main()
{
    cout<<times_hundred(1)<<endl;
    cout<<times_ten(1)<<endl;
    cout<<times_hundred(1)<<endl;

    return 0;
}

|In function 'int times_ten(int)':|
error: unknown register name '%%ebx' in 'asm'|
error: unknown register name '%%eax' in 'asm'|
In function 'int times_hundred(int)':|
error: unknown register name '%%edx' in 'asm'|
error: unknown register name '%%ebx' in 'asm'|
error: unknown register name '%%eax' in 'asm'|
In function 'int main()':|
error: unknown register name '%%edx' in 'asm'|
error: unknown register name '%%ebx' in 'asm'|
error: unknown register name '%%eax' in 'asm'|
error: unknown register name '%%ebx' in 'asm'|
error: unknown register name '%%eax' in 'asm'|
error: unknown register name '%%edx' in 'asm'|
error: unknown register name '%%ebx' in 'asm'|
error: unknown register name '%%eax' in 'asm'|
||=== Build finished: 13 errors, 0 warnings ===|
8
  • You probably need eax, abx, edx in your clobber list. Commented Jul 10, 2011 at 11:10
  • I tried that but then it wont compile. Commented Jul 10, 2011 at 11:11
  • What do you mean by "won't compile" ? Post the actual code and the actual error message(s). Commented Jul 10, 2011 at 11:11
  • 1
    You do know that gcc is really good at doing that kind of optimization (including division by reciprocal multiplication) using normal C operators and -O2, right? And that is without being bound to a particular register. So the reason why you write this assembler routine is probably for educational purpose? In any case you will want to get rid of things like %%eax in favour of a r() constraint, if performance is of any importance. You otherwise needlessly hinder the compiler in its register allocation. Commented Jul 10, 2011 at 11:46
  • 1
    %%eax is hardcoding a particular register. You can bind some variable to =r() as you have done, but you can also bind inputs to r() and allocate any locals that you need that way. You can refer to registers e.g. with %0, %1 etc (or by bind names), which uses the registers that the compiler deems best in its allocation strategy, rather than enforcing a particular register, which most likely forces the compiler to generate extra moves. Commented Jul 10, 2011 at 13:32

2 Answers 2

1

After you've fixed the %% clobber problem, change the output register:

...
"addl  %%edx,%%eax;"
              : "=a" (multiplied_by_hundred)
              : "a" (multiply_by_hundred)
              : "%eax", "%ebx", "%edx"

from "=r" to "=a". Edit: This works with clang, but not gcc. Sorry.

Sign up to request clarification or add additional context in comments.

1 Comment

what do the two letters mean... r and a?
0

This code works now.

#include <iostream> 

using namespace std; 

int times_ten(int multiply_by_ten) 
{ 
         int multiplied_by_ten = 0; 
         //this multiplies by 10 
         __asm__("shl   $1, %%eax;" 
                                   "movl %%eax,%%ebx;" 
                                   "shl  $2, %%eax;" 
                                   "addl  %%ebx,%%eax;" 
                                   : "=a" (multiplied_by_ten) 
                                   : "0" (multiply_by_ten) : "%ebx" 
         ); 

         return multiplied_by_ten; 
} 
int times_hundred(int multiply_by_hundred) 
{ 
         int multiplied_by_hundred = 0; 
         //this multiplies by 100 
         __asm__("shl   $2, %%eax;" 
                                   "movl %%eax,%%ebx;" 
                                   "shl  $3, %%eax;" 
                                   "movl %%eax,%%edx;" 
                                   "shl  $1, %%eax;" 
                                   "addl  %%ebx,%%eax;" 
                                   "addl  %%edx,%%eax;" 
                                   : "=a" (multiplied_by_hundred) 
                                   : "0" (multiply_by_hundred) : "%ebx","%edx" 

         ); 

         return multiplied_by_hundred; 
} 
int main() 
{ 
         cout<<times_hundred(1)<<endl; 
         cout<<times_ten(1)<<endl; 
         cout<<times_hundred(1)<<endl; 

     return 0; 
} 

1 Comment

As the comments above say, you should leave it to the compiler to select registers.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.