Static Values in Assembler Code

Viewed 318

I have the following simple code:

#include <cmath>
struct init_sin
{
    typedef double type;
    static constexpr type value(int index) {
        return 3*std::pow(std::sin(index * 2.0 * 3.1415 / 20.0),1.999);
    }
};

int main(){
    static double VALUE = init_sin::value(10);

    double VALUE_NONSTAT = 3*std::pow(std::sin(10 * 2.0 * 3.1415 / 20.0),1.999);

    return int(VALUE_NONSTAT);
}

I would like to find out what the meaning of the assembler code is of this given piece. Here the link to the assembly: http://pastebin.com/211AfSYh
I thought that VALUE is compile time computed and directly as value in the assembler code Which should be in this line if I am not mistaken:

33                      .size   main, .-main
  34                    .data
  35                    .align 8
  36                    .type   _ZZ4mainE5VALUE, @object
GAS LISTING /tmp/ccbPDNK8.s             page 2


  37                    .size   _ZZ4mainE5VALUE, 8
  38                _ZZ4mainE5VALUE:
  39 0000 15143B78      .long   2017137685
  40 0004 45E95B3E      .long   1046210885
  1. Why are there two values with .long ? And why are the types long? (its a double?, maybe in assembler there is only long.
  2. Does that mean that the value of VALUE was compile time generated
  3. Where is the result for VALUE_NON_STATIC? This should be computed during run-time right? I cannot quite see where?

Thanks a lot!

1 Answers

.long in this assembler syntax implies a 32-bit number. Because a double is 64-bits, what you're seeing there is the two 32-bit parts of VALUE, in their double representation. You'll also notice above it that it's being aligned to an 8-byte boundary (through the .align statement) and that it's size is 8 (through the .size statement). Also, it's in the main .data segment, which is typically used for global-scope variables which are not initialised to zero (as a side-note, .bss is typically used to zero-initialised global scope variables).

The VALUE_NONSTAT can be seen being loaded into %rax here, which is the 64-bit version of the AX register:

             V
 20 0004 48B81514              movabsq $4493441537811354645, %rax
 20      3B7845E9
 20      5B3E

Recalling that 15143B7845E95B3E is the representation of the value of 3*std::pow(std::sin(index * 2.0 * 3.1415 / 20.0),1.999) when stored in a double, you can see the internal value in hex starting around where I inserted a V.

Later statements then push it onto the stack (movq %rax, -8(%rbp)), then load it into an FP register (movsd -8(%rbp), %xmm0) before converting it to an integer and storing it in %eax, which is the register for return values (cvttsd2si %xmm0, %eax) and then returning from the routine, using ret.

In any case, at the optimisation level you're using (and probably below), your compiler has figured out that VALUE_NONSTAT is a constant expression, and just inlined it at compile time instead, since the value is fully known at compile time.

Related