[compiler-rt] [compiler-rt][ARM] Optimized integer -> FP conversions (PR #179928)

Saleem Abdulrasool via llvm-commits llvm-commits at lists.llvm.org
Mon Jun 8 09:30:07 PDT 2026


================
@@ -0,0 +1,103 @@
+//===-- floatunsisf.S - 32-bit unsigned int to single-precision FP 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 __floatunsisf function (32-bit unsigned integer to
+// single precision floating point conversion), with the IEEE-754 default
+// rounding (to nearest, ties to even), for the Arm and Thumb2 ISAs.
+//
+//===----------------------------------------------------------------------===//
+
+#include "../assembly.h"
+
+  .syntax unified
+  .text
+  .p2align 2
+
+#if __ARM_PCS_VFP
+DEFINE_COMPILERRT_FUNCTION(__floatunsisf)
+  push {r4, lr}
+  bl __aeabi_ui2f
+  vmov s0, r0
+  pop {r4, pc}
+#else
+DEFINE_COMPILERRT_FUNCTION_ALIAS(__floatunsisf, __aeabi_ui2f)
+#endif
+
+DEFINE_COMPILERRT_FUNCTION(__aeabi_ui2f)
+
+  // Find the highest set bit of the input, and shift it up to the top bit. r3
+  // contains the amount we shifted by, and r2 the shifted value.
+  clz     r3, r0
+  lsls    r2, r0, r3
+
+  // Convert the shift distance into the exponent of the output float. The
+  // exponent for an integer with bit 31 set should be 0x7f (the IEEE exponent
+  // bias) plus 31, which is 0x9e. Here we reduce that by 1, because when we
+  // add the mantissa to it, the leading mantissa bit will increment it.
+  rsb     r3, r3, #0x9d
+
+  // A side effect of the LSLS above was to set the Z flag if the input integer
+  // was actually zero. In that situation, we can just return immediately,
+  // because r0 still _contains_ the input integer, which has the same
+  // representation as the floating-point +0 that we should return.
+#if __thumb__
+  // In Thumb, we do the conditional return by branching to a return
+  // instruction later in the function. This costs more time in the case where
+  // the return is taken, but saves an IT in the case where it's not, and we
+  // assume that nonzero integers are converted to FP more often than zero is.
+  // (This also improves the _worst-case_ running time, because the nonzero
+  // code path is the limiting factor.)
+  beq     LOCAL_LABEL(return)
+#else
+  bxeq    lr
+#endif
+
+  // Shift the exponent up to its final bit position.
+  lsls    r1, r3, #23
+
+  // Recombine the mantissa with the exponent, and round. This is done
+  // differently between Arm and Thumb.
+#if __thumb__
+  // Thumb rounding sequence: recombine first with plain ADD, and _then_
+  // testing the round bit. On simple M-profile CPUs like Cortex-M3, this
+  // avoids the IT instruction (inserted before BXCC lr) costing a cycle,
+  // because it immediately follows a 16-bit LSLS instruction, so the CPU had
+  // already fetched it.
+  //
+  // So we save a cycle in the case where we don't round up, at the cost of a
+  // cycle in the case where we do (requiring a separate ADD instruction after
+  // the BXCC lr isn't taken). We expect that this is a good trade, on the
+  // theory that _most_ integers converted into floating point are not large
+  // enough to need rounding at all, so all the exact cases _and_ half the
+  // inexact ones will benefit from the saving.
+  add     r0, r1, r2, lsr #8    // r0 is now exp+mant, unrounded
+  lsls.N  r3, r2, #25           // .N to make sure it's assembled as 16-bit
----------------
compnerd wrote:

Likewise 

https://github.com/llvm/llvm-project/pull/179928


More information about the llvm-commits mailing list