Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions share/revng/test/configuration/revng-qa/for-floating-point.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#
# This file is distributed under the MIT License. See LICENSE.md for details.
#

tags:
- name: for-floating-point

# We force VFPv3 with hardfloat calling convention on armv7a, in order to
# avoid the toolchain emitting calls to the libgcc helpers for double
# precision FP.
- name: arm-double-vfp
variables:
GCC_CFLAGS:
- -mfpu=vfpv3
- -mfloat-abi=hard

# We force `mips2` in order to use the `trunc.w.d` / `trunc.w.s` single opcode
# to round toward zero, and discard the use of `FCSR`.
- name: mips-mips2
variables:
GCC_CFLAGS:
- -mips2

sources:
- tags: [simple-executable, static, nostdlib, nostartfiles, for-floating-point]
repeat-for:
- [arm, arm-double-vfp]
- [mips, mips-mips2]
- [mipsel, mips-mips2]
- [x86-64]
- [s390x]
- [i386]
- [aarch64]
prefix: share/revng/test/tests/floating-point
members:
- floating-point.c
152 changes: 152 additions & 0 deletions share/revng/test/tests/floating-point/floating-point.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
/*
* This file is distributed under the MIT License. See LICENSE.md for details.
*
*
* Where the simple form `(int)((double)a OP (double)b)` would let the
* compiler constant-fold the FP work back to integer arithmetic
* at -O2, we add a `+ 0.5` (or `+ 0.5f`).
*
*/

__attribute__((weak)) int add64(int a, int b) {
// CHECK-LABEL: @add64(
// CHECK: @float64_add(
return (int)((double)a + (double)b + 0.5);
// CHECK-NOT: call{{.*}}@float[0-9]+_{{(mul|div|sub|sqrt|rem)}}(
}

__attribute__((weak)) int add32(int a, int b) {
// CHECK-LABEL: @add32(
// CHECK: @float32_add(
return (int)((float)a + (float)b + 0.5f);
// CHECK-NOT: call{{.*}}@float[0-9]+_{{(mul|div|sub|sqrt|rem)}}(
}

__attribute__((weak)) int mul64(int a, int b) {
// CHECK-LABEL: @mul64(
// CHECK: @float64_mul(
return (int)((double)a * (double)b);
// CHECK-NOT: call{{.*}}@float[0-9]+_{{(add|div|sub|sqrt|rem)}}(
}

__attribute__((weak)) int mul32(int a, int b) {
// CHECK-LABEL: @mul32(
// CHECK: @float32_mul(
return (int)((float)a * (float)b);
// CHECK-NOT: call{{.*}}@float[0-9]+_{{(add|div|sub|sqrt|rem)}}(
}

__attribute__((weak)) int div64(int a, int b) {
// CHECK-LABEL: @div64(
// CHECK: @float64_div(
return (int)((double)a / (double)b);
// CHECK-NOT: call{{.*}}@float[0-9]+_{{(add|mul|sub|sqrt|rem)}}(
}

__attribute__((weak)) int div32(int a, int b) {
// CHECK-LABEL: @div32(
// CHECK: @float32_div(
return (int)((float)a / (float)b);
// CHECK-NOT: call{{.*}}@float[0-9]+_{{(add|mul|sub|sqrt|rem)}}(
}

__attribute__((weak)) int cmp64(int a, int b) {
// CHECK-LABEL: @cmp64(
// CHECK: @float64_{{(compare|lt)}}{{(_quiet)?}}(
return (double)a + 0.5 > (double)b;
// CHECK-NOT: call{{.*}}@float[0-9]+_{{(mul|div|sub|sqrt|rem)}}(
}

__attribute__((weak)) int cmp32(int a, int b) {
// CHECK-LABEL: @cmp32(
// CHECK: @float32_{{(compare|lt)}}{{(_quiet)?}}(
return (float)a + 0.5f > (float)b;
// CHECK-NOT: call{{.*}}@float[0-9]+_{{(mul|div|sub|sqrt|rem)}}(
}

__attribute__((weak)) int conv_i32_to_f64(int a) {
// CHECK-LABEL: @conv_i32_to_f64(
// CHECK: @{{int(32|64)}}_to_float64{{(_scalbn)?}}(
return (int)((double)a + 0.5);
// CHECK-NOT: call{{.*}}@float[0-9]+_{{(mul|div|sub|sqrt|rem)}}(
}

__attribute__((weak)) int conv_f64_to_i32(int a) {
// CHECK-LABEL: @conv_f64_to_i32(
// CHECK: @float64_to_int32{{(_scalbn|_round_to_zero)?}}(
return (int)((double)a + 0.5);
// CHECK-NOT: call{{.*}}@float[0-9]+_{{(mul|div|sub|sqrt|rem)}}(
}

__attribute__((weak)) int conv_i32_to_f32(int a) {
// CHECK-LABEL: @conv_i32_to_f32(
// CHECK: @{{int(32|64)}}_to_float32{{(_scalbn)?}}(
return (int)((float)a + 0.5f);
// CHECK-NOT: call{{.*}}@float[0-9]+_{{(mul|div|sub|sqrt|rem)}}(
}

__attribute__((weak)) int conv_f32_to_i32(int a) {
// CHECK-LABEL: @conv_f32_to_i32(
// CHECK: @float32_to_int32{{(_scalbn|_round_to_zero)?}}(
return (int)((float)a + 0.5f);
// CHECK-NOT: call{{.*}}@float[0-9]+_{{(mul|div|sub|sqrt|rem)}}(
}

/*
* We avoid emitting the tests for `i64` conversions on 32-bit architecture.
* The compiler emits calls to libgcc helpers leading back to 32-bit FP
* primiteves.
* We make use of the `CHECK-64` prefix to activate these checks.
*/
#if defined(__SIZEOF_POINTER__) && __SIZEOF_POINTER__ == 8

__attribute__((weak)) long long conv_i64_to_f64(long long a) {
// CHECK-64-LABEL: @conv_i64_to_f64(
// CHECK-64: @int64_to_float64{{(_scalbn)?}}(
return (long long)((double)a + 0.5);
// CHECK-64-NOT: call{{.*}}@float[0-9]+_{{(mul|div|sub|sqrt|rem)}}(
}

__attribute__((weak)) long long conv_f64_to_i64(long long a) {
// CHECK-64-LABEL: @conv_f64_to_i64(
// CHECK-64: @float64_to_int64{{(_scalbn|_round_to_zero)?}}(
return (long long)((double)a + 0.5);
// CHECK-64-NOT: call{{.*}}@float[0-9]+_{{(mul|div|sub|sqrt|rem)}}(
}

__attribute__((weak)) long long conv_i64_to_f32(long long a) {
// CHECK-64-LABEL: @conv_i64_to_f32(
// CHECK-64: @int64_to_float32{{(_scalbn)?}}(
return (long long)((float)a + 0.5f);
// CHECK-64-NOT: call{{.*}}@float[0-9]+_{{(mul|div|sub|sqrt|rem)}}(
}

__attribute__((weak)) long long conv_f32_to_i64(long long a) {
// CHECK-64-LABEL: @conv_f32_to_i64(
// CHECK-64: @float32_to_int64{{(_scalbn|_round_to_zero)?}}(
return (long long)((float)a + 0.5f);
// CHECK-64-NOT: call{{.*}}@float[0-9]+_{{(mul|div|sub|sqrt|rem)}}(
}

#endif

void _start(void) {
add64(1, 2);
add32(1, 2);
mul64(1, 2);
mul32(1, 2);
div64(1, 2);
div32(1, 2);
cmp64(1, 2);
cmp32(1, 2);
conv_i32_to_f64(1);
conv_f64_to_i32(1);
conv_i32_to_f32(1);
conv_f32_to_i32(1);
#if defined(__SIZEOF_POINTER__) && __SIZEOF_POINTER__ == 8
conv_i64_to_f64(1);
conv_f64_to_i64(1);
conv_i64_to_f32(1);
conv_f32_to_i64(1);
#endif
}