-2

In my C program, I would like to do the following in extended assembler: Divide two floating point numbers (variables), 'numerator' by 'denominator', and put the result in another variable, 'result'. This is my guess of how it would look like, but it does not seem to compile.

float result, numerator, denominator;

asm volatile(" fdiv %2, %1 "
           : "=r" (result)
           : "1"  (numerator), "2"  (denominator));

Compiling errors:

example_program.c:66:16: error: matching constraint references invalid operand number
                : "1"  (numerator), "2"  (denominator));

example_program:16: error: matching constraint references invalid operand number

example_program.c:64:3: error: matching constraint references invalid operand number
   asm volatile(" fdiv %2, %1 "
   ^
example_program.c:64:3: error: matching constraint references invalid operand number
make: *** [<builtin>: example_program] Error 1
mch
  • 9,424
  • 2
  • 28
  • 42
LukesDiner
  • 145
  • 8
  • That's not what numeric constraints like `"1"` mean, they're matching constraints, and you only have one non-numbered constraint. Which specifies a general-purpose (integer) register, not an x87 FP register. And your inline asm doesn't reference it (`%0`). Instead of taking wild guesses, read a tutorial and/or google for "x87 inline assembly" to find examples like [Operand type mismatch in x87 inline assembly in a Linux kernel module](https://stackoverflow.com/q/35280254) for `fsqrt` on one operand. – Peter Cordes Feb 23 '22 at 11:39
  • Also, x87 instructions can't take two arbitrary x87 registers; x87 is a register-stack machine where one operand (source or destination) always has to be the top-of-stack. http://www.ray.masmcode.com/tutorial/index.html / https://www.felixcloutier.com/x86/fdiv:fdivp:fidiv – Peter Cordes Feb 23 '22 at 12:38

1 Answers1

1

Before doing any inline assembly programming, read the documentation carefully. Gcc-style inline assembly is complicated and easy to get wrong. If you get it wrong, there is often no error. Instead, wrong code will silently be produced. So make sure you understand exactly what you are doing. In your case, you should especially focus on §6.47.2.9.

Reading this documentation, the following code seems correct:

float test(float numerator, float denominator)
{
    float result;

    asm ("fdiv%Z2 %2" : "=t"(result) : "0"(numerator), "fm"(denominator));

    return result;
}

This permits the source operand to be a memory operand. If that is not required, the statement can be simpler:

asm ("fdiv %2" : "=t"(result) : "0"(numerator), "f"(denominator));

If instead of writing the result into a different variable, the numerator is to be overwritten, the code can be even simpler.

asm ("fdiv %1" : "+t"(result) : "f"(denominator));
fuz
  • 88,405
  • 25
  • 200
  • 352