Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

> The way the x87 FP stack works is a bit weird, and these days it’s better to do floating-point arithmetic using xmm registers

x87 allows to do calculations in extended precision, i.e. word width is 80 bits. SSE is limited to double precision (64-bit words). Also FPU has some advanced math instructions, like sin, cos, tan, exp, etc., and these operations will be available in AVX512F.



Have fun debugging arithmetic difference resulting from spilling an intermediate result to memory and rounding to 64bit value vs. not spilling and keeping the intermediate value as 80 bits.


FST/FLD can store/load full 80 bits if you need such precision. No problem whatsoever.


I've never seen anyone store 10 byte IEEE-754 values in memory.

People store doubles, and people get upset when compiler optimizations (like when to spill from registers to memory and whether to use one or two instructions for multiply-and-add) change not just the performance but also the result of computations.


> I've never seen anyone store 10 byte IEEE-754 values in memory.

But you can, if you are after precision as the OP apparently was.

I'm not sure what this c-word is doing in your post, I thought we were talking assembly, but as far as c-things go, at least gcc and clang represent long double as 80b extended precision on x86.

So, for example, compiling this beauty (which is too large for x87 stack):

        long double a[64], b[64], c[64], d[64];
        // load a,b,c,d from somewhere

        long double x =
                ((((((((a[0]+a[1])+(a[2]+a[3]))+((a[4]+a[5])+(a[6]+a[7])))
                +(((a[8]+a[9])+(a[10]+a[11]))+((a[12]+a[13])+(a[14]+a[15]))))
                +((((a[16]+a[17])+(a[18]+a[19]))+((a[20]+a[21])+(a[22]+a[23])))
                +(((a[24]+a[25])+(a[26]+a[27]))+((a[28]+a[29])+(a[30]+a[31])))))
                +(((((a[32]+a[33])+(a[34]+a[35]))+((a[36]+a[37])+(a[38]+a[39])))
                +(((a[40]+a[41])+(a[42]+a[43]))+((a[44]+a[45])+(a[46]+a[47]))))
                +((((a[48]+a[49])+(a[50]+a[51]))+((a[52]+a[53])+(a[54]+a[55])))
                +(((a[56]+a[57])+(a[58]+a[59]))+((a[60]+a[61])+(a[62]+a[63]))))))

                +((((((b[0]+b[1])+(b[2]+b[3]))+((b[4]+b[5])+(b[6]+b[7])))
                +(((b[8]+b[9])+(b[10]+b[11]))+((b[12]+b[13])+(b[14]+b[15]))))
                +((((b[16]+b[17])+(b[18]+b[19]))+((b[20]+b[21])+(b[22]+b[23])))
                +(((b[24]+b[25])+(b[26]+b[27]))+((b[28]+b[29])+(b[30]+b[31])))))
                +(((((b[32]+b[33])+(b[34]+b[35]))+((b[36]+b[37])+(b[38]+b[39])))
                +(((b[40]+b[41])+(b[42]+b[43]))+((b[44]+b[45])+(b[46]+b[47]))))
                +((((b[48]+b[49])+(b[50]+b[51]))+((b[52]+b[53])+(b[54]+b[55])))
                +(((b[56]+b[57])+(b[58]+b[59]))+((b[60]+b[61])+(b[62]+b[63])))))))

                +(((((((c[0]+c[1])+(c[2]+c[3]))+((c[4]+c[5])+(c[6]+c[7])))
                +(((c[8]+c[9])+(c[10]+c[11]))+((c[12]+c[13])+(c[14]+c[15]))))
                +((((c[16]+c[17])+(c[18]+c[19]))+((c[20]+c[21])+(c[22]+c[23])))
                +(((c[24]+c[25])+(c[26]+c[27]))+((c[28]+c[29])+(c[30]+c[31])))))
                +(((((c[32]+c[33])+(c[34]+c[35]))+((c[36]+c[37])+(c[38]+c[39])))
                +(((c[40]+c[41])+(c[42]+c[43]))+((c[44]+c[45])+(c[46]+c[47]))))
                +((((c[48]+c[49])+(c[50]+c[51]))+((c[52]+c[53])+(c[54]+c[55])))
                +(((c[56]+c[57])+(c[58]+c[59]))+((c[60]+c[61])+(c[62]+c[63]))))))

                +((((((d[0]+d[1])+(d[2]+d[3]))+((d[4]+d[5])+(d[6]+d[7])))
                +(((d[8]+d[9])+(d[10]+d[11]))+((d[12]+d[13])+(d[14]+d[15]))))
                +((((d[16]+d[17])+(d[18]+d[19]))+((d[20]+d[21])+(d[22]+d[23])))
                +(((d[24]+d[25])+(d[26]+d[27]))+((d[28]+d[29])+(d[30]+d[31])))))
                +(((((d[32]+d[33])+(d[34]+d[35]))+((d[36]+d[37])+(d[38]+d[39])))
                +(((d[40]+d[41])+(d[42]+d[43]))+((d[44]+d[45])+(d[46]+d[47]))))
                +((((d[48]+d[49])+(d[50]+d[51]))+((d[52]+d[53])+(d[54]+d[55])))
                +(((d[56]+d[57])+(d[58]+d[59]))+((d[60]+d[61])+(d[62]+d[63]))))))))
                ;
produces only 80b spills (fstpt in GNU syntax):

  $ objdump -d fpmonster |grep fst
  400457:       db 7c 1c 10             fstpt  0x10(%rsp,%rbx,1)
  400462:       db bc 1c 10 04 00 00    fstpt  0x410(%rsp,%rbx,1)
  400470:       db bc 1c 10 08 00 00    fstpt  0x810(%rsp,%rbx,1)
  40047e:       db bc 1c 10 0c 00 00    fstpt  0xc10(%rsp,%rbx,1)
  400b47:       db 7c 24 10             fstpt  0x10(%rsp)
  400d91:       db 3c 24                fstpt  (%rsp)
Clearly, extended precision can be done right both in C and raw assembly.

> People store doubles, and people get upset

That's their fault :) and another story altogether. For reproducible low precision, indeed SSE is the way to go.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: