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

Reply via email to