c++clangarm64floating-point-conversion

Casting float to int with wrap-around on aarch64/arm64


I'm trying to match the behavior exactly between an application running on both x86_64 and aarch64/arm64. However, they differ in how they cast a floating point number to an integer when it's outside of the possible range of integers.

Consider the following example:

#include <stdio.h>
#include <cstdint>

void cast(float value) {
  printf("uint32_t(%.2f) = %u\n", value, uint32_t(value));
}

int main() {
  cast(4294967808.);
}

# output on x86_64:  uint32_t(4294967808.00) = 512
# output on aarch64: uint32_t(4294967808.00) = 4294967295

The x86_64 version is using cvttss2si for the conversion, which wraps-around the answer, although the documentation is quite unclear on this. Aarch64 is using fcvtzu which is saturating.

Any solution to align the two would be interesting, but ideally I'd like to set a compiler flag on clang to have the aarch64 version behave like the x86_64 one (even though the aarch64 is "nicer")


Solution

  • Use the CPU instruction fjcvtzs (or the intrinsic __builtin_arm_jcvt) to get behavior of x86 on aarch64.

    (Thanks to @EOF for providing enough information in a comment for me to find the answer)