1
votes

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 ===|
2
You probably need eax, abx, edx in your clobber list.Paul R
I tried that but then it wont compile.pandoragami
What do you mean by "won't compile" ? Post the actual code and the actual error message(s).Paul R
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.Damon
%%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.Damon

2 Answers

1
votes

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.

0
votes

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