https://github.com/statham-arm created https://github.com/llvm/llvm-project/pull/179927
This commit adds a total of 8 new functions, all converting a floating-point number to an integer, varying in 3 independent choices: * input float format (32-bit or 64-bit) * output integer size (32-bit or 64-bit) * output integer type (signed or unsigned) >From 481231a3964c2d5cb4fb28ce3532549a441c7244 Mon Sep 17 00:00:00 2001 From: Simon Tatham <[email protected]> Date: Thu, 29 Jan 2026 16:14:09 +0000 Subject: [PATCH] [compiler-rt][ARM] Optimized FP -> integer conversions This commit adds a total of 8 new functions, all converting a floating-point number to an integer, varying in 3 independent choices: * input float format (32-bit or 64-bit) * output integer size (32-bit or 64-bit) * output integer type (signed or unsigned) --- compiler-rt/lib/builtins/CMakeLists.txt | 8 + compiler-rt/lib/builtins/arm/fixdfdi.S | 211 +++++++++++++++ compiler-rt/lib/builtins/arm/fixdfsi.S | 132 +++++++++ compiler-rt/lib/builtins/arm/fixsfdi.S | 137 ++++++++++ compiler-rt/lib/builtins/arm/fixsfsi.S | 98 +++++++ compiler-rt/lib/builtins/arm/fixunsdfdi.S | 159 +++++++++++ compiler-rt/lib/builtins/arm/fixunsdfsi.S | 129 +++++++++ compiler-rt/lib/builtins/arm/fixunssfdi.S | 103 +++++++ compiler-rt/lib/builtins/arm/fixunssfsi.S | 90 +++++++ .../test/builtins/Unit/fixdfdinew_test.c | 121 +++++++++ .../test/builtins/Unit/fixdfsinew_test.c | 96 +++++++ .../test/builtins/Unit/fixsfdinew_test.c | 100 +++++++ .../test/builtins/Unit/fixsfsinew_test.c | 99 +++++++ .../test/builtins/Unit/fixunsdfdinew_test.c | 96 +++++++ .../test/builtins/Unit/fixunsdfsinew_test.c | 251 ++++++++++++++++++ .../test/builtins/Unit/fixunssfdinew_test.c | 86 ++++++ .../test/builtins/Unit/fixunssfsinew_test.c | 85 ++++++ 17 files changed, 2001 insertions(+) create mode 100644 compiler-rt/lib/builtins/arm/fixdfdi.S create mode 100644 compiler-rt/lib/builtins/arm/fixdfsi.S create mode 100644 compiler-rt/lib/builtins/arm/fixsfdi.S create mode 100644 compiler-rt/lib/builtins/arm/fixsfsi.S create mode 100644 compiler-rt/lib/builtins/arm/fixunsdfdi.S create mode 100644 compiler-rt/lib/builtins/arm/fixunsdfsi.S create mode 100644 compiler-rt/lib/builtins/arm/fixunssfdi.S create mode 100644 compiler-rt/lib/builtins/arm/fixunssfsi.S create mode 100644 compiler-rt/test/builtins/Unit/fixdfdinew_test.c create mode 100644 compiler-rt/test/builtins/Unit/fixdfsinew_test.c create mode 100644 compiler-rt/test/builtins/Unit/fixsfdinew_test.c create mode 100644 compiler-rt/test/builtins/Unit/fixsfsinew_test.c create mode 100644 compiler-rt/test/builtins/Unit/fixunsdfdinew_test.c create mode 100644 compiler-rt/test/builtins/Unit/fixunsdfsinew_test.c create mode 100644 compiler-rt/test/builtins/Unit/fixunssfdinew_test.c create mode 100644 compiler-rt/test/builtins/Unit/fixunssfsinew_test.c diff --git a/compiler-rt/lib/builtins/CMakeLists.txt b/compiler-rt/lib/builtins/CMakeLists.txt index 6b392c8eb22f0..5cf754135908b 100644 --- a/compiler-rt/lib/builtins/CMakeLists.txt +++ b/compiler-rt/lib/builtins/CMakeLists.txt @@ -457,6 +457,14 @@ if(COMPILER_RT_ARM_OPTIMIZED_FP AND BUILTIN_SUPPORTED_ARCH MATCHES "arm") arm/unorddf2.S arm/unordsf2.S arm/extendsfdf2.S + arm/fixdfdi.S + arm/fixdfsi.S + arm/fixsfdi.S + arm/fixsfsi.S + arm/fixunsdfdi.S + arm/fixunsdfsi.S + arm/fixunssfdi.S + arm/fixunssfsi.S arm/truncdfsf2.S ) set_source_files_properties(${assembly_files} diff --git a/compiler-rt/lib/builtins/arm/fixdfdi.S b/compiler-rt/lib/builtins/arm/fixdfdi.S new file mode 100644 index 0000000000000..c93c3cc3d80a4 --- /dev/null +++ b/compiler-rt/lib/builtins/arm/fixdfdi.S @@ -0,0 +1,211 @@ +//===-- fixdfdi.S - double-precision FP to 64-bit signed int conversion ---===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements the __fixdfdi function (double precision floating point +// to 64-bit signed integer conversion), with the C rounding semantics +// (rounding towards zero), for the Arm and Thumb2 ISAs. +// +//===----------------------------------------------------------------------===// + +#include "../assembly.h" +#include "endian.h" + + .syntax unified + .text + .p2align 2 + +#if __ARM_PCS_VFP +DEFINE_COMPILERRT_FUNCTION(__fixdfdi) + push {r4, lr} + VMOV_FROM_DOUBLE(r0, r1, d0) + bl __aeabi_d2lz + pop {r4, pc} +#else +DEFINE_COMPILERRT_FUNCTION_ALIAS(__fixdfdi, __aeabi_d2lz) +#endif + +DEFINE_COMPILERRT_FUNCTION(__aeabi_d2lz) + + // The fast path: deliver an answer as quickly as possible for positive cases + // that don't overflow, and branch out of line to handle everything else more + // slowly, including negative numbers, overflows, and NaNs. + // + // The basic idea is to make a bare version of the mantissa, with its leading + // 1 bit explicit at the top of the word, and shift it right by an amount + // derived from the exponent. + + // Shift the exponent down to the bottom of the word. Using ASR here in place + // of LSR means the sign bit keeps its original value, and therefore as a + // side effect the N flag will tell us whether the input was negative. On the + // positive path the output is the same anyway. + asrs r2, xh, #20 + + // Make the 64-bit mantissa word, with its top half in r3 and the bottom half + // in r12, and set the leading mantissa bit at the top of r3. + // + // (In principle, the leading mantissa bit shouldn't be set at all if the + // input exponent is zero, because then the input is either 0 or a denormal. + // But since we're always rounding towards zero and not delivering any output + // indicating whether the result is inexact, it makes no difference - all + // denormals will round down to 0 anyway, and will still do so even if we + // imagine that their leading mantissa bit was set.) + lsl r3, xh, #11 // shift top word left to discard sign+exponent + orr r3, r3, xl, lsr #21 // combine with bits from bottom word + orr r3, r3, #1<<31 // set the leading bit + lsl r12, xl, #11 // shift bottom word left + + // Branch out of line for negative cases, using the N flag set by the ASRS at + // the start of the function. + // + // For 64-bit outputs it's difficult to handle both signs in a shared code + // path. Converting to a 32-bit integer you can finish up with an RSBMI to + // conditionally negate it, but negating a 64-bit number requires two + // instructions and clobbers the flags in between, so you can't + // conditionalize both instructions on the same prior state of the flags. + bmi LOCAL_LABEL(neg) + + // Convert the mantissa into a right shift count, indicating how many bits we + // want to shift the 64-bit mantissa in r3:r12 right by. + // + // If that's negative or zero, that means the input is too big, or the + // exponent is 0x7FF (so we might have a NaN), so branch out of line again. + // + // Another possibility is that if the number is very small, the right shift + // count might not fit in a byte, in which case the AArch32 shift semantics + // might do the wrong thing, since they only look at the low byte. + // + // To spot this efficiently, we do the conversion in two steps, arranged so + // that the first step detects massive underflow and the second detects + // overflow. We needed two steps anyway, because we need to subtract the + // input exponent from 0x43e (the exponent of input numbers between 2^63 and + // 2^64), and that value doesn't fit in an immediate field. So the first step + // subtracts 0x340, which makes r2 become negative if the exponent is very + // small; then the second step subtracts from 0xfe, giving 0xfe-(exp-0x340)) + // = 0x43e-exp. + // + // The input is tiny if r2 is negative after the first subtraction. In that + // situation we set r2 to 0 before the second step, treating all exponents + // smaller than 0x340 as if they had been 0x340. We do this by ASR+BIC, which + // avoids needing an IT instruction in Thumb. + sub r2, r2, #0x340 // first stage: r2 is negative for underflow + bic r2, r2, r2, asr #31 // if so, saturate by clearing all bits of r2 + rsbs r2, r2, #0xfe // second step: r2 is now the right shift count + ble LOCAL_LABEL(invalid) // if it was negative or zero, overflow + + // Make the top word of the result, which is the easy part: it's a + // shifted-right version of the top word of the mantissa, which will be zero + // if the shift count is 32 or more. + lsrs xh, r3, r2 + + // Make the bottom word of the result. If the shift count is less than 32, + // this will be (ml >> n) | (mh << (32-n)), where 'mh' and 'ml' denote the + // high and low words of the mantissa (in r3 and r12 respectively). Otherwise + // the whole high output word is zero, and the low mantissa word contributes + // nothing to the output, so we just need mh >> (n-32). + lsr xl, r12, r2 // start by setting it to ml >> n + rsbs r2, r2, #32 // compute 32-n, and find which case we're in +#if !__thumb__ + orrhi xl, xl, r3, lsl r2 // shift count < 32, so OR in ml << (32-n) +#else + // In Thumb we must separate the register-controlled shift and the OR into + // two instructions. + lslhi r3, r3, r2 + orrhi xl, xl, r3 +#endif + rsbls r2, r2, #0 // shift count > 32, so compute n-32 + lsrls xl, r3, r2 // replace xl with mh >> (n-32) + + // We're done: the result is already rounded towards zero. + bx lr + +LOCAL_LABEL(neg): + // Handle negative numbers. We come here with the mantissa already prepared + // in r3 and r12, and the exponent in the bottom 11 bits of r2 with all 1s + // above it (because it was shifted down via ASR and the sign bit was set). + // In other words, r2 = exponent - 0x800. + + // Convert the exponent into a shift count, exactly as on the positive path + // except that the initial subtraction of 0x340 is adjusted to cancel out the + // offset of 0x800 in r2, so that it becomes an addition. + add r2, r2, #0x800-0x340 // first stage: r2 is negative for underflow + bic r2, r2, r2, asr #31 // if so, saturate by clearing all bits of r2 + rsbs r2, r2, #0xfe // second step: r2 is now the right shift count + ble LOCAL_LABEL(invalid) // if it was negative or zero, overflow + + // Shift the mantissa down to create the absolute value of the result in + // xh:xl, exactly as on the positive path above. + lsrs xh, r3, r2 // make high word of mantissa + lsr xl, r12, r2 // initially set low word to ml >> n + rsbs r2, r2, #32 // compute 32-n, and find which case we're in +#if !__thumb__ + orrhi xl, xl, r3, lsl r2 // shift count < 32, so OR in ml << (32-n) +#else + // In Thumb we must separate the register-controlled shift and the OR into + // two instructions. + lslhi r3, r3, r2 + orrhi xl, xl, r3 +#endif + rsbls r2, r2, #0 // shift count > 32, so compute n-32 + lsrls xl, r3, r2 // and replace xl with mh >> that + + // All of that was almost exactly the same as the positive code path, but now + // we must negate the answer before returning it. + rsbs xl, xl, #0 // negate low word, setting carry flag +#if !__thumb__ + rsc xh, xh, #0 // negate high word +#else + // Thumb has no RSC, so substitute MVN + ADC. + mvn xh, xh + adc xh, xh, #0 +#endif + + // We're done. + bx lr + +LOCAL_LABEL(invalid): + // We come here if the exponent field of the number is large enough that it's + // either a NaN or infinity, or a finite number of absolute value at least + // 2^63. + // + // For out-of-range positive values, we return the maximum positive signed + // integer 0x7fffffffffffffff. For out-of-range negative values, we return + // the minimum negative signed integer 0x8000000000000000. For NaNs, we + // return zero. + // + // Not _every_ number of this kind is actually an invalid input. The exact + // value -2^63 is perfectly valid. If this implementation supported FP + // exceptions, we'd have to detect that one case and return + // 0x8000000000000000 with no exception, while raising an Invalid Operation + // exception for everything else. But since we don't support exceptions, we + // don't have to tell the difference here: -2^63 and negative overflows both + // return 0x8000000000000000, and it doesn't matter that one is the right + // answer and the other a best-effort error response. + + // Check for NaNs and branch out of line. + cmp xl, #1 // set C if any bit of xl is nonzero + adc r2, xh, xh // shift that bit into xh, discarding sign + cmn r2, #1 << 21 // then greater than 0xFFE00000 means NaN + bhi LOCAL_LABEL(nan) + + // The remaining case is a too-large exponent. Return either INT_MAX or + // INT_MIN depending on sign, using the fact that (xh ASR 31) is 0 for a + // positive input or 0xFFFFFFFF for a negative input, so it's exactly the + // bitwise inverse of the correct low word of the output. + mvn xl, xh, asr #31 // make the low word of the output + eor xh, xl, #0x80000000 // make the high word by flipping sign bit + bx lr + +LOCAL_LABEL(nan): + // Return zero, for use when the input was a NaN. + movs xh, #0 + movs xl, #0 + bx lr + +END_COMPILERRT_FUNCTION(__aeabi_d2lz) + +NO_EXEC_STACK_DIRECTIVE diff --git a/compiler-rt/lib/builtins/arm/fixdfsi.S b/compiler-rt/lib/builtins/arm/fixdfsi.S new file mode 100644 index 0000000000000..c567a3690235a --- /dev/null +++ b/compiler-rt/lib/builtins/arm/fixdfsi.S @@ -0,0 +1,132 @@ +//===-- fixdfsi.S - double-precision FP to 32-bit signed int conversion ---===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements the __fixdfsi function (double precision floating point +// to 32-bit signed integer conversion), with the C rounding semantics +// (rounding towards zero), for the Arm and Thumb2 ISAs. +// +//===----------------------------------------------------------------------===// + +#include "../assembly.h" +#include "endian.h" + + .syntax unified + .text + .p2align 2 + +#if __ARM_PCS_VFP +DEFINE_COMPILERRT_FUNCTION(__fixdfsi) + push {r4, lr} + VMOV_FROM_DOUBLE(r0, r1, d0) + bl __aeabi_d2iz + pop {r4, pc} +#else +DEFINE_COMPILERRT_FUNCTION_ALIAS(__fixdfsi, __aeabi_d2iz) +#endif + +DEFINE_COMPILERRT_FUNCTION(__aeabi_d2iz) + + // The fast path: deliver an answer as quickly as possible for cases that + // don't overflow or involve a NaN, and branch out of line to handle + // everything else more slowly. + // + // The basic idea is to make a bare version of the top 32 bits of the + // mantissa, with its leading 1 bit explicit at the top of the word, and + // shift it right by an amount derived from the exponent. + + // Separate out the exponent of the input. + lsls r3, xh, #1 // everything but the sign bit + lsrs r3, r3, #21 // just the exponent + + // Convert the exponent into a right shift count. This involves subtracting + // from 0x41e (which is the exponent of 2^31, so the largest that doesn't + // overflow). We can't do that in one instruction, so do it in two. + sub r3, r3, #0x400 + rsbs r3, r3, #0x1e + + // That RSB instruction also set the flags, which tell us whether the shift + // count went below zero: we subtracted an adjusted input exponent from 0x1e, + // so the LE condition is met if 0x1e ≤ that adjusted exponent, i.e. if the + // shift count is negative or zero, i.e. if the input float has absolute + // value at least 2^31. + // + // Now check if the shift count exceeds 0xFF, so that the AArch32 shift + // semantics would reduce it mod 0x100. We can do that in a way that also + // sets the GT condition, saving an instruction on the fast path at the cost + // of having to re-test which condition happened once we branch out of line. + rsbsgt r12, r3, #0x100 // also set LE if shift count ≥ 0x100 + ble LOCAL_LABEL(uncommon) + + // Construct a word containing the top 32 bits of the mantissa. We do this in + // such a way that the initial ORRS also sets the N flag based on the sign + // bit in xh, so that we can use that for a conditional negation later. + orrs r2, xh, #1 << 20 // put on the leading 1 and test sign + lsl r2, r2, #11 // shift mantissa part of xh up to top of word + orr r2, r2, xl, lsr #21 // the top 11 mantissa bits from xl + + // Now shift the mantissa down to its output position, moving it into the + // output register r0 in the process, and negate the result if the input was + // negative. + // + // We're rounding towards zero, so bits shifted off the bottom can just be + // ignored. + lsr r0, r2, r3 // construct the rounded-down result + rsbmi r0, r0, #0 // negate it if input < 0 + bx lr // and return + +LOCAL_LABEL(uncommon): + // We come here if the exponent field of the number is either too large or + // too small, so that the number is one of + // - a NaN + // - an infinity + // - a finite number of absolute value at least 2^31 + // - a finite nonzero number small enough to underflow to zero (and so small + // that the shift instruction in the fast path couldn't handle it) + // - zero. + // + // For out-of-range positive values, we return the maximum positive signed + // integer 0x7fffffff. For out-of-range negative values, we return the + // minimum negative signed integer 0x80000000. For everything else - NaNs, + // underflows and true zero inputs - we return zero. + // + // (Not _every_ out-of-range finite number is actually an invalid input. The + // exact value -2^31 is perfectly valid. If this implementation supported FP + // exceptions, we'd have to detect that one case and return 0x80000000 with + // no exception, while raising an Invalid Operation exception for everything + // else. But since we don't support exceptions, we don't have to tell the + // difference here: -2^31 and negative overflows both return 0x80000000, and + // it doesn't matter that one is the right answer and the other a best-effort + // error response.) + + // Check for a too-large shift count (too-small exponent) first, because that + // includes the case of an exact zero, which is probably one of the more + // common inputs and should be handled fast if we can. + cmp r3, #0xFF + movgt r0, #0 + bxgt lr + + // Now check for NaNs. + lsls r2, xh, #1 // shift exponent of x to top of word + cmn r2, #1 << 21 // set HI if xh proves it's a NaN by itself + cmpeq xl, #0 // now HI is set if it's a NaN + bhi LOCAL_LABEL(nan) + + // The remaining case is a too-large exponent. Return either INT_MAX or + // INT_MIN depending on sign. + mov r2, #0x7FFFFFFF // start with INT_MAX + eor r0, r2, xh, asr #31 // flip all its bits if xh bit 31 is set + bx lr + +LOCAL_LABEL(nan): + // Out-of-line path that returns zero for NaN inputs. + mov r0, #0 + bx lr + +END_COMPILERRT_FUNCTION(__aeabi_d2iz) + +NO_EXEC_STACK_DIRECTIVE diff --git a/compiler-rt/lib/builtins/arm/fixsfdi.S b/compiler-rt/lib/builtins/arm/fixsfdi.S new file mode 100644 index 0000000000000..6736c9f21aaa8 --- /dev/null +++ b/compiler-rt/lib/builtins/arm/fixsfdi.S @@ -0,0 +1,137 @@ +//===-- fixsfdi.S - single-precision FP to 64-bit signed int conversion ---===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements the __fixsfdi function (single precision floating point +// to 64-bit signed integer conversion), with the C rounding semantics +// (rounding towards zero), for the Arm and Thumb2 ISAs. +// +//===----------------------------------------------------------------------===// + +#include "../assembly.h" +#include "endian.h" + + .syntax unified + .text + .p2align 2 + +#if __ARM_PCS_VFP +DEFINE_COMPILERRT_FUNCTION(__fixsfdi) + push {r4, lr} + vmov r0, s0 + bl __aeabi_f2lz + pop {r4, pc} +#else +DEFINE_COMPILERRT_FUNCTION_ALIAS(__fixsfdi, __aeabi_f2lz) +#endif + +DEFINE_COMPILERRT_FUNCTION(__aeabi_f2lz) + + // The fast path: deliver an answer as quickly as possible for positive cases + // that don't overflow, and branch out of line to handle everything else more + // slowly, including negative numbers, overflows, and NaNs. + // + // The basic idea is to make a bare version of the mantissa, with its leading + // 1 bit explicit at the top of the word, and shift it right by an amount + // derived from the exponent. + + // Shift the exponent down to the bottom of the word. Using ASR here in place + // of LSR means the sign bit keeps its original value, and therefore as a + // side effect the N flag will tell us whether the input was negative. On the + // positive path the output is the same anyway. + asrs r2, r0, #23 + + // Shift the mantissa to the top of the word, and put on the leading 1 bit. + mov r3, r0, lsl #8 + orrne r3, r3, #1 << 31 + + // If the value was negative, branch out of line to handle that. + bmi LOCAL_LABEL(negative) + + // Convert the mantissa into a shift count. If that's negative or zero, that + // means the input is too big, or the exponent is 0xFF (so we might have a + // NaN), so branch out of line again. + rsbs r2, r2, #63 + 0x7f + bls LOCAL_LABEL(invalid) + + // Make the top word of the result, which is the easy part: if the shift + // count is too big, nothing goes wrong, we just end up with whatever part of + // the mantissa remained in this word. + mov xh, r3, lsr r2 + + // Make the bottom word of the result. This might involve shifting the + // mantissa either left or right, depending on the exponent. + subs r12, r2, #32 // r12 = how far to shift mantissa down + movhs xl, r3, lsr r12 // if that's positive, just do it + rsblo r12, r12, #0 // otherwise, negate it + movlo xl, r3, lsl r12 // and shift left by that much instead + bx lr + +LOCAL_LABEL(negative): + // Handle negative numbers. We come here with the mantissa already prepared + // in r3, and the exponent in the bottom 8 bits of r2 with all 1s above it + // (because it was shifted down via ASR and the sign bit was set). + + // Start by clearing the top 24 bits of r2, left set by the ASR above, + // leaving just the bare exponent. + and r2, r2, #0xff + + // Now do exactly the same processing as on the positive path. + rsbs r2, r2, #63 + 0x7f // make the shift count + bls LOCAL_LABEL(invalid) // branch out of line if shift count < 0 + mov xh, r3, lsr r2 // top word of result + subs r12, r2, #32 // right-shift required for bottom word + movhs xl, r3, lsr r12 // bottom word, if shift count >= 0 + rsblo r12, r2, #32 // otherwise, turn into a left-shift count + movlo xl, r3, lsl r12 // bottom word, if it needed a left shift + + // Finally, negate the answer. + rsbs xl, xl, #0 // negate bottom word +#if !__thumb__ + rsc xh, xh, #0 // negate top word +#else + // Thumb has no RSC, so simulate it by bitwise inversion and then ADC + mvn xh, xh + adc xh, xh, #0 +#endif + + bx lr + +LOCAL_LABEL(invalid): + // We come here if the exponent field of the number is large enough that it's + // either a NaN or infinity, or a finite number of absolute value at least + // 2^63. + // + // For out-of-range positive values, we return the maximum positive signed + // integer 0x7fffffffffffffff. For out-of-range negative values, we return + // the minimum negative signed integer 0x8000000000000000. For NaNs, we + // return zero. + // + // Not _every_ number of this kind is actually an invalid input. The exact + // value -2^63 is perfectly valid. If this implementation supported FP + // exceptions, we'd have to detect that one case and return + // 0x8000000000000000 with no exception, while raising an Invalid Operation + // exception for everything else. But since we don't support exceptions, we + // don't have to tell the difference here: -2^63 and negative overflows both + // return 0x8000000000000000, and it doesn't matter that one is the right + // answer and the other a best-effort error response. + mov r1, #0xFF000000 + cmp r1, r0, lsl #1 // 0xFF000000 < (input << 1) means a NaN + blo LOCAL_LABEL(return_zero) // so branch out of line to return zero + mov r2, #0x7FFFFFFF // set up to return INT_MAX + eor xh, r2, r0, asr #31 // flip top half to 80000000 if input < 0 + mvn xl, r0, asr #31 // and bottom half is FFFFFFFF or 00000000 + bx lr + +LOCAL_LABEL(return_zero): + mov xl, #0 + mov xh, #0 + bx lr + +END_COMPILERRT_FUNCTION(__aeabi_f2lz) + +NO_EXEC_STACK_DIRECTIVE diff --git a/compiler-rt/lib/builtins/arm/fixsfsi.S b/compiler-rt/lib/builtins/arm/fixsfsi.S new file mode 100644 index 0000000000000..582463df41320 --- /dev/null +++ b/compiler-rt/lib/builtins/arm/fixsfsi.S @@ -0,0 +1,98 @@ +//===-- fixsfsi.S - single-precision FP to 32-bit signed int conversion ---===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements the __fixsfsi function (single precision floating point +// to 32-bit signed integer conversion), with the C rounding semantics +// (rounding towards zero), for the Arm and Thumb2 ISAs. +// +//===----------------------------------------------------------------------===// + +#include "../assembly.h" + + .syntax unified + .text + .p2align 2 + +#if __ARM_PCS_VFP +DEFINE_COMPILERRT_FUNCTION(__fixsfsi) + push {r4, lr} + vmov r0, s0 + bl __aeabi_f2iz + pop {r4, pc} +#else +DEFINE_COMPILERRT_FUNCTION_ALIAS(__fixsfsi, __aeabi_f2iz) +#endif + +DEFINE_COMPILERRT_FUNCTION(__aeabi_f2iz) + + // The fast path: deliver an answer as quickly as possible for cases that + // don't overflow or involve a NaN, and branch out of line to handle + // everything else more slowly. + // + // The basic idea is to make a bare version of the mantissa, with its leading + // 1 bit explicit at the top of the word, and shift it right by an amount + // derived from the exponent. + + lsls r1, r0, #1 // r1 = everything but the sign bit + lsrs r2, r1, #24 // r2 = just the exponent + rsbs r3, r2, #31 + 0x7f // r3 = how much to shift the mantissa right + + // If the shift count is negative, that means the input is too big, or else + // the exponent is 0xFF (so we might have a NaN). Branch out of line to + // handle both cases. + bls LOCAL_LABEL(invalid) + + // OR the leading 1 into the mantissa and shift it up to the top of the word. + // + // We do it in _that_ order, because that way, the OR operates on the + // original r0 and doesn't touch the top bit. So if we make it set the flags + // too, it also tests the sign of the input, leaving the result in the N + // flag, saving us a separate sign test instruction. + orrs r2, r0, #1 << 23 // put on the leading 1 and test sign + lsl r2, r2, #8 // shift mantissa up to top of word + + // Now shift the mantissa down to its output position, and negate the result + // if the input was negative. + // + // We're rounding towards zero, so bits shifted off the bottom can just be + // ignored. + lsr r0, r2, r3 // construct the rounded-down result + rsbmi r0, r0, #0 // negate it if input < 0 + bx lr // and return + +LOCAL_LABEL(invalid): + // We come here if the exponent field of the number is large enough that it's + // either a NaN or infinity, or a finite number of absolute value at least + // 2^31. + // + // For out-of-range positive values, we return the maximum positive signed + // integer 0x7fffffff. For out-of-range negative values, we return the + // minimum negative signed integer 0x80000000. For NaNs, we return zero. + // + // Not _every_ number of this kind is actually an invalid input. The exact + // value -2^31 is perfectly valid. If this implementation supported FP + // exceptions, we'd have to detect that one case and return 0x80000000 with + // no exception, while raising an Invalid Operation exception for everything + // else. But since we don't support exceptions, we don't have to tell the + // difference here: -2^31 and negative overflows both return 0x80000000, and + // it doesn't matter that one is the right answer and the other a best-effort + // error response. + mov r1, #0xFF000000 + cmp r1, r0, lsl #1 // 0xFF000000 < (input << 1) means a NaN + blo LOCAL_LABEL(return_zero) // so branch out of line to return zero + mov r2, #0x7FFFFFFF // set up to return INT_MAX + eor r0, r2, r0, asr #31 // turn it into INT_MIN if input was negative + bx lr + +LOCAL_LABEL(return_zero): + mov r0, #0 + bx lr + +END_COMPILERRT_FUNCTION(__aeabi_f2iz) + +NO_EXEC_STACK_DIRECTIVE diff --git a/compiler-rt/lib/builtins/arm/fixunsdfdi.S b/compiler-rt/lib/builtins/arm/fixunsdfdi.S new file mode 100644 index 0000000000000..f27521df3421a --- /dev/null +++ b/compiler-rt/lib/builtins/arm/fixunsdfdi.S @@ -0,0 +1,159 @@ +//===-- fixunsdfdi.S - double-precision FP to 64-bit unsigned int conversion==// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements the __fixunsdfdi function (double precision floating +// point to 64-bit unsigned integer conversion), with the C rounding semantics +// (rounding towards zero), for the Arm and Thumb2 ISAs. +// +//===----------------------------------------------------------------------===// + +#include "../assembly.h" +#include "endian.h" + + .syntax unified + .text + .p2align 2 + +#if __ARM_PCS_VFP +DEFINE_COMPILERRT_FUNCTION(__fixunsdfdi) + push {r4, lr} + VMOV_FROM_DOUBLE(r0, r1, d0) + bl __aeabi_d2ulz + pop {r4, pc} +#else +DEFINE_COMPILERRT_FUNCTION_ALIAS(__fixunsdfdi, __aeabi_d2ulz) +#endif + +DEFINE_COMPILERRT_FUNCTION(__aeabi_d2ulz) + + // The fast path: deliver an answer as quickly as possible for positive cases + // that don't overflow, and branch out of line to handle everything else more + // slowly, including negative numbers, overflows, and NaNs. + // + // The basic idea is to make a bare version of the mantissa, with its leading + // 1 bit explicit at the top of the word, and shift it right by an amount + // derived from the exponent. + + // Shift the exponent down to the bottom of the word. We keep the sign bit, + // which will cause negative inputs to be treated like positive numbers with + // extra-enormous exponent. This is good enough to trigger a branch out of + // line later without needing an extra instruction, and then we can handle + // negative inputs properly after that branch. + asrs r2, xh, #20 + + // Make the 64-bit mantissa word, with its top half in r3 and the bottom half + // in r12, and set the leading mantissa bit at the top of r3. + // + // (In principle, the leading mantissa bit shouldn't be set at all if the + // input exponent is zero, because then the input is either 0 or a denormal. + // But since we're always rounding towards zero and not delivering any output + // indicating whether the result is inexact, it makes no difference - all + // denormals will round down to 0 anyway, and will still do so even if we + // imagine that their leading mantissa bit was set.) + lsl r3, xh, #11 // shift top word left to discard sign+exponent + orr r3, r3, xl, lsr #21 // combine with bits from bottom word + orr r3, r3, #1<<31 // set the leading bit + lsl r12, xl, #11 // shift bottom word left + + // Convert the mantissa into a right shift count, indicating how many bits we + // want to shift the 64-bit mantissa in r3:r12 right by. + // + // If that's negative, that means the input is too big, or the exponent is + // 0x7FF (so we might have a NaN), or the value in r2 was 0x800 or more + // because the input was negative, so branch out of line again. + // + // Another possibility is that if the number is very small, the right shift + // count might not fit in a byte, in which case the AArch32 shift semantics + // might do the wrong thing, since they only look at the low byte. + // + // To spot this efficiently, we do the conversion in two steps, arranged so + // that the first step detects massive underflow and the second detects + // overflow. We needed two steps anyway, because we need to subtract the + // input exponent from 0x43e (the exponent of input numbers between 2^63 and + // 2^64), and that value doesn't fit in an immediate field. So the first step + // subtracts 0x340, which makes r2 become negative if the exponent is very + // small; then the second step subtracts from 0xfe, giving 0xfe-(exp-0x340)) + // = 0x43e-exp. + // + // The input is tiny if r2 is negative after the first subtraction. In that + // situation we set r2 to 0 before the second step, treating all exponents + // smaller than 0x340 as if they had been 0x340. We do this by ASR+BIC, which + // avoids needing an IT instruction in Thumb. + sub r2, r2, #0x340 // first stage: r2 is negative for underflow + bic r2, r2, r2, asr #31 // if so, saturate by clearing all bits of r2 + rsbs r2, r2, #0xfe // second step: r2 is now the right shift count + blt LOCAL_LABEL(uncommon) // if it was negative, overflow + + // Make the top word of the result, which is the easy part: it's a + // shifted-right version of the top word of the mantissa, which will be zero + // if the shift count is 32 or more. + lsrs xh, r3, r2 + + // Make the bottom word of the result. If the shift count is less than 32, + // this will be (ml >> n) | (mh << (32-n)), where 'mh' and 'ml' denote the + // high and low words of the mantissa (in r3 and r12 respectively). Otherwise + // the whole high output word is zero, and the low mantissa word contributes + // nothing to the output, so we just need mh >> (n-32). + lsr xl, r12, r2 // start by setting it to ml >> n + rsbs r2, r2, #32 // compute 32-n, and find which case we're in +#if !__thumb__ + orrhi xl, xl, r3, lsl r2 // shift count < 32, so OR in ml << (32-n) +#else + // In Thumb we must separate the register-controlled shift and the OR into + // two instructions. + lslhi r3, r3, r2 + orrhi xl, xl, r3 +#endif + rsbls r2, r2, #0 // shift count > 32, so compute n-32 + lsrls xl, r3, r2 // replace xl with mh >> (n-32) + + // We're done: the result is already rounded towards zero. + bx lr + +LOCAL_LABEL(uncommon): + // We come here if the exponent field of the number is either too large or + // too small, or if the sign bit is set, so that the number is one of + // - a NaN + // - an infinity + // - a positive finite number of absolute value at least 2^31 + // - any negative number at all. + + // Test the sign bit first, and branch out of line for positive values, on + // the theory that reasonably sensible negative values (like -0.5) are more + // likely than the overflow, infinity or NaN cases, and want to be handled as + // quickly as possible. + tst xh, xh + bpl LOCAL_LABEL(positive_invalid) + + // Now we have either a negative finite value, -inf, or a NaN (with the sign + // bit set). Conveniently, _all_ of those just return 0, so we don't have to + // bother checking which. + // + // If we were reporting exceptions, then inputs in the range (-1,0] would + // _legally_ return 0 (after rounding toward zero), whereas -1 and below + // would raise the IEEE Invalid Operation exception. +LOCAL_LABEL(return_zero): + movs xh, #0 + movs xl, #0 + bx lr + +LOCAL_LABEL(positive_invalid): + // Here we have a positive value causing an invalid operation exception. If + // it's a NaN, we return zero; otherwise we return UINT_MAX. + cmp xl, #1 // set C if any bit of xl is nonzero + adc r2, xh, xh // shift that bit into xh, discarding sign + cmn r2, #1 << 21 // then greater than 0xFFE00000 means NaN + bhi LOCAL_LABEL(return_zero) // so we go back to the case above + + mov xh, #0xFFFFFFFF + mov xl, #0xFFFFFFFF + bx lr + +END_COMPILERRT_FUNCTION(__aeabi_d2ulz) + +NO_EXEC_STACK_DIRECTIVE diff --git a/compiler-rt/lib/builtins/arm/fixunsdfsi.S b/compiler-rt/lib/builtins/arm/fixunsdfsi.S new file mode 100644 index 0000000000000..cefa2d615b055 --- /dev/null +++ b/compiler-rt/lib/builtins/arm/fixunsdfsi.S @@ -0,0 +1,129 @@ +//===-- fixunsdfsi.S - double-precision FP to 32-bit unsigned int conversion==// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements the __fixunsdfsi function (double precision floating +// point to 32-bit unsigned integer conversion), with the C rounding semantics +// (rounding towards zero), for the Arm and Thumb2 ISAs. +// +//===----------------------------------------------------------------------===// + +#include "../assembly.h" +#include "endian.h" + + .syntax unified + .text + .p2align 2 + +#if __ARM_PCS_VFP +DEFINE_COMPILERRT_FUNCTION(__fixunsdfsi) + push {r4, lr} + VMOV_FROM_DOUBLE(r0, r1, d0) + bl __aeabi_d2uiz + pop {r4, pc} +#else +DEFINE_COMPILERRT_FUNCTION_ALIAS(__fixunsdfsi, __aeabi_d2uiz) +#endif + +DEFINE_COMPILERRT_FUNCTION(__aeabi_d2uiz) + + // The fast path: deliver an answer as quickly as possible for positive + // inputs that don't overflow, and branch out of line to handle everything + // else (negative numbers, overflows and NaNs) more slowly. + // + // The basic idea is to make a bare version of the mantissa, with its leading + // 1 bit explicit at the top of the word, and shift it right by an amount + // derived from the exponent. + + lsrs r3, xh, #20 // exponent, or >=0x800 if input is negative + + // Convert the exponent into a right shift count. This involves subtracting + // from 0x41e (which is the exponent of 2^31, so the largest that doesn't + // overflow). We can't do that in one instruction, so do it in two. + sub r3, r3, #0x400 + rsbs r3, r3, #0x1e + + // That RSB instruction also set the flags, which tell us whether the shift + // count went below zero: we subtracted an adjusted input exponent from 0x1e, + // so the LT condition is met if 0x1e < that adjusted exponent, i.e. if the + // shift count is negative, i.e. if the input float has absolute value at + // least 2^32. + // + // We didn't bother removing the sign bit when we shifted right to get the + // exponent. So negative numbers will be treated the same as overlarge + // positive numbers and NaNs, i.e. will branch out of line, and we can sort + // out which is which later. + // + // Now check if the shift count exceeds 0xFF, so that the AArch32 shift + // semantics would reduce it mod 0x100. We can do that in a way that also + // sets the GT condition, saving an instruction on the fast path at the cost + // of having to re-test which condition happened once we branch out of line. + rsbsge r12, r3, #0xFF // also set LT if shift count > 0xFF + blt LOCAL_LABEL(uncommon) + + // Construct a word containing the top 32 bits of the mantissa. + orr r2, xh, #1 << 20 // put on the leading 1 + lsls r2, r2, #11 // shift mantissa part of xh up to top of word + orr r2, r2, xl, lsr #21 // the top 11 mantissa bits from xl + + // Now shift the mantissa down to its output position, moving it into the + // output register r0 in the process. + // + // We're rounding towards zero, so bits shifted off the bottom can just be + // ignored. + lsrs r0, r2, r3 // construct the rounded-down result + bx lr // and return + +LOCAL_LABEL(uncommon): + // We come here if the exponent field of the number is either too large or + // too small, or if the sign bit is set, so that the number is one of + // - a NaN + // - an infinity + // - a positive finite number of absolute value at least 2^31 + // - a positive finite nonzero number small enough to underflow to zero (and + // so small that the shift instruction in the fast path couldn't handle + // it) + // - zero + // - any negative number at all. + + // Check for a too-large shift count (too-small exponent) first, because that + // includes the case of an exact zero, which is probably one of the more + // common inputs and should be handled fast if we can. + cmp r3, #0xFF + movgt r0, #0 + bxgt lr + + // Next test the sign bit. Branch out of line for positive values, again on + // the theory that reasonably sensible negative values (like -0.5) are more + // likely than any of the remaining positive cases. + tst xh, xh + bpl LOCAL_LABEL(positive_invalid) + + // Now we have either a negative finite value, -inf, or a NaN (with the sign + // bit set). Conveniently, _all_ of those just return 0, so we don't have to + // bother checking which. + // + // If we were reporting exceptions, then inputs in the range (-1,0] would + // _legally_ return 0 (after rounding toward zero), whereas -1 and below + // would raise the IEEE Invalid Operation exception. +LOCAL_LABEL(return_zero): + mov r0, #0 + bx lr + +LOCAL_LABEL(positive_invalid): + // Here we have a positive value causing an invalid operation exception. If + // it's a NaN, we return zero; otherwise we return UINT_MAX. + lsls r2, xh, #1 // shift exponent of x to top of word + cmn r2, #1 << 21 // set HI if xh proves it's a NaN by itself + cmpeq xl, #0 // now HI is set if it's a NaN + bhi LOCAL_LABEL(return_zero) + mov r0, #0xFFFFFFFF + bx lr + +END_COMPILERRT_FUNCTION(__aeabi_d2uiz) + +NO_EXEC_STACK_DIRECTIVE diff --git a/compiler-rt/lib/builtins/arm/fixunssfdi.S b/compiler-rt/lib/builtins/arm/fixunssfdi.S new file mode 100644 index 0000000000000..00068077d2cc1 --- /dev/null +++ b/compiler-rt/lib/builtins/arm/fixunssfdi.S @@ -0,0 +1,103 @@ +//===-- fixunssfdi.S - single-precision FP to 64-bit unsigned int conversion==// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements the __fixunssfdi function (single precision floating +// point to 64-bit unsigned integer conversion), with the C rounding semantics +// (rounding towards zero), for the Arm and Thumb2 ISAs. +// +//===----------------------------------------------------------------------===// + +#include "../assembly.h" +#include "endian.h" + + .syntax unified + .text + .p2align 2 + +#if __ARM_PCS_VFP +DEFINE_COMPILERRT_FUNCTION(__fixunssfdi) + push {r4, lr} + vmov r0, s0 + bl __aeabi_f2ulz + pop {r4, pc} +#else +DEFINE_COMPILERRT_FUNCTION_ALIAS(__fixunssfdi, __aeabi_f2ulz) +#endif + +DEFINE_COMPILERRT_FUNCTION(__aeabi_f2ulz) + + // The fast path: deliver an answer as quickly as possible for positive + // inputs that don't overflow, and branch out of line to handle everything + // else (negative numbers, overflows and NaNs) more slowly. + // + // The basic idea is to make a bare version of the mantissa, with its leading + // 1 bit explicit at the top of the word, and shift it right by an amount + // derived from the exponent. + + // Shift the exponent down to the bottom of the word. + lsrs r2, r0, #23 // r2 = exponent, or >=256 if input is negative + rsbs r2, r2, #63 + 0x7f // r2 = how much to shift the mantissa right + + // If the shift count is negative, that means the input is too big, or the + // exponent is 0xFF (so we might have a NaN), or the sign bit was set (so the + // input is negative). Branch out of line to handle all those cases. + blo LOCAL_LABEL(uncommon) + + // Shift the mantissa to the top of the word, and put on the leading 1 bit. + lsl r3, r0, #8 + orr r3, r3, #0x80000000 + + // Make the top word of the result, which is the easy part: if the shift + // count is too big, nothing goes wrong, we just end up with whatever part of + // the mantissa remained in this word. + mov xh, r3, lsr r2 + + // Make the bottom word of the result. This might involve shifting the + // mantissa either left or right, depending on the exponent. + // + // We're rounding towards zero, so bits shifted off the bottom can just be + // ignored. + subs r12, r2, #32 // r12 = how far to shift mantissa down + movhs xl, r3, lsr r12 // if that's positive, just do it + rsblo r12, r12, #0 // otherwise, negate it + movlo xl, r3, lsl r12 // and shift left by that much instead + bx lr + +LOCAL_LABEL(uncommon): + // We come here for positive overflows, positive infinity, NaNs, and anything + // with the sign bit set. + // + // Start by testing the sign bit. Branch out of line for positive values. + tst r0, r0 + bpl LOCAL_LABEL(positive_invalid) + + // Now we have either a negative finite value, -inf, or a NaN (with the sign + // bit set). Conveniently, _all_ of those just return 0, so we don't have to + // bother checking which. + // + // If we were reporting exceptions, then inputs in the range (-1,0] would + // _legally_ return 0 (after rounding toward zero), whereas -1 and below + // would raise the IEEE Invalid Operation exception. +LOCAL_LABEL(return_zero): + mov xl, #0 + mov xh, #0 + bx lr + +LOCAL_LABEL(positive_invalid): + // Here we have a positive value causing an invalid operation exception. If + // it's a NaN, we return zero; otherwise we return UINT_MAX. + mov r1, #0xFF000000 + cmp r1, r0, lsl #1 + blo LOCAL_LABEL(return_zero) + mov xl, #0xFFFFFFFF + mov xh, #0xFFFFFFFF + bx lr + +END_COMPILERRT_FUNCTION(__aeabi_f2ulz) + +NO_EXEC_STACK_DIRECTIVE diff --git a/compiler-rt/lib/builtins/arm/fixunssfsi.S b/compiler-rt/lib/builtins/arm/fixunssfsi.S new file mode 100644 index 0000000000000..1594a132801bb --- /dev/null +++ b/compiler-rt/lib/builtins/arm/fixunssfsi.S @@ -0,0 +1,90 @@ +//===-- fixunssfsi.S - single-precision FP to 32-bit unsigned int conversion==// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements the __fixunssfsi function (single precision floating +// point to 32-bit unsigned integer conversion), with the C rounding semantics +// (rounding towards zero), for the Arm and Thumb2 ISAs. +// +//===----------------------------------------------------------------------===// + +#include "../assembly.h" + + + .syntax unified + .text + .p2align 2 + +#if __ARM_PCS_VFP +DEFINE_COMPILERRT_FUNCTION(__fixunssfsi) + push {r4, lr} + vmov r0, s0 + bl __aeabi_f2uiz + pop {r4, pc} +#else +DEFINE_COMPILERRT_FUNCTION_ALIAS(__fixunssfsi, __aeabi_f2uiz) +#endif + +DEFINE_COMPILERRT_FUNCTION(__aeabi_f2uiz) + + // The fast path: deliver an answer as quickly as possible for positive + // inputs that don't overflow, and branch out of line to handle everything + // else (negative numbers, overflows and NaNs) more slowly. + // + // The basic idea is to make a bare version of the mantissa, with its leading + // 1 bit explicit at the top of the word, and shift it right by an amount + // derived from the exponent. + + lsrs r1, r0, #23 // r1 = exponent, or >=256 if input is negative + rsbs r2, r1, #31 + 0x7f // r2 = how much to shift the mantissa right + + // If the shift count is negative, that means the input is too big, or the + // exponent is 0xFF (so we might have a NaN), or the sign bit was set (so the + // input is negative). Branch out of line to handle all those cases. + blt LOCAL_LABEL(uncommon) // negative, infinite or NaN + + // Shift the mantissa up to the top of the word, OR in the leading 1, and + // then shift it back down to make the result. + // + // We're rounding towards zero, so bits shifted off the bottom can just be + // ignored. + lsl r3, r0, #8 // shift mantissa up + orr r3, r3, #0x80000000 // add leading 1 + mov r0, r3, lsr r2 // shift down again + bx lr + +LOCAL_LABEL(uncommon): + // We come here for positive overflows, positive infinity, NaNs, and anything + // with the sign bit set. + // + // Start by testing the sign bit. Branch out of line for positive values. + tst r0, r0 + bpl LOCAL_LABEL(positive_invalid) + + // Now we have either a negative finite value, -inf, or a NaN (with the sign + // bit set). Conveniently, _all_ of those just return 0, so we don't have to + // bother checking which. + // + // If we were reporting exceptions, then inputs in the range (-1,0] would + // _legally_ return 0 (after rounding toward zero), whereas -1 and below + // would raise the IEEE Invalid Operation exception. +LOCAL_LABEL(return_zero): + mov r0, #0 + bx lr + +LOCAL_LABEL(positive_invalid): + // Here we have a positive value causing an invalid operation exception. If + // it's a NaN, we return zero; otherwise we return UINT_MAX. + mov r1, #0xFF000000 + cmp r1, r0, lsl #1 + blo LOCAL_LABEL(return_zero) + mov r0, #0xFFFFFFFF + bx lr + +END_COMPILERRT_FUNCTION(__aeabi_f2uiz) + +NO_EXEC_STACK_DIRECTIVE diff --git a/compiler-rt/test/builtins/Unit/fixdfdinew_test.c b/compiler-rt/test/builtins/Unit/fixdfdinew_test.c new file mode 100644 index 0000000000000..a8bcbf72fd349 --- /dev/null +++ b/compiler-rt/test/builtins/Unit/fixdfdinew_test.c @@ -0,0 +1,121 @@ +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +// RUN: %clang_builtins %s %librt -o %t && %run %t +// REQUIRES: librt_has_fixdfdi + +#include "int_lib.h" +#include <inttypes.h> +#include <stdio.h> + +#include "fp_test.h" + +// By default this test does not specify the expected results for overflowing +// and NaN inputs, because they can vary between platforms. For the Arm +// optimized FP implementation, which commits to more detail, we include some +// extra test cases specific to that NaN policy. +#if (__arm__ && !(__thumb__ && !__thumb2__)) && COMPILER_RT_ARM_OPTIMIZED_FP +#define ARM_INVALID_HANDLING +#endif + +// Returns: a converted from double to int64_t +COMPILER_RT_ABI int64_t __fixdfdi(double a); + +int test__fixdfdi(int line, uint64_t a_rep, uint64_t expected) { + double a = fromRep64(a_rep); + uint64_t x = (uint64_t)__fixdfdi(a); + int ret = x != expected; + + if (ret) { + printf("error at line %d: __fixdfdi(%016" PRIx64 ") = %016" PRIx64 + ", expected %016" PRIx64 "\n", + line, a_rep, x, expected); + } + return ret; +} + +#define test__fixdfdi(a,x) test__fixdfdi(__LINE__,a,x) + +int main(void) { + int status = 0; + + status |= test__fixdfdi(0x0000000000000000, 0x0000000000000000); + status |= test__fixdfdi(0x0000000000000001, 0x0000000000000000); + status |= test__fixdfdi(0x0000000000500000, 0x0000000000000000); + status |= test__fixdfdi(0x3fd0000000000000, 0x0000000000000000); + status |= test__fixdfdi(0x3fe0000000000000, 0x0000000000000000); + status |= test__fixdfdi(0x3fe8000000000000, 0x0000000000000000); + status |= test__fixdfdi(0x3ff0000000000000, 0x0000000000000001); + status |= test__fixdfdi(0x3ff4000000000000, 0x0000000000000001); + status |= test__fixdfdi(0x3ff8000000000000, 0x0000000000000001); + status |= test__fixdfdi(0x3ffc000000000000, 0x0000000000000001); + status |= test__fixdfdi(0x4000000000000000, 0x0000000000000002); + status |= test__fixdfdi(0x4002000000000000, 0x0000000000000002); + status |= test__fixdfdi(0x4004000000000000, 0x0000000000000002); + status |= test__fixdfdi(0x4006000000000000, 0x0000000000000002); + status |= test__fixdfdi(0x41f0000000040000, 0x0000000100000000); + status |= test__fixdfdi(0x41f0000000080000, 0x0000000100000000); + status |= test__fixdfdi(0x41f00000000c0000, 0x0000000100000000); + status |= test__fixdfdi(0x41f0000000140000, 0x0000000100000001); + status |= test__fixdfdi(0x41f0000000180000, 0x0000000100000001); + status |= test__fixdfdi(0x41f00000001c0000, 0x0000000100000001); + status |= test__fixdfdi(0x41f0000000240000, 0x0000000100000002); + status |= test__fixdfdi(0x41f0000000280000, 0x0000000100000002); + status |= test__fixdfdi(0x41f00000002c0000, 0x0000000100000002); + status |= test__fixdfdi(0x41fffffffff40000, 0x00000001ffffffff); + status |= test__fixdfdi(0x41fffffffff80000, 0x00000001ffffffff); + status |= test__fixdfdi(0x41fffffffffc0000, 0x00000001ffffffff); + status |= test__fixdfdi(0x42a0468ace000000, 0x0000082345670000); + status |= test__fixdfdi(0x43dfffffffffffff, 0x7ffffffffffffc00); + status |= test__fixdfdi(0x8000000000000000, 0x0000000000000000); + status |= test__fixdfdi(0x8000000000000001, 0x0000000000000000); + status |= test__fixdfdi(0x8000000000500000, 0x0000000000000000); + status |= test__fixdfdi(0xbfd0000000000000, 0x0000000000000000); + status |= test__fixdfdi(0xbfe0000000000000, 0x0000000000000000); + status |= test__fixdfdi(0xbfe8000000000000, 0x0000000000000000); + status |= test__fixdfdi(0xbff0000000000000, 0xffffffffffffffff); + status |= test__fixdfdi(0xbff4000000000000, 0xffffffffffffffff); + status |= test__fixdfdi(0xbff8000000000000, 0xffffffffffffffff); + status |= test__fixdfdi(0xbffc000000000000, 0xffffffffffffffff); + status |= test__fixdfdi(0xc000000000000000, 0xfffffffffffffffe); + status |= test__fixdfdi(0xc002000000000000, 0xfffffffffffffffe); + status |= test__fixdfdi(0xc004000000000000, 0xfffffffffffffffe); + status |= test__fixdfdi(0xc006000000000000, 0xfffffffffffffffe); + status |= test__fixdfdi(0xc1f0000000040000, 0xffffffff00000000); + status |= test__fixdfdi(0xc1f0000000080000, 0xffffffff00000000); + status |= test__fixdfdi(0xc1f00000000c0000, 0xffffffff00000000); + status |= test__fixdfdi(0xc1f0000000140000, 0xfffffffeffffffff); + status |= test__fixdfdi(0xc1f0000000180000, 0xfffffffeffffffff); + status |= test__fixdfdi(0xc1f00000001c0000, 0xfffffffeffffffff); + status |= test__fixdfdi(0xc1f0000000240000, 0xfffffffefffffffe); + status |= test__fixdfdi(0xc1f0000000280000, 0xfffffffefffffffe); + status |= test__fixdfdi(0xc1f00000002c0000, 0xfffffffefffffffe); + status |= test__fixdfdi(0xc1fffffffff40000, 0xfffffffe00000001); + status |= test__fixdfdi(0xc1fffffffff80000, 0xfffffffe00000001); + status |= test__fixdfdi(0xc1fffffffffc0000, 0xfffffffe00000001); + status |= test__fixdfdi(0xc3dfffffffffffff, 0x8000000000000400); + status |= test__fixdfdi(0xc3e0000000000000, 0x8000000000000000); + +#ifdef ARM_INVALID_HANDLING + // Tests specific to the handling of float-to-integer conversions in + // Arm hardware, mimicked by arm/fixdfdi.S: + // + // - too-large positive inputs, including +infinity, return the + // maximum possible signed integer value + // + // - too-large negative inputs, including -infinity, return the + // minimum possible signed integer value + // + // - NaN inputs return 0 + status |= test__fixdfdi(0x43e0000000000000, 0x7fffffffffffffff); + status |= test__fixdfdi(0x7ff0000000000000, 0x7fffffffffffffff); + status |= test__fixdfdi(0x7ff6d1ebdfe15ee3, 0x0000000000000000); + status |= test__fixdfdi(0x7ff9a4da74944a09, 0x0000000000000000); + status |= test__fixdfdi(0xc3e0000000000001, 0x8000000000000000); + status |= test__fixdfdi(0xfff0000000000000, 0x8000000000000000); + +#endif // ARM_INVALID_HANDLING + + return status; +} diff --git a/compiler-rt/test/builtins/Unit/fixdfsinew_test.c b/compiler-rt/test/builtins/Unit/fixdfsinew_test.c new file mode 100644 index 0000000000000..bf3944ea616a0 --- /dev/null +++ b/compiler-rt/test/builtins/Unit/fixdfsinew_test.c @@ -0,0 +1,96 @@ +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +// RUN: %clang_builtins %s %librt -o %t && %run %t +// REQUIRES: librt_has_fixdfsi + +#include "int_lib.h" +#include <inttypes.h> +#include <stdio.h> + +#include "fp_test.h" + +// By default this test does not specify the expected results for overflowing +// and NaN inputs, because they can vary between platforms. For the Arm +// optimized FP implementation, which commits to more detail, we include some +// extra test cases specific to that NaN policy. +#if (__arm__ && !(__thumb__ && !__thumb2__)) && COMPILER_RT_ARM_OPTIMIZED_FP +#define ARM_INVALID_HANDLING +#endif + +// Returns: a converted from double to int32_t +COMPILER_RT_ABI int32_t __fixdfsi(double a); + +int test__fixdfsi(int line, uint64_t a_rep, uint32_t expected) { + double a = fromRep64(a_rep); + uint32_t x = (uint32_t)__fixdfsi(a); + int ret = x != expected; + + if (ret) { + printf("error at line %d: __fixdfsi(%016" PRIx64 ") = %08" PRIx32 + ", expected %08" PRIx32 "\n", + line, a_rep, x, expected); + } + return ret; +} + +#define test__fixdfsi(a,x) test__fixdfsi(__LINE__,a,x) + +int main(void) { + int status = 0; + + status |= test__fixdfsi(0x0000000000000000, 0x00000000); + status |= test__fixdfsi(0x0000000000000001, 0x00000000); + status |= test__fixdfsi(0x380a000000000000, 0x00000000); + status |= test__fixdfsi(0x3fd0000000000000, 0x00000000); + status |= test__fixdfsi(0x3fe0000000000000, 0x00000000); + status |= test__fixdfsi(0x3fe8000000000000, 0x00000000); + status |= test__fixdfsi(0x3ff0000000000000, 0x00000001); + status |= test__fixdfsi(0x3ff4000000000000, 0x00000001); + status |= test__fixdfsi(0x3ff8000000000000, 0x00000001); + status |= test__fixdfsi(0x3ffc000000000000, 0x00000001); + status |= test__fixdfsi(0x4000000000000000, 0x00000002); + status |= test__fixdfsi(0x4002000000000000, 0x00000002); + status |= test__fixdfsi(0x4004000000000000, 0x00000002); + status |= test__fixdfsi(0x4006000000000000, 0x00000002); + status |= test__fixdfsi(0x8000000000000000, 0x00000000); + status |= test__fixdfsi(0x8000000000000001, 0x00000000); + status |= test__fixdfsi(0xb80a000000000000, 0x00000000); + status |= test__fixdfsi(0xbfd0000000000000, 0x00000000); + status |= test__fixdfsi(0xbfe0000000000000, 0x00000000); + status |= test__fixdfsi(0xbfe8000000000000, 0x00000000); + status |= test__fixdfsi(0xbff0000000000000, 0xffffffff); + status |= test__fixdfsi(0xbff4000000000000, 0xffffffff); + status |= test__fixdfsi(0xbff8000000000000, 0xffffffff); + status |= test__fixdfsi(0xbffc000000000000, 0xffffffff); + status |= test__fixdfsi(0xc000000000000000, 0xfffffffe); + status |= test__fixdfsi(0xc002000000000000, 0xfffffffe); + status |= test__fixdfsi(0xc004000000000000, 0xfffffffe); + status |= test__fixdfsi(0xc006000000000000, 0xfffffffe); + status |= test__fixdfsi(0xc1e0000000000000, 0x80000000); + +#ifdef ARM_INVALID_HANDLING + // Tests specific to the handling of float-to-integer conversions in + // Arm hardware, mimicked by arm/fixdfsi.S: + // + // - too-large positive inputs, including +infinity, return the + // maximum possible signed integer value + // + // - too-large negative inputs, including -infinity, return the + // minimum possible signed integer value + // + // - NaN inputs return 0 + status |= test__fixdfsi(0x41dfffffffffffff, 0x7fffffff); + status |= test__fixdfsi(0x41e0000000000000, 0x7fffffff); + status |= test__fixdfsi(0x7ff0000000000000, 0x7fffffff); + status |= test__fixdfsi(0x7ff6d1ebdfe15ee3, 0x00000000); + status |= test__fixdfsi(0x7ff9a4da74944a09, 0x00000000); + status |= test__fixdfsi(0xc1e00000001fffff, 0x80000000); + status |= test__fixdfsi(0xc1e0000000200000, 0x80000000); + status |= test__fixdfsi(0xfff0000000000000, 0x80000000); + +#endif // ARM_INVALID_HANDLING + + return status; +} diff --git a/compiler-rt/test/builtins/Unit/fixsfdinew_test.c b/compiler-rt/test/builtins/Unit/fixsfdinew_test.c new file mode 100644 index 0000000000000..6a719c3140dcc --- /dev/null +++ b/compiler-rt/test/builtins/Unit/fixsfdinew_test.c @@ -0,0 +1,100 @@ +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +// RUN: %clang_builtins %s %librt -o %t && %run %t +// REQUIRES: librt_has_fixsfdi + +#include "int_lib.h" +#include <inttypes.h> +#include <stdio.h> + +#include "fp_test.h" + +// By default this test does not specify the expected results for overflowing +// and NaN inputs, because they can vary between platforms. For the Arm +// optimized FP implementation, which commits to more detail, we include some +// extra test cases specific to that NaN policy. +#if (__arm__ && !(__thumb__ && !__thumb2__)) && COMPILER_RT_ARM_OPTIMIZED_FP +#define ARM_INVALID_HANDLING +#endif + +// Returns: a converted from float to int64_t +COMPILER_RT_ABI int64_t __fixsfdi(float a); + +int test__fixsfdi(int line, uint32_t a_rep, uint64_t expected) { + float a = fromRep32(a_rep); + uint64_t x = (uint64_t)__fixsfdi(a); + int ret = x != expected; + + if (ret) { + printf("error at line %d: __fixsfdi(%08" PRIx32 ") = %016" PRIx64 + ", expected %016" PRIx64 "\n", + line, a_rep, x, expected); + } + return ret; +} + +#define test__fixsfdi(a,x) test__fixsfdi(__LINE__,a,x) + +int main(void) { + int status = 0; + + status |= test__fixsfdi(0x00000000, 0x0000000000000000); + status |= test__fixsfdi(0x00000001, 0x0000000000000000); + status |= test__fixsfdi(0x00000001, 0x0000000000000000); + status |= test__fixsfdi(0x00500000, 0x0000000000000000); + status |= test__fixsfdi(0x00500000, 0x0000000000000000); + status |= test__fixsfdi(0x3e800000, 0x0000000000000000); + status |= test__fixsfdi(0x3f000000, 0x0000000000000000); + status |= test__fixsfdi(0x3f400000, 0x0000000000000000); + status |= test__fixsfdi(0x3f800000, 0x0000000000000001); + status |= test__fixsfdi(0x3fa00000, 0x0000000000000001); + status |= test__fixsfdi(0x3fc00000, 0x0000000000000001); + status |= test__fixsfdi(0x3fe00000, 0x0000000000000001); + status |= test__fixsfdi(0x40000000, 0x0000000000000002); + status |= test__fixsfdi(0x40100000, 0x0000000000000002); + status |= test__fixsfdi(0x40200000, 0x0000000000000002); + status |= test__fixsfdi(0x40300000, 0x0000000000000002); + status |= test__fixsfdi(0x55023450, 0x0000082345000000); + status |= test__fixsfdi(0x5effffff, 0x7fffff8000000000); + status |= test__fixsfdi(0x80000000, 0x0000000000000000); + status |= test__fixsfdi(0x80000001, 0x0000000000000000); + status |= test__fixsfdi(0x80000001, 0x0000000000000000); + status |= test__fixsfdi(0x80500000, 0x0000000000000000); + status |= test__fixsfdi(0x80500000, 0x0000000000000000); + status |= test__fixsfdi(0xbe800000, 0x0000000000000000); + status |= test__fixsfdi(0xbf000000, 0x0000000000000000); + status |= test__fixsfdi(0xbf400000, 0x0000000000000000); + status |= test__fixsfdi(0xbf800000, 0xffffffffffffffff); + status |= test__fixsfdi(0xbfa00000, 0xffffffffffffffff); + status |= test__fixsfdi(0xbfc00000, 0xffffffffffffffff); + status |= test__fixsfdi(0xbfe00000, 0xffffffffffffffff); + status |= test__fixsfdi(0xc0000000, 0xfffffffffffffffe); + status |= test__fixsfdi(0xc0100000, 0xfffffffffffffffe); + status |= test__fixsfdi(0xc0200000, 0xfffffffffffffffe); + status |= test__fixsfdi(0xc0300000, 0xfffffffffffffffe); + status |= test__fixsfdi(0xdf000000, 0x8000000000000000); + +#ifdef ARM_INVALID_HANDLING + // Tests specific to the handling of float-to-integer conversions in + // Arm hardware, mimicked by arm/fixsfdi.S: + // + // - too-large positive inputs, including +infinity, return the + // maximum possible signed integer value + // + // - too-large negative inputs, including -infinity, return the + // minimum possible signed integer value + // + // - NaN inputs return 0 + status |= test__fixsfdi(0x5f000000, 0x7fffffffffffffff); + status |= test__fixsfdi(0x7f800000, 0x7fffffffffffffff); + status |= test__fixsfdi(0x7fa111d3, 0x0000000000000000); + status |= test__fixsfdi(0x7febfdda, 0x0000000000000000); + status |= test__fixsfdi(0xdf000001, 0x8000000000000000); + status |= test__fixsfdi(0xff800000, 0x8000000000000000); + +#endif // ARM_INVALID_HANDLING + + return status; +} diff --git a/compiler-rt/test/builtins/Unit/fixsfsinew_test.c b/compiler-rt/test/builtins/Unit/fixsfsinew_test.c new file mode 100644 index 0000000000000..12475a5e447ee --- /dev/null +++ b/compiler-rt/test/builtins/Unit/fixsfsinew_test.c @@ -0,0 +1,99 @@ +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +// RUN: %clang_builtins %s %librt -o %t && %run %t +// REQUIRES: librt_has_fixsfsi + +#include "int_lib.h" +#include <inttypes.h> +#include <stdio.h> + +#include "fp_test.h" + +// By default this test does not specify the expected results for overflowing +// and NaN inputs, because they can vary between platforms. For the Arm +// optimized FP implementation, which commits to more detail, we include some +// extra test cases specific to that NaN policy. +#if (__arm__ && !(__thumb__ && !__thumb2__)) && COMPILER_RT_ARM_OPTIMIZED_FP +#define ARM_INVALID_HANDLING +#endif + +// Returns: a converted from float to int32_t +COMPILER_RT_ABI int32_t __fixsfsi(float a); + +int test__fixsfsi(int line, uint32_t a_rep, uint32_t expected) { + float a = fromRep32(a_rep); + uint32_t x = (uint32_t)__fixsfsi(a); + int ret = x != expected; + + if (ret) { + printf("error at line %d: __fixsfsi(%08" PRIx32 ") = %08" PRIx32 + ", expected %08" PRIx32 "\n", + line, a_rep, x, expected); + } + return ret; +} + +#define test__fixsfsi(a,x) test__fixsfsi(__LINE__,a,x) + +int main(void) { + int status = 0; + + status |= test__fixsfsi(0x00000000, 0x00000000); + status |= test__fixsfsi(0x00000001, 0x00000000); + status |= test__fixsfsi(0x00000001, 0x00000000); + status |= test__fixsfsi(0x00500000, 0x00000000); + status |= test__fixsfsi(0x00500000, 0x00000000); + status |= test__fixsfsi(0x3e800000, 0x00000000); + status |= test__fixsfsi(0x3f000000, 0x00000000); + status |= test__fixsfsi(0x3f400000, 0x00000000); + status |= test__fixsfsi(0x3f800000, 0x00000001); + status |= test__fixsfsi(0x3fa00000, 0x00000001); + status |= test__fixsfsi(0x3fc00000, 0x00000001); + status |= test__fixsfsi(0x3fe00000, 0x00000001); + status |= test__fixsfsi(0x40000000, 0x00000002); + status |= test__fixsfsi(0x40100000, 0x00000002); + status |= test__fixsfsi(0x40200000, 0x00000002); + status |= test__fixsfsi(0x40300000, 0x00000002); + status |= test__fixsfsi(0x4effffff, 0x7fffff80); + status |= test__fixsfsi(0x80000000, 0x00000000); + status |= test__fixsfsi(0x80000001, 0x00000000); + status |= test__fixsfsi(0x80000001, 0x00000000); + status |= test__fixsfsi(0x80500000, 0x00000000); + status |= test__fixsfsi(0x80500000, 0x00000000); + status |= test__fixsfsi(0xbe800000, 0x00000000); + status |= test__fixsfsi(0xbf000000, 0x00000000); + status |= test__fixsfsi(0xbf400000, 0x00000000); + status |= test__fixsfsi(0xbf800000, 0xffffffff); + status |= test__fixsfsi(0xbfa00000, 0xffffffff); + status |= test__fixsfsi(0xbfc00000, 0xffffffff); + status |= test__fixsfsi(0xbfe00000, 0xffffffff); + status |= test__fixsfsi(0xc0000000, 0xfffffffe); + status |= test__fixsfsi(0xc0100000, 0xfffffffe); + status |= test__fixsfsi(0xc0200000, 0xfffffffe); + status |= test__fixsfsi(0xc0300000, 0xfffffffe); + status |= test__fixsfsi(0xcf000000, 0x80000000); + +#ifdef ARM_INVALID_HANDLING + // Tests specific to the handling of float-to-integer conversions in + // Arm hardware, mimicked by arm/fixsfsi.S: + // + // - too-large positive inputs, including +infinity, return the + // maximum possible signed integer value + // + // - too-large negative inputs, including -infinity, return the + // minimum possible signed integer value + // + // - NaN inputs return 0 + status |= test__fixsfsi(0x4f000000, 0x7fffffff); + status |= test__fixsfsi(0x7f800000, 0x7fffffff); + status |= test__fixsfsi(0x7fa111d3, 0x00000000); + status |= test__fixsfsi(0x7febfdda, 0x00000000); + status |= test__fixsfsi(0xcf000001, 0x80000000); + status |= test__fixsfsi(0xff800000, 0x80000000); + +#endif // ARM_INVALID_HANDLING + + return status; +} diff --git a/compiler-rt/test/builtins/Unit/fixunsdfdinew_test.c b/compiler-rt/test/builtins/Unit/fixunsdfdinew_test.c new file mode 100644 index 0000000000000..9d87469443375 --- /dev/null +++ b/compiler-rt/test/builtins/Unit/fixunsdfdinew_test.c @@ -0,0 +1,96 @@ +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +// RUN: %clang_builtins %s %librt -o %t && %run %t +// REQUIRES: librt_has_fixunsdfdi + +#include "int_lib.h" +#include <inttypes.h> +#include <stdio.h> + +#include "fp_test.h" + +// By default this test does not specify the expected results for overflowing +// and NaN inputs, because they can vary between platforms. For the Arm +// optimized FP implementation, which commits to more detail, we include some +// extra test cases specific to that NaN policy. +#if (__arm__ && !(__thumb__ && !__thumb2__)) && COMPILER_RT_ARM_OPTIMIZED_FP +#define ARM_INVALID_HANDLING +#endif + +// Returns: a converted from double to int64_t +COMPILER_RT_ABI int64_t __fixunsdfdi(double a); + +int test__fixunsdfdi(int line, uint64_t a_rep, uint64_t expected) { + double a = fromRep64(a_rep); + uint64_t x = (uint64_t)__fixunsdfdi(a); + int ret = x != expected; + + if (ret) { + printf("error at line %d: __fixunsdfdi(%016" PRIx64 ") = %016" PRIx64 + ", expected %016" PRIx64 "\n", + line, a_rep, x, expected); + } + return ret; +} + +#define test__fixunsdfdi(a,x) test__fixunsdfdi(__LINE__,a,x) + +int main(void) { + int status = 0; + + status |= test__fixunsdfdi(0x0000000000000000, 0x0000000000000000); + status |= test__fixunsdfdi(0x0000000000000001, 0x0000000000000000); + status |= test__fixunsdfdi(0x0000000000500000, 0x0000000000000000); + status |= test__fixunsdfdi(0x3fd0000000000000, 0x0000000000000000); + status |= test__fixunsdfdi(0x3fe0000000000000, 0x0000000000000000); + status |= test__fixunsdfdi(0x3fe8000000000000, 0x0000000000000000); + status |= test__fixunsdfdi(0x3ff0000000000000, 0x0000000000000001); + status |= test__fixunsdfdi(0x3ff4000000000000, 0x0000000000000001); + status |= test__fixunsdfdi(0x3ff8000000000000, 0x0000000000000001); + status |= test__fixunsdfdi(0x3ffc000000000000, 0x0000000000000001); + status |= test__fixunsdfdi(0x4000000000000000, 0x0000000000000002); + status |= test__fixunsdfdi(0x4002000000000000, 0x0000000000000002); + status |= test__fixunsdfdi(0x4004000000000000, 0x0000000000000002); + status |= test__fixunsdfdi(0x4006000000000000, 0x0000000000000002); + status |= test__fixunsdfdi(0x41f0000000040000, 0x0000000100000000); + status |= test__fixunsdfdi(0x41f0000000080000, 0x0000000100000000); + status |= test__fixunsdfdi(0x41f00000000c0000, 0x0000000100000000); + status |= test__fixunsdfdi(0x41f0000000140000, 0x0000000100000001); + status |= test__fixunsdfdi(0x41f0000000180000, 0x0000000100000001); + status |= test__fixunsdfdi(0x41f00000001c0000, 0x0000000100000001); + status |= test__fixunsdfdi(0x41f0000000240000, 0x0000000100000002); + status |= test__fixunsdfdi(0x41f0000000280000, 0x0000000100000002); + status |= test__fixunsdfdi(0x41f00000002c0000, 0x0000000100000002); + status |= test__fixunsdfdi(0x41fffffffff40000, 0x00000001ffffffff); + status |= test__fixunsdfdi(0x41fffffffff80000, 0x00000001ffffffff); + status |= test__fixunsdfdi(0x41fffffffffc0000, 0x00000001ffffffff); + status |= test__fixunsdfdi(0x42a0468ace000000, 0x0000082345670000); + status |= test__fixunsdfdi(0x43efffffffffffff, 0xfffffffffffff800); + status |= test__fixunsdfdi(0x8000000000000000, 0x0000000000000000); + +#ifdef ARM_INVALID_HANDLING + // Tests specific to the handling of float-to-integer conversions in + // Arm hardware, mimicked by arm/fixunsdfsi.S: + // + // - too-large positive inputs, including +infinity, return the + // maximum possible unsigned integer value + // + // - negative inputs too small to round up to 0, including + // -infinity, return 0 + // + // - NaN inputs return 0 + status |= test__fixunsdfdi(0x43f0000000000000, 0xffffffffffffffff); + status |= test__fixunsdfdi(0x7ff0000000000000, 0xffffffffffffffff); + status |= test__fixunsdfdi(0x7ff6d1ebdfe15ee3, 0x0000000000000000); + status |= test__fixunsdfdi(0x7ff9a4da74944a09, 0x0000000000000000); + status |= test__fixunsdfdi(0xbfefffffffffffff, 0x0000000000000000); + status |= test__fixunsdfdi(0xbff0000000000000, 0x0000000000000000); + status |= test__fixunsdfdi(0xc000000000000000, 0x0000000000000000); + status |= test__fixunsdfdi(0xfff0000000000000, 0x0000000000000000); + +#endif // ARM_INVALID_HANDLING + + return status; +} diff --git a/compiler-rt/test/builtins/Unit/fixunsdfsinew_test.c b/compiler-rt/test/builtins/Unit/fixunsdfsinew_test.c new file mode 100644 index 0000000000000..a15bda5cbecfe --- /dev/null +++ b/compiler-rt/test/builtins/Unit/fixunsdfsinew_test.c @@ -0,0 +1,251 @@ +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +// RUN: %clang_builtins %s %librt -o %t && %run %t +// REQUIRES: librt_has_fixunsdfsi + +#include "int_lib.h" +#include <inttypes.h> +#include <stdio.h> + +#include "fp_test.h" + +// By default this test does not specify the expected results for overflowing +// and NaN inputs, because they can vary between platforms. For the Arm +// optimized FP implementation, which commits to more detail, we include some +// extra test cases specific to that NaN policy. +#if (__arm__ && !(__thumb__ && !__thumb2__)) && COMPILER_RT_ARM_OPTIMIZED_FP +#define ARM_INVALID_HANDLING +#endif + +// Returns: a converted from double to uint32_t +COMPILER_RT_ABI uint32_t __fixunsdfsi(double a); + +int test__fixunsdfsi(int line, uint64_t a_rep, uint32_t expected) { + double a = fromRep64(a_rep); + int32_t x = __fixunsdfsi(a); + int ret = x != expected; + + if (ret) { + printf("error at line %d: __fixunsdfsi(%016" PRIx64 ") = %08" PRIx32 + ", expected %08" PRIx32 "\n", + line, a_rep, x, expected); + } + return ret; +} + +#define test__fixunsdfsi(a,x) test__fixunsdfsi(__LINE__,a,x) + +int main(void) { + int status = 0; + + status |= test__fixunsdfsi(0x0000000000000000, 0x00000000); + status |= test__fixunsdfsi(0x0000000000000001, 0x00000000); + status |= test__fixunsdfsi(0x001fffefffffffff, 0x00000000); + status |= test__fixunsdfsi(0x002ffffffbffffff, 0x00000000); + status |= test__fixunsdfsi(0x380a000000000000, 0x00000000); + status |= test__fixunsdfsi(0x3fd0000000000000, 0x00000000); + status |= test__fixunsdfsi(0x3fe0000000000000, 0x00000000); + status |= test__fixunsdfsi(0x3fe8000000000000, 0x00000000); + status |= test__fixunsdfsi(0x3fe8000000000000, 0x00000000); + status |= test__fixunsdfsi(0x3ff0000000000000, 0x00000001); + status |= test__fixunsdfsi(0x3ff0000000000000, 0x00000001); + status |= test__fixunsdfsi(0x3ff3cf3a9243d54d, 0x00000001); + status |= test__fixunsdfsi(0x3ff4000000000000, 0x00000001); + status |= test__fixunsdfsi(0x3ff8000000000000, 0x00000001); + status |= test__fixunsdfsi(0x3ff8000000000000, 0x00000001); + status |= test__fixunsdfsi(0x3ff907591158c5d8, 0x00000001); + status |= test__fixunsdfsi(0x3ffc000000000000, 0x00000001); + status |= test__fixunsdfsi(0x4000000000000000, 0x00000002); + status |= test__fixunsdfsi(0x4000000000000000, 0x00000002); + status |= test__fixunsdfsi(0x4002000000000000, 0x00000002); + status |= test__fixunsdfsi(0x4004000000000000, 0x00000002); + status |= test__fixunsdfsi(0x4004000000000000, 0x00000002); + status |= test__fixunsdfsi(0x4006000000000000, 0x00000002); + status |= test__fixunsdfsi(0x4006882d42e373c2, 0x00000002); + status |= test__fixunsdfsi(0x400af556280c2c53, 0x00000003); + status |= test__fixunsdfsi(0x400c000000000000, 0x00000003); + status |= test__fixunsdfsi(0x4010e2652ca3b655, 0x00000004); + status |= test__fixunsdfsi(0x4013752289364b88, 0x00000004); + status |= test__fixunsdfsi(0x4018000000000000, 0x00000006); + status |= test__fixunsdfsi(0x401a000000000000, 0x00000006); + status |= test__fixunsdfsi(0x401e000000000000, 0x00000007); + status |= test__fixunsdfsi(0x40213e96e6ee06b6, 0x00000008); + status |= test__fixunsdfsi(0x4028cdf10f8a4e54, 0x0000000c); + status |= test__fixunsdfsi(0x402c000000000000, 0x0000000e); + status |= test__fixunsdfsi(0x402d000000000000, 0x0000000e); + status |= test__fixunsdfsi(0x402f000000000000, 0x0000000f); + status |= test__fixunsdfsi(0x4030800000000000, 0x00000010); + status |= test__fixunsdfsi(0x4034eefd80e0249b, 0x00000014); + status |= test__fixunsdfsi(0x4037800000000000, 0x00000017); + status |= test__fixunsdfsi(0x403b000000000000, 0x0000001b); + status |= test__fixunsdfsi(0x403d6996adec0f09, 0x0000001d); + status |= test__fixunsdfsi(0x4041d25097b9ee14, 0x00000023); + status |= test__fixunsdfsi(0x4047c00000000000, 0x0000002f); + status |= test__fixunsdfsi(0x404b400000000000, 0x00000036); + status |= test__fixunsdfsi(0x404c0773be0cb9b7, 0x00000038); + status |= test__fixunsdfsi(0x404e000000000000, 0x0000003c); + status |= test__fixunsdfsi(0x4051e00000000000, 0x00000047); + status |= test__fixunsdfsi(0x4053200000000000, 0x0000004c); + status |= test__fixunsdfsi(0x405589958f279d42, 0x00000056); + status |= test__fixunsdfsi(0x4059000000000000, 0x00000064); + status |= test__fixunsdfsi(0x405ea94c1daf1a78, 0x0000007a); + status |= test__fixunsdfsi(0x40615bb017eb1476, 0x0000008a); + status |= test__fixunsdfsi(0x4069500000000000, 0x000000ca); + status |= test__fixunsdfsi(0x406a22674b8b878f, 0x000000d1); + status |= test__fixunsdfsi(0x406bf00000000000, 0x000000df); + status |= test__fixunsdfsi(0x406d800000000000, 0x000000ec); + status |= test__fixunsdfsi(0x4072d80000000000, 0x0000012d); + status |= test__fixunsdfsi(0x40757c8231fe92f1, 0x00000157); + status |= test__fixunsdfsi(0x4076a80000000000, 0x0000016a); + status |= test__fixunsdfsi(0x4077500000000000, 0x00000175); + status |= test__fixunsdfsi(0x407af61b26e4a441, 0x000001af); + status |= test__fixunsdfsi(0x4080f40000000000, 0x0000021e); + status |= test__fixunsdfsi(0x4081363310b2470c, 0x00000226); + status |= test__fixunsdfsi(0x40860c0000000000, 0x000002c1); + status |= test__fixunsdfsi(0x408b000000000000, 0x00000360); + status |= test__fixunsdfsi(0x408e9aaa9a478b59, 0x000003d3); + status |= test__fixunsdfsi(0x4091c67f05129ed4, 0x00000471); + status |= test__fixunsdfsi(0x4093a60000000000, 0x000004e9); + status |= test__fixunsdfsi(0x4098140000000000, 0x00000605); + status |= test__fixunsdfsi(0x409a5a0000000000, 0x00000696); + status |= test__fixunsdfsi(0x409ff99df878ad3e, 0x000007fe); + status |= test__fixunsdfsi(0x40a3500000000000, 0x000009a8); + status |= test__fixunsdfsi(0x40a5598ffcbb08ba, 0x00000aac); + status |= test__fixunsdfsi(0x40a956fba09be449, 0x00000cab); + status |= test__fixunsdfsi(0x40ab8f0000000000, 0x00000dc7); + status |= test__fixunsdfsi(0x40ad090000000000, 0x00000e84); + status |= test__fixunsdfsi(0x40b1118000000000, 0x00001111); + status |= test__fixunsdfsi(0x40b3bab731bb5e6d, 0x000013ba); + status |= test__fixunsdfsi(0x40b6de0000000000, 0x000016de); + status |= test__fixunsdfsi(0x40bac06eeb8b97ba, 0x00001ac0); + status |= test__fixunsdfsi(0x40bce28000000000, 0x00001ce2); + status |= test__fixunsdfsi(0x40c2870000000000, 0x0000250e); + status |= test__fixunsdfsi(0x40c84471c85901df, 0x00003088); + status |= test__fixunsdfsi(0x40c9c34000000000, 0x00003386); + status |= test__fixunsdfsi(0x40cd9b94b71f57ea, 0x00003b37); + status |= test__fixunsdfsi(0x40cdc3c000000000, 0x00003b87); + status |= test__fixunsdfsi(0x40d00da000000000, 0x00004036); + status |= test__fixunsdfsi(0x40d19f4000000000, 0x0000467d); + status |= test__fixunsdfsi(0x40d79d704d0443f1, 0x00005e75); + status |= test__fixunsdfsi(0x40db84e000000000, 0x00006e13); + status |= test__fixunsdfsi(0x40de81403e6071ea, 0x00007a05); + status |= test__fixunsdfsi(0x40e2a16f9da2ed87, 0x0000950b); + status |= test__fixunsdfsi(0x40e92a3000000000, 0x0000c951); + status |= test__fixunsdfsi(0x40e9d5d000000000, 0x0000ceae); + status |= test__fixunsdfsi(0x40eb548000000000, 0x0000daa4); + status |= test__fixunsdfsi(0x40ec19b6638d34af, 0x0000e0cd); + status |= test__fixunsdfsi(0x40f2d4d49a34df18, 0x00012d4d); + status |= test__fixunsdfsi(0x40f2de6800000000, 0x00012de6); + status |= test__fixunsdfsi(0x40f46b9af08e6ece, 0x000146b9); + status |= test__fixunsdfsi(0x40fb2fe000000000, 0x0001b2fe); + status |= test__fixunsdfsi(0x40fc81d800000000, 0x0001c81d); + status |= test__fixunsdfsi(0x4100669800000000, 0x00020cd3); + status |= test__fixunsdfsi(0x4104a6686f29748d, 0x000294cd); + status |= test__fixunsdfsi(0x410a1fc576d6489b, 0x000343f8); + status |= test__fixunsdfsi(0x410b997400000000, 0x0003732e); + status |= test__fixunsdfsi(0x410e962c00000000, 0x0003d2c5); + status |= test__fixunsdfsi(0x4113e47a321d351e, 0x0004f91e); + status |= test__fixunsdfsi(0x41159158c64c86e2, 0x00056456); + status |= test__fixunsdfsi(0x411ce43e00000000, 0x0007390f); + status |= test__fixunsdfsi(0x411eacc400000000, 0x0007ab31); + status |= test__fixunsdfsi(0x411ee00a00000000, 0x0007b802); + status |= test__fixunsdfsi(0x4120eb1f00000000, 0x0008758f); + status |= test__fixunsdfsi(0x4121bc002850dcff, 0x0008de00); + status |= test__fixunsdfsi(0x4123669100000000, 0x0009b348); + status |= test__fixunsdfsi(0x4125458fefa849cd, 0x000aa2c7); + status |= test__fixunsdfsi(0x412c5f6600000000, 0x000e2fb3); + status |= test__fixunsdfsi(0x41311f349fdd064e, 0x00111f34); + status |= test__fixunsdfsi(0x4135e3c47a5a7295, 0x0015e3c4); + status |= test__fixunsdfsi(0x413bb95a80000000, 0x001bb95a); + status |= test__fixunsdfsi(0x413dc4b980000000, 0x001dc4b9); + status |= test__fixunsdfsi(0x413dded700000000, 0x001dded7); + status |= test__fixunsdfsi(0x4143339380000000, 0x00266727); + status |= test__fixunsdfsi(0x4143f42f7838cebe, 0x0027e85e); + status |= test__fixunsdfsi(0x4148d71240000000, 0x0031ae24); + status |= test__fixunsdfsi(0x414f8b46986123ff, 0x003f168d); + status |= test__fixunsdfsi(0x414fc468c0000000, 0x003f88d1); + status |= test__fixunsdfsi(0x4152d16760000000, 0x004b459d); + status |= test__fixunsdfsi(0x41559b87ac7fd1fb, 0x00566e1e); + status |= test__fixunsdfsi(0x415679a847497583, 0x0059e6a1); + status |= test__fixunsdfsi(0x41568d0e20000000, 0x005a3438); + status |= test__fixunsdfsi(0x415efb4d80000000, 0x007bed36); + status |= test__fixunsdfsi(0x41603a2370000000, 0x0081d11b); + status |= test__fixunsdfsi(0x4160d14709ee668a, 0x00868a38); + status |= test__fixunsdfsi(0x416705f510000000, 0x00b82fa8); + status |= test__fixunsdfsi(0x41678a2eb167a88f, 0x00bc5175); + status |= test__fixunsdfsi(0x416dc05b40000000, 0x00ee02da); + status |= test__fixunsdfsi(0x41730fb978000000, 0x0130fb97); + status |= test__fixunsdfsi(0x417395a4a66fca01, 0x01395a4a); + status |= test__fixunsdfsi(0x41756ef08b6d5dd0, 0x0156ef08); + status |= test__fixunsdfsi(0x4179efdb00000000, 0x019efdb0); + status |= test__fixunsdfsi(0x417b4f6208000000, 0x01b4f620); + status |= test__fixunsdfsi(0x4180907a07f893a5, 0x02120f40); + status |= test__fixunsdfsi(0x41862857dc000000, 0x02c50afb); + status |= test__fixunsdfsi(0x4187df63b4000000, 0x02fbec76); + status |= test__fixunsdfsi(0x418c997fa8000000, 0x03932ff5); + status |= test__fixunsdfsi(0x418ee2d28aa63b87, 0x03dc5a51); + status |= test__fixunsdfsi(0x419306468a000000, 0x04c191a2); + status |= test__fixunsdfsi(0x41948b47dbc198b6, 0x0522d1f6); + status |= test__fixunsdfsi(0x4195be8a08000000, 0x056fa282); + status |= test__fixunsdfsi(0x419acb35e46baf44, 0x06b2cd79); + status |= test__fixunsdfsi(0x419ec43dfe000000, 0x07b10f7f); + status |= test__fixunsdfsi(0x41a68e6716000000, 0x0b47338b); + status |= test__fixunsdfsi(0x41a893264f33d251, 0x0c499327); + status |= test__fixunsdfsi(0x41af11d19d000000, 0x0f88e8ce); + status |= test__fixunsdfsi(0x41af241394ce98da, 0x0f9209ca); + status |= test__fixunsdfsi(0x41afb8d0b7000000, 0x0fdc685b); + status |= test__fixunsdfsi(0x41b1a63370800000, 0x11a63370); + status |= test__fixunsdfsi(0x41b23df14b800000, 0x123df14b); + status |= test__fixunsdfsi(0x41b6f2d50149e2d9, 0x16f2d501); + status |= test__fixunsdfsi(0x41ba1aa592000000, 0x1a1aa592); + status |= test__fixunsdfsi(0x41bf53402fd53daa, 0x1f53402f); + status |= test__fixunsdfsi(0x41c18548afc00000, 0x230a915f); + status |= test__fixunsdfsi(0x41c2e365e5345a6b, 0x25c6cbca); + status |= test__fixunsdfsi(0x41c4492dac400000, 0x28925b58); + status |= test__fixunsdfsi(0x41ca895f94000000, 0x3512bf28); + status |= test__fixunsdfsi(0x41ccc3e5f1e5b560, 0x3987cbe3); + status |= test__fixunsdfsi(0x41d01a143e200000, 0x406850f8); + status |= test__fixunsdfsi(0x41d01d7605400000, 0x4075d815); + status |= test__fixunsdfsi(0x41ddcda3abe00000, 0x77368eaf); + status |= test__fixunsdfsi(0x41de53dafe34e730, 0x794f6bf8); + status |= test__fixunsdfsi(0x41df843af68a9ef5, 0x7e10ebda); + status |= test__fixunsdfsi(0x41e2c728e4400000, 0x96394722); + status |= test__fixunsdfsi(0x41e950d535f00000, 0xca86a9af); + status |= test__fixunsdfsi(0x41e9afe08a500000, 0xcd7f0452); + status |= test__fixunsdfsi(0x41eb81ce4bd25eaa, 0xdc0e725e); + status |= test__fixunsdfsi(0x41ef6975dbc19d7a, 0xfb4baede); + status |= test__fixunsdfsi(0x8000000000000000, 0x00000000); + status |= test__fixunsdfsi(0xb818000000000000, 0x00000000); + +#ifdef ARM_INVALID_HANDLING + // Tests specific to the handling of float-to-integer conversions in + // Arm hardware, mimicked by arm/fixunsdfsi.S: + // + // - too-large positive inputs, including +infinity, return the + // maximum possible unsigned integer value + // + // - negative inputs too small to round up to 0, including + // -infinity, return 0 + // + // - NaN inputs return 0 + status |= test__fixunsdfsi(0x41efffffffffffff, 0xffffffff); + status |= test__fixunsdfsi(0x41f0000000000000, 0xffffffff); + status |= test__fixunsdfsi(0x41f37bc9c8400000, 0xffffffff); + status |= test__fixunsdfsi(0x41f3c0b771e5a126, 0xffffffff); + status |= test__fixunsdfsi(0x41fb837587480000, 0xffffffff); + status |= test__fixunsdfsi(0x41fc069b87f80000, 0xffffffff); + status |= test__fixunsdfsi(0x41feea6325bf9a55, 0xffffffff); + status |= test__fixunsdfsi(0x7ff0000000000000, 0xffffffff); + status |= test__fixunsdfsi(0x7ff6d1ebdfe15ee3, 0x00000000); + status |= test__fixunsdfsi(0x7ff9a4da74944a09, 0x00000000); + status |= test__fixunsdfsi(0xbfefffffffffffff, 0x00000000); + status |= test__fixunsdfsi(0xbff0000000000000, 0x00000000); + status |= test__fixunsdfsi(0xc000000000000000, 0x00000000); + status |= test__fixunsdfsi(0xfff0000000000000, 0x00000000); + +#endif // ARM_INVALID_HANDLING + + return status; +} diff --git a/compiler-rt/test/builtins/Unit/fixunssfdinew_test.c b/compiler-rt/test/builtins/Unit/fixunssfdinew_test.c new file mode 100644 index 0000000000000..43021f4d9490c --- /dev/null +++ b/compiler-rt/test/builtins/Unit/fixunssfdinew_test.c @@ -0,0 +1,86 @@ +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +// RUN: %clang_builtins %s %librt -o %t && %run %t +// REQUIRES: librt_has_fixunssfdi + +#include "int_lib.h" +#include <inttypes.h> +#include <stdio.h> + +#include "fp_test.h" + +// By default this test does not specify the expected results for overflowing +// and NaN inputs, because they can vary between platforms. For the Arm +// optimized FP implementation, which commits to more detail, we include some +// extra test cases specific to that NaN policy. +#if (__arm__ && !(__thumb__ && !__thumb2__)) && COMPILER_RT_ARM_OPTIMIZED_FP +#define ARM_INVALID_HANDLING +#endif + +// Returns: a converted from float to int64_t +COMPILER_RT_ABI int64_t __fixunssfdi(float a); + +int test__fixunssfdi(int line, uint32_t a_rep, uint64_t expected) { + float a = fromRep32(a_rep); + uint64_t x = (uint64_t)__fixunssfdi(a); + int ret = x != expected; + + if (ret) { + printf("error at line %d: __fixunssfdi(%08" PRIx32 ") = %016" PRIx64 + ", expected %016" PRIx64 "\n", + line, a_rep, x, expected); + } + return ret; +} + +#define test__fixunssfdi(a,x) test__fixunssfdi(__LINE__,a,x) + +int main(void) { + int status = 0; + + status |= test__fixunssfdi(0x00000000, 0x0000000000000000); + status |= test__fixunssfdi(0x00000001, 0x0000000000000000); + status |= test__fixunssfdi(0x00000001, 0x0000000000000000); + status |= test__fixunssfdi(0x00500000, 0x0000000000000000); + status |= test__fixunssfdi(0x00500000, 0x0000000000000000); + status |= test__fixunssfdi(0x3e800000, 0x0000000000000000); + status |= test__fixunssfdi(0x3f000000, 0x0000000000000000); + status |= test__fixunssfdi(0x3f400000, 0x0000000000000000); + status |= test__fixunssfdi(0x3f800000, 0x0000000000000001); + status |= test__fixunssfdi(0x3fa00000, 0x0000000000000001); + status |= test__fixunssfdi(0x3fc00000, 0x0000000000000001); + status |= test__fixunssfdi(0x3fe00000, 0x0000000000000001); + status |= test__fixunssfdi(0x40000000, 0x0000000000000002); + status |= test__fixunssfdi(0x40100000, 0x0000000000000002); + status |= test__fixunssfdi(0x40200000, 0x0000000000000002); + status |= test__fixunssfdi(0x40300000, 0x0000000000000002); + status |= test__fixunssfdi(0x55023450, 0x0000082345000000); + status |= test__fixunssfdi(0x5f7fffff, 0xffffff0000000000); + status |= test__fixunssfdi(0x80000000, 0x0000000000000000); + status |= test__fixunssfdi(0xbf7fffff, 0x0000000000000000); + +#ifdef ARM_INVALID_HANDLING + // Tests specific to the handling of float-to-integer conversions in + // Arm hardware, mimicked by arm/fixunssfsi.S: + // + // - too-large positive inputs, including +infinity, return the + // maximum possible unsigned integer value + // + // - negative inputs too small to round up to 0, including + // -infinity, return 0 + // + // - NaN inputs return 0 + status |= test__fixunssfdi(0x5f800000, 0xffffffffffffffff); + status |= test__fixunssfdi(0x7f800000, 0xffffffffffffffff); + status |= test__fixunssfdi(0x7fa111d3, 0x0000000000000000); + status |= test__fixunssfdi(0x7febfdda, 0x0000000000000000); + status |= test__fixunssfdi(0xbf800000, 0x0000000000000000); + status |= test__fixunssfdi(0xc0000000, 0x0000000000000000); + status |= test__fixunssfdi(0xff800000, 0x0000000000000000); + +#endif // ARM_INVALID_HANDLING + + return status; +} diff --git a/compiler-rt/test/builtins/Unit/fixunssfsinew_test.c b/compiler-rt/test/builtins/Unit/fixunssfsinew_test.c new file mode 100644 index 0000000000000..0f2774c71686e --- /dev/null +++ b/compiler-rt/test/builtins/Unit/fixunssfsinew_test.c @@ -0,0 +1,85 @@ +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +// RUN: %clang_builtins %s %librt -o %t && %run %t +// REQUIRES: librt_has_fixunssfsi + +#include "int_lib.h" +#include <inttypes.h> +#include <stdio.h> + +#include "fp_test.h" + +// By default this test does not specify the expected results for overflowing +// and NaN inputs, because they can vary between platforms. For the Arm +// optimized FP implementation, which commits to more detail, we include some +// extra test cases specific to that NaN policy. +#if (__arm__ && !(__thumb__ && !__thumb2__)) && COMPILER_RT_ARM_OPTIMIZED_FP +#define ARM_INVALID_HANDLING +#endif + +// Returns: a converted from float to uint32_t +COMPILER_RT_ABI uint32_t __fixunssfsi(float a); + +int test__fixunssfsi(int line, uint32_t a_rep, uint32_t expected) { + float a = fromRep32(a_rep); + int32_t x = __fixunssfsi(a); + int ret = x != expected; + + if (ret) { + printf("error at line %d: __fixunssfsi(%08" PRIx32 ") = %08" PRIx32 + ", expected %08" PRIx32 "\n", + line, a_rep, x, expected); + } + return ret; +} + +#define test__fixunssfsi(a,x) test__fixunssfsi(__LINE__,a,x) + +int main(void) { + int status = 0; + + status |= test__fixunssfsi(0x00000000, 0x00000000); + status |= test__fixunssfsi(0x00000001, 0x00000000); + status |= test__fixunssfsi(0x00000001, 0x00000000); + status |= test__fixunssfsi(0x00500000, 0x00000000); + status |= test__fixunssfsi(0x00500000, 0x00000000); + status |= test__fixunssfsi(0x3e800000, 0x00000000); + status |= test__fixunssfsi(0x3f000000, 0x00000000); + status |= test__fixunssfsi(0x3f400000, 0x00000000); + status |= test__fixunssfsi(0x3f800000, 0x00000001); + status |= test__fixunssfsi(0x3fa00000, 0x00000001); + status |= test__fixunssfsi(0x3fc00000, 0x00000001); + status |= test__fixunssfsi(0x3fe00000, 0x00000001); + status |= test__fixunssfsi(0x40000000, 0x00000002); + status |= test__fixunssfsi(0x40100000, 0x00000002); + status |= test__fixunssfsi(0x40200000, 0x00000002); + status |= test__fixunssfsi(0x40300000, 0x00000002); + status |= test__fixunssfsi(0x4f7fffff, 0xffffff00); + status |= test__fixunssfsi(0x80000000, 0x00000000); + status |= test__fixunssfsi(0xbf7fffff, 0x00000000); + +#ifdef ARM_INVALID_HANDLING + // Tests specific to the handling of float-to-integer conversions in + // Arm hardware, mimicked by arm/fixunssfsi.S: + // + // - too-large positive inputs, including +infinity, return the + // maximum possible unsigned integer value + // + // - negative inputs too small to round up to 0, including + // -infinity, return 0 + // + // - NaN inputs return 0 + status |= test__fixunssfsi(0x4f800000, 0xffffffff); + status |= test__fixunssfsi(0x7f800000, 0xffffffff); + status |= test__fixunssfsi(0x7fa111d3, 0x00000000); + status |= test__fixunssfsi(0x7febfdda, 0x00000000); + status |= test__fixunssfsi(0xbf800000, 0x00000000); + status |= test__fixunssfsi(0xc0000000, 0x00000000); + status |= test__fixunssfsi(0xff800000, 0x00000000); + +#endif // ARM_INVALID_HANDLING + + return status; +} _______________________________________________ llvm-branch-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
