Skip to content

em: Wrong value conversion #637

@luismgsilva

Description

@luismgsilva

This issue was identified during the testing validation for the 2024.06 release, specifically occurring with the em CPU (-mcpu=em).

original test case

The test case has been reduced. It checks the correctness of type conversions between integers and floating-point numbers. The critical part involves converting a maximum negative value from an integer to a floating-point number and back, ensuring the value remains unchanged.

$ cat test.c
#include <stdlib.h>

int
main (void)
{
  static volatile signed long long ivin, ivout;
  static volatile double fv1, fv2;

  ivin = ((signed long long)(unsigned long long)~(unsigned long long)0);
  fv1 = ((signed long long)(unsigned long long)~(unsigned long long)0);

  fv2 = ivin;

  ivout = fv2;
  if ((1) && ivout != ivin)
    abort();

  exit (0);
}
$ arc-elf32-gcc \
        -fdiagnostics-plain-output  \
        --specs=hl.specs            \
        -mcpu=em                    \
        -O0                         \
        test.c                      \
        -lm -o ./test.x
$ nsimdrv \
        -on nsim_isa_enable_timer_0         \
        -on nsim_isa_enable_timer_1         \
        -off invalid_instruction_interrupt  \
        -off memory_exception_interrupt     \
        -on nsim_download_elf_sections      \
        -prop=nsim_hlink_gnu_io_ext=1       \
        -p nsim_isa_family=av2em            \
        -p nsim_isa_core=3                  \
        -on nsim_isa_sat                    \
        -p nsim_isa_shift_option=0          \
        -p nsim_isa_bitscan_option=0        \
        ./test.x
$ echo $?
6
ivin = ((signed long long)(unsigned long long)~(unsigned long long)0);
fv1 = ((signed long long)(unsigned long long)~(unsigned long long)0);
  • The expression (unsigned long long)~(unsigned long long)0 results in the maximum unsigned long long value, 0xFFFFFFFF.
  • Casting this to a signed long long gives -1 because of two's complement representation.
  • Both ivin and fv1 are assigned this value, so both hold -1.
fv2 = ivin;
  • Assigning ivin (which is -1) to fv2, a double, should theoretically result in -1.0.
  • However, fv2 holds -0.9999999962747097.
ivout = fv2;
  • Converting fv2 (holding -0.9999999962747097) back to an integer results in 0. This is because when a floating-point number between -1.0 and 0.0 is converted to an integer, it truncates towards zero.
if ((1) && ivout != ivin)
  abort();
  • With that said, ivout is 0 and ivin is -1, so the condition ivout != ivin is true, resulting in a call to abort() with a non-zero exit status 6.

Note: According to Jenkins results from the last release (arc-2023.09), this test case passes. However, I was unable to reproduce the passing result. The expected behavior was compared to arc600.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions