Q:

Reading assembly comparing multiplication vs division

I am trying to see if in our compilation there is a gain between writing 
x/3.0

versus 
    const double one_over_three = 1.0/3.0;
    x * one_over_three;
But I need a bit of help reading assembly, which I haven't learned. 
I compiled 
int div3(double x) {
  const double three = 1/3.0;
  return x*three;
}

and obtained 
    div3(double):
    pushq   %rbp
    movq    %rsp, %rbp
    movsd   %xmm0, -24(%rbp)
    movabsq $4599676419421066581, %rax
    movq    %rax, -8(%rbp)
    movsd   -24(%rbp), %xmm1
    movsd   .LC0(%rip), %xmm0
    mulsd   %xmm1, %xmm0
    cvttsd2si       %xmm0, %eax
    popq    %rbp
    ret
    .LC0:
    .long   1431655765
    .long   1070945621

Then compiled 
int div3(double x) {
  return x/3.0;
}

and obtained 
    div3(double):
    pushq   %rbp
    movq    %rsp, %rbp
    movsd   %xmm0, -8(%rbp)
    movsd   -8(%rbp), %xmm0
    movsd   .LC0(%rip), %xmm1
    divsd   %xmm1, %xmm0
    cvttsd2si       %xmm0, %eax
    popq    %rbp
    ret
    .LC0:
    .long   0
    .long   1074266112

Q1: Could someone kindly help me read the assembly?
Q2: What is the meaning of those two last lines in each of the codes?

A:

If this is how you are doing optimizations, you are doing it wrong. I am sorry, I don't usually use negative terms when explaining something, but you are on a wrong path.
What you are doing is called premature optimization and micro-optimization. You are trying to optimize something you don't know it needs optimizing. First, and this is a deal breaker: use compiler optimizations. And then you would normally profile and try to optimize the hot spots.

Lets see how relevant the optimization you are trying to do is:
I firstly compile with -O3 (gcc 6.1): Let's see the output (also on the Godbolt compiler explorer):
mul_inverse3(double):
        mulsd   .LC0(%rip), %xmm0
        cvttsd2si       %xmm0, %eax
        ret

div3(double):
        divsd   .LC1(%rip), %xmm0
        cvttsd2si       %xmm0, %eax
        ret

where .LCO and .LC1 are the constants: the nearest double to 1/3.0, and 3.0:
.LC0:
        .long   1431655765
        .long   1070945621
.LC1:
        .long   0
        .long   1074266112

Ok so you already see how much the compiler can do on it's own.  This is what you should have been looking at, not the noisy -O0 output.
Which one is faster? As a rule of thumb multiplication is faster than division on all CPUs.  The ratio depends on the specific microarchitecture.  For x86, see Agner Fog's instruction tables and microarch pdf, and other perf links in the x86 tag wiki.  For example, ~3x the latency and ~1/12th the throughput on Intel Sandybridge.  And still, div might not even be the bottleneck, so div vs. mul might not affect the total performance.  Cache misses, other pipelines stalls, or even other things like IO could hide the difference entirely.

But they are still different. Can we obtain the same code from the compiler? Yes! Add -ffast-math. With this option, the compiler can rearrange/change floating operations even if it changes slightly the result (which is what you are trying to do by hand). Be careful though as this applies to the whole program.
mul_inverse3(double):
        mulsd   .LC0(%rip), %xmm0
        cvttsd2si       %xmm0, %eax
        ret

div3(double):
        mulsd   .LC0(%rip), %xmm0
        cvttsd2si       %xmm0, %eax
        ret

Can we do more? Yes: add -march=native and search the compiler documentation for more switches.
So that was the first lesson: Let the compiler do it's optimizations first!

Here comes the second:
You spend 1 week trying to optimize a random operations. You finally do it! After a week of hard work and sleepless nights you make that operation 10 times faster (wow! congratulations). Then you run your program and see that the program is only 1% faster. The horror! How can this be possible? Well if your program spends only 1% of it's time doing that operation, then... you get the point. Or there can be other mechanisms underneath like OS optimizations, CPU pipeline etc. that make an operation repeated 100 times to consume much much less than 100 times more. What you need to do is profile first! Find the hot loops and optimize those! Optimize the the loop/function the program spends 60% of it's time.
More importantly, look for high level optimizations so your code can do less work, instead of just doing the same work faster.

A:

The .longs are simply the constants you supplied in the functions 1/3rd and 3. 3.0 in double is 0x4008000000000000 when broken into 32 bit chunks you get one of them zero the other 0x40080000 which in decimal is 1074266112. All they are doing there is pre-computing the constants and loading them into registers to perform the math requested by the code.  Why use .longs and decimal?  Well they have to choose something in order to generate the bit patterns they wanted, it could have been an array of bytes or whatever.  And decimal vs hex, most folks even programmers think in decimal so they pick one.
Same goes for the other constant 1/3rd which is roughly 0x3FD5555555555555 which becomes 1431655765 1070945621. Granted being float you might see some rounding differences if you compute this yourself
If you optimize you will reduce the amount of asm you have to figure out
int div3(double x) {
  return x/3.0;
}

and of course dramatically changes your performance
0000000000000000 <div3>:
   0:   f2 0f 5e 05 00 00 00    divsd  0x0(%rip),%xmm0        # 8 <div3+0x8>
   7:   00 
   8:   f2 0f 2c c0             cvttsd2si %xmm0,%eax
   c:   c3                      retq   

Disassembly of section .rodata.cst8:

0000000000000000 <.LC0>:
   0:   00 00                   add    %al,(%rax)
   2:   00 00                   add    %al,(%rax)
   4:   00 00                   add    %al,(%rax)
   6:   08                      .byte 0x8
   7:   40                      rex

this is not linked.  note there is our constant in a different form.
int div3(double x) {
  const double three = 1/3.0;
  return x*three;
}

0000000000000000 <div3>:
   0:   f2 0f 59 05 00 00 00    mulsd  0x0(%rip),%xmm0        # 8 <div3+0x8>
   7:   00 
   8:   f2 0f 2c c0             cvttsd2si %xmm0,%eax
   c:   c3                      retq   

Disassembly of section .rodata.cst8:

0000000000000000 <.LC0>:
   0:   55                      push   %rbp
   1:   55                      push   %rbp
   2:   55                      push   %rbp
   3:   55                      push   %rbp
   4:   55                      push   %rbp
   5:   55                      push   %rbp
   6:   d5                      (bad)  
   7:   3f                      (bad)  

And I assume you understand being floating point, even with double, there is no reason to expect the same result from these two functions.

