0

So recently we learned about floating point operations and got a few questions as a homework.
One of those is:

"Write down the calling convention of single precision floats!".

So i know about the xmm registers and know that on double precision the first input goes into xmm0 and so on.
I looked up the topic on Google but couldn't find the answer. Would be nice if someone could help me on this question.

Macmade
  • 52,708
  • 13
  • 106
  • 123
  • 3
    `nasm` is an assembler, it doesn't define the calling convention. That's defined by the relevant ABI for your environment, that you didn't say. For linux and mac, look at the [SysV document](http://stackoverflow.com/questions/18133812/where-is-the-x86-64-abi-documented), for windows look at [msdn](https://msdn.microsoft.com/en-us/library/zthk2dkh.aspx). – Jester Dec 01 '16 at 17:15
  • Calling convention / ABI doc links in the [x86 tag wiki](http://stackoverflow.com/tags/x86/info). Oh, that's what my answer on the linked question already says... hadn't checked to see what Jester linked :P – Peter Cordes Dec 01 '16 at 17:22
  • 1
    The question is broken because it assumes that there is such thing as *"the"* calling convention. There is not. The asker should have been more specific about *which* calling convention they were referring to. Each of them have different rules. Once you know the calling convention that is being referred to, you can easily look it up. – Cody Gray - on strike Dec 02 '16 at 14:18

1 Answers1

1

Every calling convention I'm familiar with handles single float the same as it does double. (Not that all calling conventions handle them the same, just that within one calling convention there's no diff).

Some (like i386 System V) pass on the stack and return in x87 st(0).

float foo(float x) { return 2.0f*x; }

; NASM implementation for i386 System V, or Windows cdecl
foo:
     fld    dword [esp+4]         ; arg from the stack, above the return address
     fadd   st0                   ; st0 += st0
     ret                          ; return value = st0

Some pass / return in XMM registers. (e.g. x86-64 System V passes the first 8 FP args in xmm0..7, and an FP return value is returned in xmm0. The upper bytes of those XMM registers isn't guaranteed to be zero, but there are scalar instructions like sqrtsd that only operate on the low element.)

; x86-64 System V, and Windows x64
foo:
    addss   xmm0, xmm0    ; xmm0 += xmm0, scalar single-precision
    ret                   ; returns in xmm0

(See the compiler-generated GAS .intel_syntax noprefix versions of these on Godbolt.)

Windows calling conventions are similar but different. See links to ABI docs in the tag wiki. (e.g. Windows x64 passes the 3rd arg in xmm3, even if it's the first FP arg and the earlier args were integer).


Note that C rules for variadic functions like printf mean that float args are promoted to double by the caller. Why does printf() promote a float to a double?. There is no % conversion for single-precision, only double or long double. How to print a single-precision float with printf (in asm).


Note that in 32-bit calling conventions that pass doubles in memory on the call-stack, they take twice as much space as integers / pointers / floats. So a double takes up two stack slots.

It may also have an 8B alignment requirement leading to padding. But they're still not "special" because of this: any other 8B object with an 8B alignment requirement (e.g. a struct with an alignas(8) member) would be treated the same, I think.

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
  • 1
    The only case I can think of where float and double might be treated differently is if you had a register-based calling convention for SSE (which only supports 32-bit floats), but had to fall back to the x87 stack for 64-bit doubles. But I don't think such a register-based calling convention exists. __vectorcall requires SSE2 support. – Cody Gray - on strike Dec 02 '16 at 14:16