Bug 319393

Summary: bad rounding in cvtsi2ss instruction
Product: [Developer tools] valgrind Reporter: chzchzchz
Component: vexAssignee: Julian Seward <jseward>
Status: REPORTED ---    
Severity: normal CC: jackrabbit, pjfloyd
Priority: NOR    
Version: 3.8.0   
Target Milestone: ---   
Platform: Other   
OS: Linux   
Latest Commit: Version Fixed In:

Description chzchzchz 2013-05-06 05:01:22 UTC
libvex translates cvtsi2ss into an I64StoF64, followed by an F64toF32. In some cases, this leads to loss of precision which diverges from hardware results.

Here's a test case:

#include <stdio.h>
#include <stdint.h>

int main(void)
{
        uint64_t        rbx, rcx;

        rbx = 0x0100000100000001;
        __asm__ __volatile__(
                "cvtsi2ss       %%rbx,%%xmm2           \n"
                "movd           %%xmm2, %%rcx          \n"
        : "=c" (rcx) : "b" (rbx) : "%xmm2");

        printf("rcx: %lx\n", rcx);

        return 0;
}

Reproducible: Always

Steps to Reproduce:
1. compile test case
2. run on valgrind
3. run natively
Actual Results:  
Valgrind gives: "rcx: 5b800000"
Native gives: "rcx: 5b800001"


Expected Results:  
Valgrind should return "rcx: 5b800001".
Comment 1 Julian Seward 2013-07-02 16:07:56 UTC
I guess this happens because the value is rounded twice, as opposed
to once when running on real hardware.
Comment 2 jackrabbit 2019-09-10 21:11:00 UTC
Just ran into this myself, here is another repro where results differ when running under valgrind and not:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
  long a = 0x7fffff4000000001;
  float b = a;
  unsigned c;
  memcpy(&c, &b, sizeof(b));
  printf("%f %u\n", (double) b, c);
  return 0;
}